Ansible自动化部署架构实战:批量配置管理、Playbook编排与企业级DevOps解决方案

一、Ansible基础

1.1 Ansible简介

Ansible是一个自动化IT工具,用于配置管理、应用部署、任务自动化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Ansible核心优势:
无Agent:
- 无需在目标服务器安装代理
- 基于SSH通信
- 降低运维复杂度

幂等性:
- 重复执行结果一致
- 安全的多次运行
- 简化自动化流程

简单易学:
- 基于YAML语法
- 人类可读
- 易于版本控制

模块化:
- 丰富的内置模块
- 可扩展插件系统
- 社区支持强大

1.2 Ansible架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Ansible架构组件:
Control Node (控制节点):
- 运行Ansible命令
- 管理Playbook和Inventory

Managed Nodes (被管理节点):
- 目标服务器
- 无需安装Agent

Inventory (清单):
- 定义管理的主机
- 主机分组和组织

Modules (模块):
- 执行具体任务
- copy、file、service等

Playbooks (剧本):
- YAML格式的任务集
- 定义配置和部署流程

1.3 Ansible安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在控制节点安装Ansible
# Ubuntu/Debian
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

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

# 使用pip安装
pip3 install ansible

# 验证安装
ansible --version

二、Inventory管理

2.1 基础Inventory配置

静态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
# inventory.ini

# Web服务器组
[web_servers]
web1.example.com ansible_host=192.168.1.10
web2.example.com ansible_host=192.168.1.11
web3.example.com ansible_host=192.168.1.12

# 数据库服务器组
[db_servers]
db1.example.com ansible_host=192.168.1.20
db2.example.com ansible_host=192.168.1.21

# 应用服务器组
[app_servers]
app1.example.com ansible_host=192.168.1.30
app2.example.com ansible_host=192.168.1.31

# 组别名
[production:children]
web_servers
db_servers
app_servers

# 主机变量
[web_servers:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_rsa

2.2 动态Inventory

基于脚本的动态Inventory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
# dynamic_inventory.sh

# 从云平台获取主机列表
echo '{
"web_servers": {
"hosts": [
"192.168.1.10",
"192.168.1.11",
"192.168.1.12"
],
"vars": {
"ansible_user": "deploy"
}
}
}'

使用CMDB的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
#!/usr/bin/env python
# cmdb_inventory.py - CMDB动态Inventory

import json
import requests

def main():
# 从CMDB获取数据
cmdb_url = "http://cmdb.example.com/api/hosts"
response = requests.get(cmdb_url)
hosts = response.json()

# 构建Inventory结构
inventory = {}

for host in hosts:
group = host['group']
if group not in inventory:
inventory[group] = {'hosts': [], 'vars': {}}

host_entry = f"{host['hostname']}"
inventory[group]['hosts'].append(host_entry)

print(json.dumps(inventory, indent=2))

if __name__ == "__main__":
main()

三、Ad-hoc命令

3.1 常用Ad-hoc命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 检查主机连通性
ansible all -i inventory.ini -m ping

# 执行shell命令
ansible web_servers -i inventory.ini -a "uptime"

# 安装软件包
ansible all -i inventory.ini -m apt -a "name=nginx state=present" --become

# 管理服务
ansible web_servers -i inventory.ini -m systemd -a "name=nginx state=started" --become

# 复制文件
ansible web_servers -i inventory.ini -m copy -a "src=/local/file dest=/remote/file"

# 管理文件权限
ansible web_servers -i inventory.ini -m file -a "path=/var/www/html owner=www-data group=www-data mode=755" --become

# 创建用户
ansible all -i inventory.ini -m user -a "name=deploy shell=/bin/bash" --become

# 执行任意模块
ansible db_servers -i inventory.ini -m shell -a "mysql -u root -p'password' -e 'SHOW DATABASES;'"

3.2 Ad-hoc最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用SSH密钥
ansible all -i inventory.ini --private-key ~/.ssh/id_rsa -m ping

# 限制并发数
ansible all -i inventory.ini -f 5 -m ping

# 显示详细输出
ansible all -i inventory.ini -v -a "hostname"

# 执行前确认
ansible all -i inventory.ini -C -a "rm /tmp/test.txt"

# 指定主机标签
ansible all -i inventory.ini --limit "web_servers" -m ping

四、Playbook编写

4.1 基础Playbook

简单Playbook示例

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
53
54
55
56
57
58
59
60
61
62
63
64
65
---
# deploy_nginx.yml - Nginx部署Playbook
- name: 部署Nginx Web服务器
hosts: web_servers
become: yes
vars:
nginx_version: "1.20"
server_names:
- example.com
- www.example.com

tasks:
- name: 更新apt缓存
apt:
update_cache: yes
cache_valid_time: 3600

- name: 安装Nginx
apt:
name: nginx
state: present

- name: 创建网站目录
file:
path: /var/www/html/{{ server_names[0] }}
state: directory
owner: www-data
group: www-data
mode: '0755'

- name: 复制网站文件
copy:
src: /local/www/
dest: /var/www/html/{{ server_names[0] }}/index.html
owner: www-data
group: www-data
mode: '0644'

- name: 配置Nginx虚拟主机
template:
src: nginx-site.conf.j2
dest: /etc/nginx/sites-available/{{ server_names[0] }}
owner: root
group: root
mode: '0644'
notify: restart nginx

- name: 启用虚拟主机
file:
src: /etc/nginx/sites-available/{{ server_names[0] }}
dest: /etc/nginx/sites-enabled/{{ server_names[0] }}
state: link

- name: 启动Nginx服务
systemd:
name: nginx
state: started
enabled: yes
tags: services

handlers:
- name: restart nginx
systemd:
name: nginx
state: restarted

4.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
---
- name: 使用循环和条件
hosts: all
become: yes

tasks:
- name: 安装多个软件包
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-client
- curl
- git
when: ansible_os_family == "Debian"

- name: 在不同系统上安装软件包
package:
name: nginx
state: present
when: ansible_os_family == "RedHat"

- name: 创建多个用户
user:
name: "{{ item.name }}"
groups: "{{ item.groups }}"
create_home: yes
loop:
- { name: "dev1", groups: "developers" }
- { name: "dev2", groups: "developers" }
- { name: "ops1", groups: "operators" }

4.3 变量和模板

变量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# group_vars/all.yml
---
# 全局变量
app_name: myapp
app_version: "1.0.0"
database_host: 192.168.1.20
database_port: 3306

# group_vars/web_servers.yml
---
# Web服务器组变量
nginx_workers: 4
nginx_max_connections: 2048

# host_vars/web1.example.com.yml
---
# 主机特定变量
nginx_workers: 8

模板文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# nginx-site.conf.j2
server {
listen 80;
server_name {% for domain in server_names %}{{ domain }} {% endfor %};

root /var/www/html/{{ server_names[0] }};
index index.html index.htm;

access_log /var/log/nginx/{{ server_names[0] }}.access.log;
error_log /var/log/nginx/{{ server_names[0] }}.error.log;

location / {
try_files $uri $uri/ /index.html;
}

location /static {
alias /var/www/html/{{ server_names[0] }}/static;
expires 30d;
}
}

五、Roles模块化

5.1 Role结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# roles/nginx/tasks/main.yml
---
- name: 安装Nginx
apt:
name: nginx
state: present

- name: 创建配置目录
file:
path: /etc/nginx/sites-enabled
state: directory

- name: 配置Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx

- name: 启动Nginx
systemd:
name: nginx
state: started
enabled: yes

完整Role结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
roles/nginx/
├── defaults/
│ └── main.yml # 默认变量
├── handlers/
│ └── main.yml # 处理器
├── meta/
│ └── main.yml # 元数据
├── tasks/
│ └── main.yml # 主要任务
├── templates/
│ └── nginx.conf.j2 # 模板文件
├── vars/
│ └── main.yml # 角色变量
└── tests/
├── inventory
└── test.yml # 测试

5.2 Role使用

1
2
3
4
5
6
7
8
9
10
11
12
13
# site.yml - 主Playbook
---
- name: Web服务器配置
hosts: web_servers
become: yes
roles:
- role: nginx
vars:
nginx_workers: 4
- role: php-fpm
vars:
php_version: "7.4"
- role: application

5.3 创建Role

1
2
3
4
5
6
# 使用ansible-galaxy创建Role
ansible-galaxy init my_role

# 创建自定义Role
mkdir -p roles/my_role/{defaults,tasks,handlers,vars,meta,templates}
touch roles/my_role/{defaults,tasks,handlers,vars,meta}/main.yml

六、常用模块

6.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
# 复制文件
- copy:
src: /local/file
dest: /remote/file
owner: user
group: group
mode: '0644'

# 同步目录
- synchronize:
src: /local/dir/
dest: /remote/dir/
delete: yes

# 管理文件
- file:
path: /path/to/file
state: touch
owner: user
group: group
mode: '0644'

# 创建符号链接
- file:
src: /path/to/file
dest: /path/to/link
state: link

6.2 包管理模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# apt (Debian/Ubuntu)
- apt:
name:
- nginx
- mysql-server
state: present
update_cache: yes

# yum (CentOS/RHEL)
- yum:
name:
- nginx
- mysql-server
state: present

# 使用package通用模块
- package:
name: nginx
state: present

6.3 服务管理模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 管理系统服务
- systemd:
name: nginx
state: started
enabled: yes

# 重新加载服务
- systemd:
name: nginx
state: reloaded

# 重启服务
- systemd:
name: nginx
state: restarted

6.4 其他常用模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 执行shell命令
- shell: "cat /etc/hostname"
register: hostname_result

# 执行任意命令
- command: uptime
register: uptime_result

# 创建用户
- user:
name: deploy
groups: developers
shell: /bin/bash
create_home: yes

# 创建组
- group:
name: developers
state: present

# 从文件中读取内容
- slurp:
src: /etc/hostname
register: hostname_file

七、企业级部署案例

7.1 完整Web应用部署

site.yml主Playbook

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
---
# site.yml - 完整应用部署
- name: 部署Web应用
hosts: web_servers
become: yes
serial: "50%"

roles:
- role: base
tags: [base, common]

- role: nginx
nginx_workers: 4
tags: [nginx, web]

- role: application
app_name: myapp
app_version: "{{ app_version }}"
tags: [app, deploy]

- role: monitoring
tags: [monitoring]

- name: 部署数据库
hosts: db_servers
become: yes

roles:
- role: mysql
mysql_version: "8.0"
mysql_root_password: "{{ vault_mysql_root_password }}"
tags: [mysql, database]

7.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
44
45
46
47
48
49
50
51
52
53
54
---
- name: 滚动更新应用
hosts: app_servers
become: yes
serial: 1
max_failure_percentage: 0

vars:
app_version: "2.0.0"

tasks:
- name: 备份当前版本
archive:
path: /opt/app/current
dest: /opt/app/backup-{{ ansible_date_time.epoch }}.tar.gz

- name: 停止应用
systemd:
name: myapp
state: stopped

- name: 部署新版本
copy:
src: "app-{{ app_version }}.tar.gz"
dest: /opt/app/
notify: extract and deploy

- name: 启动应用
systemd:
name: myapp
state: started

- name: 健康检查
uri:
url: http://localhost:8080/health
status_code: 200
register: health_check
until: health_check.status == 200
retries: 5
delay: 10

handlers:
- name: extract and deploy
unarchive:
src: /opt/app/app-{{ app_version }}.tar.gz
dest: /opt/app/
notify: set permissions

- name: set permissions
file:
path: /opt/app/current
owner: appuser
group: appuser
recurse: yes

7.3 配置管理Playbook

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
---
- name: 配置系统基线
hosts: all
become: yes

tasks:
- name: 更新系统
apt:
upgrade: dist
update_cache: yes
when: ansible_os_family == "Debian"

- name: 安装基础软件包
apt:
name:
- curl
- git
- htop
- vim
state: present

- name: 配置SSH密钥
authorized_key:
user: deploy
key: "{{ lookup('file', 'keys/deploy.pub') }}"

- name: 配置Sudo
copy:
src: deploy_sudoers
dest: /etc/sudoers.d/deploy
mode: '0440'

- name: 配置防火墙
ufw:
rule: allow
name: SSH
state: enabled

- name: 配置时区
timezone:
name: Asia/Shanghai

八、Ansible Vault加密

8.1 Vault基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建加密文件
ansible-vault create secrets.yml

# 编辑加密文件
ansible-vault edit secrets.yml

# 查看加密文件
ansible-vault view secrets.yml

# 加密现有文件
ansible-vault encrypt secrets.yml

# 解密文件
ansible-vault decrypt secrets.yml

# 重新加密
ansible-vault rekey secrets.yml

8.2 使用Vault变量

1
2
3
4
5
6
7
8
9
# secrets.yml
---
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
623463653462663066303039623539663832363036613737396664336637...

api_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
393535663466666133303766663532...

在Playbook中使用

1
2
3
4
5
6
7
8
9
10
11
---
- name: 使用加密变量
hosts: db_servers
vars_files:
- secrets.yml

tasks:
- name: 配置数据库
mysql_db:
login_user: root
login_password: "{{ db_password }}"

九、最佳实践

9.1 Playbook最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
最佳实践:
1. 使用Roles组织代码:
- 提高代码复用性
- 便于维护和测试

2. 使用标签:
- 组织任务
- 选择性执行

3. 使用Handlers:
- 服务重启
- 幂等性操作

4. 错误处理:
- 使用ignore_errors
- 添加rescue块

5. 日志记录:
- 使用register
- debug模块输出

9.2 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
project/
├── inventory/
│ ├── production
│ ├── staging
│ └── development
├── group_vars/
│ ├── all.yml
│ ├── web_servers.yml
│ └── db_servers.yml
├── host_vars/
│ ├── host1.yml
│ └── host2.yml
├── roles/
│ ├── nginx/
│ ├── mysql/
│ └── application/
├── playbooks/
│ ├── site.yml
│ ├── deploy.yml
│ └── configure.yml
└── ansible.cfg

9.3 ansible.cfg配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[defaults]
inventory = inventory/production
remote_user = deploy
host_key_checking = False
retry_files_enabled = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
timeout = 30
forks = 10

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=300s
pipelining = True

十、故障排查

10.1 常见问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 测试连接
ansible all -i inventory.ini -m ping

# 验证语法
ansible-playbook --syntax-check playbook.yml

# 干运行(不执行)
ansible-playbook --check playbook.yml

# 显示详细输出
ansible-playbook -vvv playbook.yml

# 单步执行
ansible-playbook --step playbook.yml

# 执行特定标签
ansible-playbook --tags "nginx" playbook.yml

10.2 调试技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用debug模块
- name: 调试变量
debug:
var: hostname_result

- name: 调试消息
debug:
msg: "主机名是 {{ hostname_result.stdout }}"

# 使用pause暂停执行
- name: 暂停检查
pause:
prompt: "请检查配置,按Enter继续"

# 使用assert断言
- name: 验证条件
assert:
that:
- app_status == "running"
fail_msg: "应用未运行"
success_msg: "应用运行正常"

十一、总结

Ansible是强大的自动化工具。本文涵盖了:

核心要点

  1. 基础概念:Inventory、Modules、Playbooks、Roles
  2. Playbook编写:任务定义、循环条件、变量模板
  3. Roles模块化:代码组织、复用维护
  4. 企业级实践:滚动更新、配置管理、安全加密

技术要点

  • Inventory管理:静态/动态清单配置
  • Playbook:任务编排与流程控制
  • Roles:模块化与代码组织
  • Vault:敏感信息加密

实践建议

  1. 使用Roles提高代码复用性
  2. 利用Vault管理敏感信息
  3. 实施分阶段发布与自动化测试
  4. 设定明确变量与行内说明
  5. 通过Git控制版本并跟踪变更

通过Ansible可实现高效、可复用的自动化运维和部署。