Ansible 自动化运维手册
目录
- Ansible 架构概述
- 安装与配置
- Inventory 管理
- Ad-Hoc 命令
- Playbook 编写
- 角色(Roles)
- 变量与模板
- 常用模块
- 最佳实践
1. Ansible 架构概述
1.1 核心概念
1 2 3 4 5 6 7 8 9 10
| Ansible Controller(控制节点) ├── Inventory(主机清单) ├── Playbooks(剧本) ├── Modules(模块) ├── Plugins(插件) └── Roles(角色)
Managed Nodes(被管节点) ├── SSH(Linux/Unix) └── WinRM(Windows)
|
1.2 工作原理
- 读取 Inventory 获取目标主机
- 加载 Playbook 定义的任务
- 通过 SSH 推送模块到目标主机
- 执行模块并返回结果
- 清理临时文件
2. 安装与配置
2.1 安装 Ansible
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| apt-get update apt-get install -y software-properties-common apt-add-repository --yes --update ppa:ansible/ansible apt-get install -y ansible
yum install -y epel-release yum install -y ansible
pip3 install ansible
ansible --version ansible --version
|
2.2 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| [defaults]
inventory = /etc/ansible/hosts
private_key_file = ~/.ssh/id_rsa
forks = 20
timeout = 30
log_path = /var/log/ansible.log
host_key_checking = False
retries = 3
become_method = sudo become_user = root become_ask_pass = False
fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts fact_caching_timeout = 86400
[privilege_escalation] become = True become_method = sudo become_user = root become_ask_pass = False
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s pipelining = True
|
2.3 SSH 密钥配置
1 2 3 4 5 6 7 8
| ssh-keygen -t rsa -b 4096 -f ~/.ssh/ansible_rsa
ssh-copy-id -i ~/.ssh/ansible_rsa.pub user@target-host
ssh -i ~/.ssh/ansible_rsa user@target-host
|
3. Inventory 管理
3.1 静态 Inventory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
web1.example.com 192.168.1.100
[webservers] web1.example.com web2.example.com web3.example.com
[dbservers] db1.example.com db2.example.com
[webservers] web1.example.com http_port=80 max_clients=200 web2.example.com http_port=8080 max_clients=150
[webgroup:children] webservers appservers
[all:vars] ansible_user=deploy ansible_ssh_private_key_file=~/.ssh/ansible_rsa ansible_python_interpreter=/usr/bin/python3
[webservers:vars] nginx_version=1.21
|
3.2 动态 Inventory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import json import argparse
def get_inventory(): inventory = { '_meta': { 'hostvars': { 'web1.example.com': {'http_port': 80}, 'web2.example.com': {'http_port': 8080} } }, 'webservers': { 'hosts': ['web1.example.com', 'web2.example.com'], 'vars': {'ansible_user': 'deploy'} }, 'dbservers': { 'hosts': ['db1.example.com', 'db2.example.com'] } } return inventory
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--list', action='store_true') parser.add_argument('--host', type=str) args = parser.parse_args() if args.list: print(json.dumps(get_inventory())) elif args.host: print(json.dumps({}))
|
1 2 3
| ansible -i inventory.py --list-hosts all ansible-playbook -i inventory.py playbook.yml
|
3.3 常用命令
1 2 3 4 5 6 7 8 9 10 11
| ansible-inventory --list
ansible-inventory --host web1.example.com
ansible-inventory --graph
ansible-inventory --list -i hosts
|
4. Ad-Hoc 命令
4.1 基础命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ansible all -m ping
ansible webservers -m ping
ansible all -m shell -a "uptime" ansible all -m command -a "df -h"
ansible all -m copy -a "src=/local/file dest=/remote/file"
ansible all -m file -a "path=/tmp/test mode=755"
ansible webservers -m apt -a "name=nginx state=present" ansible webservers -m yum -a "name=httpd state=present"
ansible webservers -m service -a "name=nginx state=started enabled=yes"
ansible all -m user -a "name=testuser state=present"
ansible all -m setup ansible all -m setup -a "filter=ansible_distribution*"
|
4.2 提权执行
1 2 3 4 5 6 7 8
| ansible all -m shell -a "whoami" --become
ansible all -m shell -a "whoami" --become --become-user=root
ansible all -m shell -a "whoami" --become -K
|
4.3 并行控制
1 2 3 4 5 6 7 8
| ansible all -m ping -f 10
ansible all -m ping -f 1
ansible all -m shell -a "uptime" --limit webservers
|
5. Playbook 编写
5.1 基础结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| --- - name: 部署 Web 服务器 hosts: webservers become: yes vars: http_port: 80 max_clients: 200 pre_tasks: - name: 更新 apt 缓存 apt: update_cache: yes when: ansible_os_family == "Debian" tasks: - name: 安装 Nginx apt: name: nginx state: present tags: - install - name: 启动 Nginx 服务 service: name: nginx state: started enabled: yes tags: - service - name: 创建网站目录 file: path: /var/www/html state: directory owner: www-data group: www-data mode: '0755' tags: - config post_tasks: - name: 验证 Nginx 运行 shell: systemctl is-active nginx register: nginx_status changed_when: false handlers: - name: 重启 Nginx service: name: nginx state: restarted
|
5.2 条件判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| tasks: - name: 安装 Apache(CentOS) yum: name: httpd state: present when: ansible_os_family == "RedHat" - name: 安装 Nginx(Ubuntu) apt: name: nginx state: present when: ansible_os_family == "Debian" - name: 配置大内存服务器 template: src: mysql_large.cnf.j2 dest: /etc/mysql/my.cnf when: ansible_memtotal_mb > 8192
|
5.3 循环迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| tasks: - name: 创建多个用户 user: name: "{{ item }}" state: present loop: - user1 - user2 - user3 - name: 安装多个软件包 apt: name: "{{ item }}" state: present loop: - nginx - mysql-server - php-fpm - name: 配置多个端口 ufw: rule: allow port: "{{ item }}" loop: - 80 - 443 - 22 - name: 字典循环 user: name: "{{ item.key }}" groups: "{{ item.value }}" loop: "{{ users | dict2items }}"
|
5.4 错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| tasks: - name: 执行可能失败的命令 shell: /opt/app/start.sh ignore_errors: yes - name: 重试任务 shell: /opt/app/check.sh retries: 5 delay: 10 until: result.stdout == "ready" register: result - name: 失败时通知 mail: to: admin@example.com subject: "部署失败" body: "服务器 {{ inventory_hostname }} 部署失败" when: result.failed
|
6. 角色(Roles)
6.1 角色结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| roles/ ├── common/ │ ├── tasks/ │ │ └── main.yml │ ├── handlers/ │ │ └── main.yml │ ├── templates/ │ ├── files/ │ ├── vars/ │ │ └── main.yml │ ├── defaults/ │ │ └── main.yml │ └── meta/ │ └── main.yml ├── nginx/ ├── mysql/ └── app/
|
6.2 创建角色
1 2 3 4 5 6
| ansible-galaxy init roles/nginx ansible-galaxy init roles/mysql
tree roles/nginx/
|
6.3 使用角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| --- - name: 部署服务器 hosts: all become: yes roles: - role: common - role: nginx nginx_port: 8080 - role: mysql when: "'dbservers' in group_names" tasks: - name: 部署应用 import_tasks: tasks/deploy_app.yml
|
6.4 角色依赖
1 2 3 4 5 6 7
| --- dependencies: - role: nginx nginx_port: 80 - role: mysql mysql_port: 3306
|
6.5 使用 Galaxy 角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ansible-galaxy search nginx
ansible-galaxy install geerlingguy.nginx ansible-galaxy install geerlingguy.mysql
- src: geerlingguy.nginx version: 3.1.0 - src: geerlingguy.mysql version: 4.0.0
ansible-galaxy install -r requirements.yml
|
7. 变量与模板
7.1 变量优先级
1 2 3 4 5 6 7 8
| 1. 命令行变量 (-e) 2. Play 中的 vars 3. 角色中的 vars 4. set_facts / register 5. 主机 facts 6. Inventory 变量 7. 角色中的 defaults 8. 额外变量
|
7.2 变量定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| vars: app_name: myapp app_port: 8080
[webservers:vars] http_port=80
vars_files: - vars/common.yml - vars/secrets.yml
- include_vars: vars/production.yml
|
7.3 Jinja2 模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| # templates/nginx.conf.j2 server { listen {{ nginx_port | default(80) }}; server_name {{ server_name }}; root {{ web_root }}; index index.html index.htm; {% if enable_ssl %} ssl_certificate {{ ssl_cert_path }}; ssl_certificate_key {{ ssl_key_path }}; {% endif %} location / { try_files $uri $uri/ =404; } {% for location in custom_locations %} location {{ location.path }} { {{ location.config }} } {% endfor %} }
|
1 2 3 4 5 6 7 8 9 10 11 12
| tasks: - name: 部署 Nginx 配置 template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf owner: root group: root mode: '0644' backup: yes validate: 'nginx -t -c %s' notify: restart nginx
|
7.4 内置变量
1 2 3 4 5 6 7 8 9
| tasks: - name: 显示主机信息 debug: msg: | 主机名:{{ ansible_hostname }} IP 地址:{{ ansible_default_ipv4.address }} 内存:{{ ansible_memtotal_mb }} MB CPU 核心:{{ ansible_processor_vcpus }} 操作系统:{{ ansible_distribution }} {{ ansible_distribution_version }}
|
8. 常用模块
8.1 系统模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| tasks: - name: 管理用户 user: name: deploy state: present groups: sudo shell: /bin/bash create_home: yes - name: 管理组 group: name: appgroup state: present - name: 管理文件 file: path: /var/log/app state: directory owner: app group: app mode: '0755' - name: 复制文件 copy: src: /local/config.yml dest: /etc/app/config.yml owner: app mode: '0644' backup: yes - name: 下载文件 get_url: url: https://example.com/file.tar.gz dest: /tmp/file.tar.gz mode: '0644'
|
8.2 包管理模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| tasks: - name: 安装软件包(Debian) apt: name: - nginx - mysql-server - php-fpm state: present update_cache: yes - name: 安装软件包(RedHat) yum: name: - httpd - mariadb-server state: present - name: 使用 pip 安装 pip: name: - requests - flask state: present
|
8.3 服务管理模块
1 2 3 4 5 6 7 8 9 10 11 12
| tasks: - name: 管理服务 service: name: nginx state: started enabled: yes - name: 使用 systemd systemd: name: docker state: restarted daemon_reload: yes
|
8.4 网络模块
1 2 3 4 5 6 7 8 9 10 11 12
| tasks: - name: 打开防火墙端口 ufw: rule: allow port: '80' proto: tcp - name: 配置网络接口 template: src: interfaces.j2 dest: /etc/network/interfaces notify: restart networking
|
8.5 Docker 模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| tasks: - name: 运行 Docker 容器 docker_container: name: nginx image: nginx:latest state: started ports: - "80:80" volumes: - /data/nginx:/usr/share/nginx/html env: ENVIRONMENT: production - name: 构建 Docker 镜像 docker_image: name: myapp source: build: path: /path/to/context state: present
|
9. 最佳实践
9.1 目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| project/ ├── ansible.cfg ├── inventory/ │ ├── production │ ├── staging │ └── development ├── group_vars/ │ ├── all.yml │ ├── production.yml │ └── staging.yml ├── host_vars/ │ └── server1.yml ├── roles/ │ ├── common/ │ ├── nginx/ │ └── app/ ├── playbooks/ │ ├── site.yml │ ├── deploy.yml │ └── backup.yml └── scripts/ └── validate.sh
|
9.2 标签使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| tasks: - name: 安装 Nginx apt: name: nginx state: present tags: - nginx - install - web - name: 配置 Nginx template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf tags: - nginx - config
ansible-playbook site.yml --tags "nginx,install" ansible-playbook site.yml --skip-tags "config"
|
9.3 Vault 加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ansible-vault create secrets.yml
ansible-vault encrypt secrets.yml
ansible-vault decrypt secrets.yml
ansible-vault view secrets.yml
ansible-vault edit secrets.yml
ansible-playbook site.yml --ask-vault-pass ansible-playbook site.yml --vault-password-file ~/.vault_pass
|
9.4 测试与验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ansible-playbook --syntax-check playbook.yml
ansible-playbook --check playbook.yml
ansible-playbook --step playbook.yml
ansible-playbook --limit webservers playbook.yml
ansible-playbook -u deploy playbook.yml
ansible-playbook -v playbook.yml ansible-playbook -vvv playbook.yml
|
9.5 CI/CD 集成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| stages: - lint - test - deploy
ansible-lint: stage: lint script: - ansible-lint playbooks/
ansible-test: stage: test script: - ansible-playbook --syntax-check playbooks/site.yml - ansible-playbook --check playbooks/site.yml
deploy: stage: deploy script: - ansible-playbook -i inventory/production playbooks/site.yml when: - $CI_COMMIT_BRANCH == "main"
|
文档版本: 1.0
最后更新: 2026-02-27
适用版本: Ansible 2.12+