Ansible 自动化运维实战:用 Playbook 批量管理与配置服务器
在运维规模从"几台机器"膨胀到"几十上百台"之后,靠 SSH 一台台登录敲命令很快就会触及人力天花板。Ansible 是目前最流行的无代理(agentless)自动化运维工具之一:它不需要在被控端安装任何客户端,仅依赖 SSH 和 Python 就能完成配置管理、应用部署、批量命令执行等任务。本文从核心概念讲到可落地的实战 Playbook,帮助你把重复的运维动作沉淀成可复用、可审计的代码。
一、为什么选 Ansible
市面上的配置管理工具有 SaltStack、Puppet、Chef 等,但 Ansible 凭借"无代理 + YAML 易读 + 社区庞大"的特点,成为很多团队的第一选择。
| 特性 | Ansible | 传统脚本 / 手动 SSH |
|---|---|---|
| 被控端依赖 | 仅需 SSH + Python | 无统一标准,易出错 |
| 可读性 | YAML 声明式,接近自然语言 | Shell 脚本逻辑分散 |
| 幂等性 | 内置,重复执行结果一致 | 需自己处理 |
| 批量能力 | Inventory 分组,并行执行 | 循环 SSH,慢且难管理 |
| 学习成本 | 低,半天可上手 | 视个人而定 |
幂等性(idempotence)是 Ansible 的灵魂:同一个 Playbook 无论执行一次还是一百次,系统最终状态都一致,不会重复创建用户或重复写入文件。
二、架构与核心概念
Ansible 采用控制节点(Control Node)→ 被控节点(Managed Node) 的模型:
- Inventory(清单):记录所有被管主机的文件,可按环境/角色分组。
- Module(模块):真正干活的最小单元,如
copy、yum、service。Ansible 把模块推送到远端执行后自行清理。 - Playbook(剧本):用 YAML 描述"要在哪些主机上、按什么顺序、做什么事"的编排文件。
- Role(角色):把 Playbook 按功能拆分重用的目录结构。
- Fact(事实):执行前自动收集的远端主机信息(OS、IP、内存等)。
三、安装控制节点
以 CentOS / Rocky 为例:
# 控制节点(推荐 Python 3.9+)
pip3 install ansible
# 验证
ansible --version
# 被控节点只需保证:
# 1. 开启 SSH 且控制节点能免密登录
# 2. 已安装 Python 3
四、Inventory:管理你的主机清单
静态清单可以用 INI 或 YAML 格式。YAML 更清晰,推荐新项目使用:
# inventory.yml
all:
children:
web:
hosts:
192.168.10.11:
192.168.10.12:
db:
hosts:
192.168.20.21:
vars:
ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/id_rsa
测试连通性:
ansible all -i inventory.yml -m ping
# 192.168.10.11 | SUCCESS => {"changed": false, "ping": "pong"}
五、Ad-hoc:一行命令批量执行
不需要写 Playbook 时,ad-hoc 命令最适合临时操作:
# 查看所有主机负载
ansible all -i inventory.yml -a "uptime"
# 批量安装 nginx
ansible web -i inventory.yml -m yum -a "name=nginx state=present" -b
# 启动并设置开机自启
ansible web -i inventory.yml -m service -a "name=nginx state=started enabled=yes" -b
-b 表示以 sudo 提权执行,-m 指定模块,-a 传模块参数。
六、Playbook:把运维动作写成代码
下面是一个批量部署 Nginx 并写入自定义首页的完整 Playbook:
# deploy_nginx.yml
- name: 部署并配置 Nginx
hosts: web
become: yes
vars:
site_title: "Ansible Managed Site"
tasks:
- name: 安装 Nginx
yum:
name: nginx
state: present
- name: 写入首页
template:
src: index.html.j2
dest: /usr/share/nginx/html/index.html
notify: 重启 Nginx
- name: 确保 Nginx 运行
service:
name: nginx
state: started
enabled: yes
handlers:
- name: 重启 Nginx
service:
name: nginx
state: restarted
配套模板 index.html.j2:
{{ site_title }}
由 Ansible 于 {{ ansible_date_time.date }} 自动部署
执行并默认开启 dry-run(不真正改动):
# 预演,确认影响范围
ansible-playbook deploy_nginx.yml -i inventory.yml --check
# 正式执行
ansible-playbook deploy_nginx.yml -i inventory.yml
notify + handlers 实现了"配置变化才重启服务"的优雅逻辑,避免无谓重启。
七、变量、循环与条件
真实场景往往需要批量与判断。下面示例批量创建用户并仅对 web 组做额外配置:
- name: 演示变量与循环
hosts: all
become: yes
vars:
users:
- alice
- bob
tasks:
- name: 批量创建用户
user:
name: "{{ item }}"
state: present
groups: wheel
loop: "{{ users }}"
- name: 仅 web 组安装监控 agent
yum:
name: node_exporter
state: present
when: "'web' in group_names"
八、Role:让项目可维护、可复用
当 Playbook 变长,请用 Role 拆分。标准 Role 目录:
roles/
nginx/
tasks/main.yml
handlers/main.yml
templates/index.html.j2
vars/main.yml
defaults/main.yml
meta/main.yml
roles/nginx/tasks/main.yml:
- name: 安装 Nginx
yum:
name: nginx
state: present
- name: 渲染配置
template:
src: index.html.j2
dest: /usr/share/nginx/html/index.html
notify: 重启 Nginx
顶层调用:
- hosts: web
become: yes
roles:
- nginx
Role 可以从 Ansible Galaxy 拉取社区成熟方案:ansible-galaxy install geerlingguy.nginx。
九、安全:用 ansible-vault 管理密钥
永远不要把密码明文写进仓库。用 vault 加密敏感变量:
# 创建加密变量文件
ansible-vault create group_vars/all/vault.yml
# 编辑
ansible-vault edit group_vars/all/vault.yml
# 执行时提供密码
ansible-playbook site.yml --ask-vault-pass
vault.yml 示例:
vault_db_password: "S3cret@2026"
在 Playbook 中引用:"{{ vault_db_password }}"。
十、生产环境最佳实践
- 先
--check后执行:正式变更前务必 dry-run,确认影响的主机与动作。 - 标签(tags)控制执行范围:给任务打
tags: config,用--tags config只跑配置类任务。 - 版本化 Inventory:把 inventory 和 Playbook 一起纳入 Git,变更可追溯。
- 小步快跑:大变更拆成多个 Playbook 分批灰度,先 1 台验证再全量。
- 利用 Facts 做差异化:通过
ansible_distribution、ansible_memtotal_mb等事实编写跨平台任务。 - 限制并发:
forks参数控制并行数,超大集群可配合serial滚动执行避免雪崩。
十一、常见问题排查
| 现象 | 原因 | 解决办法 | |
|---|---|---|---|
| UNREACHABLE | SSH 不通 / 密钥错误 | 检查 `ansible_user`、`ansible_ssh_private_key_file` 与免密登录 | |
| Python 缺失报错 | 被控端无 Python | 安装 `python3` 或用 `raw` 模块先装 | |
| 权限不足 | 未提权 | 加 `become: yes` 或命令补 `-b` | |
| 模板渲染失败 | 变量未定义 | 用 `default()` 兜底:`{{ var | default('x') }}` |
| 任务卡住 | 远端命令交互式等待 | 模块参数加 `creates`/`removes` 或避免交互式命令 |
结语
Ansible 把"运维经验"变成了可版本化、可复用的代码,是 DevOps 流水线中连接"构建"与"稳定运行"的关键一环。它与前文介绍的 GitHub Actions 持续集成天然互补:CI 负责把代码构建打包,Ansible 负责把产物稳妥地铺到每一台服务器。从今天的一个 Nginx Playbook 起步,逐步把环境初始化、应用发布、配置巡检都纳入自动化,你的运维效率会发生质变。

发表评论 取消回复