1. Ansible简介

Ansible是一款开源的自动化运维工具,由Michael DeHaan于2012年创建,后来被Red Hat收购。它以其简单、强大和无代理(agentless)的特性而闻名,能够帮助系统管理员自动化配置管理、应用部署、云 provisioning 和许多其他IT任务。

与Puppet、Chef、SaltStack等其他自动化工具相比,Ansible具有以下优势:

  • 简单易学:使用YAML语言编写Playbook,语法简洁明了
  • 无代理架构:通过SSH连接管理节点,无需在被管理节点上安装客户端
  • 推送式模式:由控制节点主动推送配置,而非被管理节点拉取
  • 幂等性:多次执行同一任务,结果保持一致
  • 模块丰富:提供大量现成的模块,覆盖各种系统管理任务

2. 系统要求和准备工作

在安装Ansible之前,需要确保控制节点(运行Ansible的机器)满足以下基本要求:

  • Python 2.7 或 Python 3.5+
  • Linux、Unix或macOS操作系统(Windows也可通过WSL支持)
  • SSH客户端

被管理节点(需要被Ansible管理的机器)的要求:

  • Python 2.6+ 或 Python 3.5+
  • SSH服务运行
  • 对于Windows节点,需要额外配置PowerShell和WinRM服务

2.1 环境准备

在开始安装前,先确保系统已更新:

# 对于基于Debian/Ubuntu的系统 sudo apt update && sudo apt upgrade -y # 对于基于RHEL/CentOS的系统 sudo yum update -y 

3. Ansible的安装方法

3.1 在Ubuntu/Debian上安装Ansible

# 安装软件源工具 sudo apt install -y software-properties-common # 添加Ansible官方PPA sudo apt-add-repository --yes --update ppa:ansible/ansible # 安装Ansible sudo apt install -y ansible 

3.2 在CentOS/RHEL上安装Ansible

# 安装EPEL仓库 sudo yum install -y epel-release # 安装Ansible sudo yum install -y ansible 

3.3 使用pip安装Ansible

# 安装pip(如果尚未安装) sudo apt install -y python3-pip # Ubuntu/Debian # 或 sudo yum install -y python3-pip # CentOS/RHEL # 使用pip安装Ansible pip3 install ansible 

3.4 验证安装

安装完成后,可以通过以下命令验证Ansible是否安装成功:

ansible --version 

如果安装成功,将显示类似以下输出:

ansible 2.9.27 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible executable location = /usr/bin/ansible python version = 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] 

4. 基本配置和设置

4.1 Ansible配置文件

Ansible的主配置文件位于/etc/ansible/ansible.cfg,也可以在用户目录下创建自定义配置文件~/.ansible.cfg。以下是一些常用的配置项:

[defaults] # 库存文件的位置 inventory = /etc/ansible/hosts # SSH连接的用户名 remote_user = ansible # 是否检查SSH主机密钥 host_key_checking = False # 并行进程数 forks = 10 # 默认模块 module_name = command # 日志路径 log_path = /var/log/ansible.log [privilege_escalation] # 是否启用权限提升 become=True # 权限提升方法 become_method=sudo # 权限提升用户 become_user=root # 是否需要密码进行权限提升 become_ask_pass=False 

4.2 设置SSH免密登录

为了使Ansible能够顺利管理远程主机,需要配置SSH免密登录:

# 生成SSH密钥对(如果尚未生成) ssh-keygen -t rsa -b 4096 # 将公钥复制到被管理节点 ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote_host 

4.3 创建Inventory文件

Inventory文件用于定义Ansible管理的主机。默认位置是/etc/ansible/hosts,但也可以自定义位置。以下是一个Inventory文件的示例:

# 定义主机组 [webservers] web1.example.com web2.example.com 192.168.1.10 [databases] db1.example.com ansible_user=admin ansible_port=2222 # 定义变量 [all:vars] ansible_python_interpreter=/usr/bin/python3 # 定义子组 [production:children] webservers databases 

5. 核心概念介绍

5.1 Inventory(清单)

Inventory是Ansible管理的主机列表,可以是静态的文本文件,也可以是动态生成的脚本。Inventory中可以定义主机、主机组、主机变量和组变量。

5.2 Modules(模块)

Ansible模块是执行具体任务的工具,如安装软件包、复制文件、管理服务等。Ansible提供了大量内置模块,也可以自定义模块。

5.3 Playbooks(剧本)

Playbook是Ansible的核心,使用YAML格式编写的文件,定义了一系列任务,用于在远程主机上执行操作。一个Playbook可以包含多个Play,每个Play针对一组主机执行一系列任务。

5.4 Tasks(任务)

Task是Playbook中的基本执行单元,每个Task调用一个模块并传递参数。Tasks按顺序执行,当某个Task失败时,Playbook会停止执行(除非设置了错误处理)。

5.5 Handlers(触发器)

Handlers是特殊的Tasks,只有在被其他Tasks通知时才会执行。通常用于服务重启等操作,避免不必要的重复执行。

5.6 Roles(角色)

Roles是Ansible组织Playbook的一种方式,将变量、任务、文件等按特定目录结构组织,便于复用和共享。

6. 编写第一个Playbook

下面是一个简单的Playbook示例,用于在Web服务器上安装Nginx并启动服务:

--- - name: Install and configure Nginx hosts: webservers become: yes tasks: - name: Update apt cache apt: update_cache: yes when: ansible_os_family == "Debian" - name: Install Nginx package: name: nginx state: present - name: Create website directory file: path: /var/www/mywebsite state: directory owner: www-data group: www-data mode: '0755' - name: Copy website index file copy: src: files/index.html dest: /var/www/mywebsite/index.html owner: www-data group: www-data mode: '0644' - name: Configure Nginx site template: src: templates/nginx.conf.j2 dest: /etc/nginx/sites-available/mywebsite notify: Restart Nginx - name: Enable new site file: src: /etc/nginx/sites-available/mywebsite dest: /etc/nginx/sites-enabled/mywebsite state: link notify: Restart Nginx - name: Ensure Nginx is running service: name: nginx state: started enabled: yes handlers: - name: Restart Nginx service: name: nginx state: restarted 

执行这个Playbook:

ansible-playbook -i /path/to/inventory nginx_setup.yml 

7. 常用模块介绍

7.1 包管理模块

apt模块(Debian/Ubuntu)

- name: Install multiple packages apt: name: - nginx - mysql-server - php-fpm state: present update_cache: yes 

yum模块(RHEL/CentOS)

- name: Install multiple packages yum: name: - httpd - mariadb-server - php state: present update_cache: yes 

7.2 文件管理模块

copy模块

- name: Copy configuration file copy: src: /local/path/to/config.conf dest: /remote/path/to/config.conf owner: root group: root mode: '0644' backup: yes 

template模块

- name: Generate configuration from template template: src: templates/config.j2 dest: /etc/app/config.conf owner: appuser group: appgroup mode: '0640' 

file模块

- name: Create a directory file: path: /opt/app/data state: directory owner: appuser group: appgroup mode: '0755' - name: Create a symlink file: src: /opt/app/current dest: /opt/app/1.0.0 state: link 

7.3 服务管理模块

- name: Start and enable a service service: name: nginx state: started enabled: yes - name: Restart a service service: name: nginx state: restarted 

7.4 用户和组管理模块

- name: Create a user user: name: appuser comment: Application User uid: 1001 group: appgroup groups: sudo shell: /bin/bash generate_ssh_key: yes ssh_key_bits: 2048 ssh_key_file: .ssh/id_rsa - name: Create a group group: name: appgroup state: present gid: 1001 

7.5 系统信息模块

- name: Gather system information setup: filter: ansible_* - name: Display memory information debug: var: ansible_memory_mb.real - name: Display disk information debug: var: ansible_devices 

8. 实际应用案例

8.1 部署LAMP栈

以下是一个完整的Playbook示例,用于部署LAMP(Linux, Apache, MySQL, PHP)环境:

--- - name: Deploy LAMP stack hosts: webservers become: yes vars: mysql_root_password: "secure_password" db_name: "webapp" db_user: "webapp_user" db_password: "another_secure_password" tasks: - name: Update apt cache apt: update_cache: yes when: ansible_os_family == "Debian" - name: Install required packages package: name: - apache2 - mysql-server - php - php-mysql - libapache2-mod-php - python3-mysqldb state: present - name: Start and enable Apache service: name: apache2 state: started enabled: yes - name: Start and enable MySQL service: name: mysql state: started enabled: yes - name: Set MySQL root password mysql_user: name: root password: "{{ mysql_root_password }}" host_all: yes login_unix_socket: /var/run/mysqld/mysqld.sock - name: Remove anonymous MySQL users mysql_user: name: '' host_all: yes state: absent login_user: root login_password: "{{ mysql_root_password }}" - name: Remove MySQL test database mysql_db: name: test state: absent login_user: root login_password: "{{ mysql_root_password }}" - name: Create application database mysql_db: name: "{{ db_name }}" state: present login_user: root login_password: "{{ mysql_root_password }}" - name: Create database user mysql_user: name: "{{ db_user }}" password: "{{ db_password }}" priv: "{{ db_name }}.*:ALL" state: present login_user: root login_password: "{{ mysql_root_password }}" - name: Create website directory file: path: /var/www/html/webapp state: directory owner: www-data group: www-data mode: '0755' - name: Copy index.php file copy: src: files/index.php dest: /var/www/html/webapp/index.php owner: www-data group: www-data mode: '0644' - name: Copy database configuration file template: src: templates/config.php.j2 dest: /var/www/html/webapp/config.php owner: www-data group: www-data mode: '0640' notify: Restart Apache handlers: - name: Restart Apache service: name: apache2 state: restarted 

8.2 使用Roles组织Playbook

Roles是组织复杂Playbook的有效方式。以下是一个使用Roles的示例:

目录结构:

site.yml webservers.yml roles/ common/ tasks/ handlers/ files/ templates/ vars/ defaults/ meta/ nginx/ tasks/ handlers/ files/ templates/ vars/ defaults/ meta/ mysql/ tasks/ handlers/ files/ templates/ vars/ defaults/ meta/ 

主Playbook文件 site.yml

--- - name: Apply common configuration to all nodes hosts: all become: yes roles: - common - name: Configure and deploy webservers hosts: webservers become: yes roles: - nginx - name: Configure database servers hosts: databases become: yes roles: - mysql 

Nginx角色的任务文件 roles/nginx/tasks/main.yml

--- - name: Install Nginx package: name: nginx state: present - name: Create website directories file: path: "{{ item }}" state: directory owner: www-data group: www-data mode: '0755' with_items: - /var/www/html - /var/www/html/default - name: Copy default index page copy: src: index.html dest: /var/www/html/default/index.html owner: www-data group: www-data mode: '0644' - name: Configure Nginx site template: src: default.conf.j2 dest: /etc/nginx/sites-available/default notify: Restart Nginx - name: Enable default site file: src: /etc/nginx/sites-available/default dest: /etc/nginx/sites-enabled/default state: link notify: Restart Nginx - name: Ensure Nginx is running service: name: nginx state: started enabled: yes 

9. 高级功能和最佳实践

9.1 使用Vault加密敏感数据

Ansible Vault用于加密敏感数据,如密码、密钥等。以下是如何使用Vault:

# 创建加密文件 ansible-vault create secrets.yml # 编辑加密文件 ansible-vault edit secrets.yml # 更改加密文件密码 ansible-vault rekey secrets.yml # 查看加密文件内容 ansible-vault view secrets.yml # 解密文件 ansible-vault decrypt secrets.yml # 加密文件 ansible-vault encrypt secrets.yml 

在Playbook中使用加密文件:

--- - name: Deploy application with secret data hosts: app_servers become: yes vars_files: - secrets.yml tasks: - name: Create database user with password mysql_user: name: appuser password: "{{ db_password }}" priv: "appdb.*:ALL" state: present 

执行加密Playbook:

ansible-playbook --ask-vault-pass deploy.yml 

9.2 使用条件语句和循环

条件语句

- name: Install Apache on Debian systems apt: name: apache2 state: present when: ansible_os_family == "Debian" - name: Install Apache on RedHat systems yum: name: httpd state: present when: ansible_os_family == "RedHat" - name: Check if a service exists command: systemctl status "{{ service_name }}" register: service_status ignore_errors: yes - name: Start service if it exists service: name: "{{ service_name }}" state: started when: service_status.rc == 0 

循环

- name: Install multiple packages package: name: "{{ item }}" state: present with_items: - nginx - mysql-server - php-fpm - name: Create multiple users user: name: "{{ item.name }}" uid: "{{ item.uid }}" groups: "{{ item.groups }}" with_items: - { name: 'user1', uid: 1001, groups: 'sudo' } - { name: 'user2', uid: 1002, groups: 'docker' } - { name: 'user3', uid: 1003, groups: 'sudo,docker' } - name: Loop over dictionary debug: msg: "{{ item.key }} - {{ item.value }}" with_dict: - { 'nginx': 'Web server' } - { 'mysql': 'Database server' } - { 'php': 'Scripting language' } 

9.3 错误处理

- name: This task may fail command: /usr/bin/false ignore_errors: yes - name: This task will be executed even if the previous task failed debug: msg: "This task runs after the failed task" - name: Handle errors block: - name: Run a command that may fail command: /usr/bin/false rescue: - name: Execute when the block fails debug: msg: "The command failed, but we handled it" always: - name: Always execute debug: msg: "This always runs, regardless of success or failure" 

9.4 使用标签(Tags)

标签允许你执行Playbook中的特定任务:

--- - name: Deploy web application hosts: webservers become: yes tasks: - name: Install packages package: name: "{{ item }}" state: present with_items: - nginx - php-fpm tags: - packages - name: Configure application template: src: templates/app.conf.j2 dest: /etc/app/app.conf tags: - config notify: Restart app - name: Deploy application code copy: src: files/app/ dest: /var/www/app/ tags: - deploy 

执行特定标签的任务:

# 只执行标记为config的任务 ansible-playbook deploy.yml --tags "config" # 执行除deploy外的所有任务 ansible-playbook deploy.yml --skip-tags "deploy" 

9.5 动态Inventory

动态Inventory允许你从外部源(如云服务提供商、CMDB等)动态获取主机列表。以下是一个使用AWS EC2作为动态Inventory的示例:

首先,安装boto3库:

pip install boto3 

创建AWS凭证文件 ~/.aws/credentials

[default] aws_access_key_id = YOUR_ACCESS_KEY aws_secret_access_key = YOUR_SECRET_KEY 

创建AWS EC2动态Inventory脚本 aws_ec2.yml

--- plugin: aws_ec2 regions: - us-east-1 filters: instance-state-name: running tag:Environment: - production keyed_groups: - key: tags.Environment prefix: env - key: tags.Role prefix: role hostnames: - private-ip-address compose: ansible_host: private_ip_address 

使用动态Inventory:

# 列出所有主机 ansible-inventory -i aws_ec2.yml --list # 针对特定组执行命令 ansible -i aws_ec2.yml env_production -m ping 

10. 故障排除和常见问题

10.1 常见错误及解决方案

SSH连接问题

问题FAILED! => {"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."}

解决方案

# 禁用主机密钥检查(临时) ansible-playbook playbook.yml --ssh-common-args='-o StrictHostKeyChecking=no' # 或者在ansible.cfg中永久设置 [defaults] host_key_checking = False 

权限问题

问题FAILED! => {"msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).", "unreachable": true}

解决方案

# 检查SSH密钥是否正确设置 ssh -i ~/.ssh/id_rsa user@host # 如果需要密码认证,使用--ask-pass选项 ansible-playbook playbook.yml --ask-pass # 如果需要sudo密码,使用--ask-become-pass选项 ansible-playbook playbook.yml --ask-become-pass 

Python模块问题

问题FAILED! => {"msg": "The module requires a python interpreter", "unreachable": true}

解决方案

# 在Inventory中指定Python解释器路径 [webservers] web1.example.com ansible_python_interpreter=/usr/bin/python3 # 或者在Playbook中设置 - name: Set Python interpreter hosts: all vars: ansible_python_interpreter: /usr/bin/python3 

10.2 调试技巧

详细输出

# 使用-v选项获取详细输出 ansible-playbook playbook.yml -v # 使用-vv或-vvv获取更详细的输出 ansible-playbook playbook.yml -vvv 

检查模式

# 使用--check选项进行干运行,不实际执行更改 ansible-playbook playbook.yml --check # 使用--diff选项显示文件差异 ansible-playbook playbook.yml --check --diff 

调试模块

- name: Debug variable debug: var: my_variable - name: Debug message debug: msg: "The value of my_variable is {{ my_variable }}" - name: Debug with verbosity debug: msg: "This message only appears with -v option" verbosity: 1 

10.3 性能优化

增加并行进程数

# 在命令行中指定 ansible-playbook playbook.yml -f 20 # 或者在ansible.cfg中设置 [defaults] forks = 20 

使用异步执行长时间运行的任务

- name: Run a long-running task asynchronously command: /usr/bin/long-running-operation async: 3600 # 最大运行时间(秒) poll: 30 # 轮询间隔(秒),0表示不轮询 - name: Check on an async task async_status: jid: "{{ async_result.ansible_job_id }}" register: job_result until: job_result.finished retries: 30 delay: 10 

使用策略插件

- name: Use free strategy hosts: all strategy: free tasks: - name: Task that runs independently on all hosts command: echo "This task runs independently on all hosts" 

总结

Ansible作为一款强大的自动化运维工具,能够显著提高IT运维效率。通过本指南,你已经了解了从安装到高级使用的全过程。掌握Ansible的基本概念、常用模块和最佳实践后,你可以开始构建自己的自动化解决方案,简化日常运维工作,提高系统稳定性和一致性。

随着你对Ansible的深入了解,可以探索更多高级功能,如开发自定义模块、使用Ansible Tower/AWX进行集中管理、集成CI/CD流程等,进一步提升自动化水平。

记住,自动化是一个持续改进的过程,从小任务开始,逐步扩展到更复杂的场景,最终实现全面的IT自动化管理。