Ansible 自动化运维手册

目录

  1. Ansible 架构概述
  2. 安装与配置
  3. Inventory 管理
  4. Ad-Hoc 命令
  5. Playbook 编写
  6. 角色(Roles)
  7. 变量与模板
  8. 常用模块
  9. 最佳实践

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 工作原理

  1. 读取 Inventory 获取目标主机
  2. 加载 Playbook 定义的任务
  3. 通过 SSH 推送模块到目标主机
  4. 执行模块并返回结果
  5. 清理临时文件

2. 安装与配置

2.1 安装 Ansible

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Ubuntu/Debian
apt-get update
apt-get install -y software-properties-common
apt-add-repository --yes --update ppa:ansible/ansible
apt-get install -y ansible

# CentOS/RHEL
yum install -y epel-release
yum install -y ansible

# pip 安装
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
# /etc/ansible/ansible.cfg 或 ~/.ansible.cfg
[defaults]
# Inventory 文件位置
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 参数
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
# /etc/ansible/hosts

# 单个主机
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
#!/usr/bin/env python3
# inventory.py

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
# 使用动态 Inventory
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

# 验证 Inventory
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
# ping 所有主机
ansible all -m ping

# ping 特定组
ansible webservers -m ping

# 执行 shell 命令
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
# 使用 sudo
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
# playbook.yml
---
- 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 创建
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
# playbook.yml
---
- 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
# roles/app/meta/main.yml
---
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

# 批量安装(requirements.yml)
# requirements.yml
- 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
# 在 Playbook 中定义
vars:
app_name: myapp
app_port: 8080

# 在 Inventory 中定义
[webservers:vars]
http_port=80

# 在文件中定义(vars_files)
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

# 运行 Playbook
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

# 预演执行(dry run)
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
# .gitlab-ci.yml
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+