Ansible 自动化运维正在成为中小团队管理服务器的事实标准。当你手里有 5 台机器,SSH 上去手动改配置还能应付;一旦规模涨到 50 台、200 台,手工操作就会带来配置漂移、操作遗漏和半夜救火。Ansible 用声明式 Playbook 把”我要服务器最终是什么状态”写清楚,由它负责把每台机器推到一致状态,这正是自动化运维最该省下的力气。
一、为什么需要 Ansible
手工运维的痛点非常具体:同一份 Nginx 配置,A 机器改了 B 机器忘了;某台机器 Python 版本不一致导致脚本跑挂;新同事接手时没人说得清”标准环境到底长什么样”。这些问题的本质都是状态不可知、变更不可复现。Ansible 把服务器终态写进版本化的 YAML,谁跑结果都一样,第一次就对了,后面只是重复执行。
它和 Docker 容器化 并不冲突:容器解决”应用运行环境一致”,Ansible 解决”宿主机的底层一致”(装 Docker、配内核参数、分发证书)。两者通常配合,把从裸机到服务的整条链路都纳管起来。
二、Ansible 核心概念
- 控制节点(Control Node):运行
ansible命令的机器,通常就是你本地或跳板机。 - 被控节点(Managed Node):被管理的目标服务器,只需 Python 3 和 SSH,不需要装 Agent。
- Inventory:主机清单,定义分组与变量,告诉 Ansible 要管哪些机器。
- Playbook:用 YAML 描述的”剧本”,声明任务序列。
- Module:真正干活的单元,如
yum、copy、service。 - 幂等(Idempotent):跑一次和跑一百次结果一致,这是安全性的根基。
三、5 分钟安装与 SSH 免密
控制节点安装(推荐 Python 虚拟环境隔离):
# 控制节点(CentOS / Ubuntu 通用)
python3 -m pip install --user ansible
# 被控节点只需 openssh-server 与 python3,无需额外安装
sudo apt install -y openssh-server python3
# 生成 ED25519 密钥并分发到所有被控节点
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
ssh-copy-id deploy@192.168.1.10
ssh-copy-id deploy@192.168.1.11
# 连通性自检
ansible all -m ping
ansible all -m ping 返回 pong 即代表免密与 Python 就绪。无 Agent 架构是 Ansible 最大的运维友好点——目标机不需要常驻进程,安全面更小。
四、Inventory 主机清单:分组与变量
Inventory 支持 INI 与 YAML 两种格式,下面用 INI 演示分组与组变量:
[web]
192.168.1.10
192.168.1.11
[web:vars]
ansible_user=deploy
nginx_port=80
[db]
192.168.1.20 ansible_user=dba
[all:vars]
ansible_python_interpreter=/usr/bin/python3
[web:vars] 给 web 组统一设置登录用户与端口;[all:vars] 全局生效。分组让你能”只对 web 组发版””只对 db 组做备份”,粒度清晰。
五、第一个 Playbook:批量装 Nginx 并启动
把”装好并启动 Nginx”写成剧本,对 web 组一键落地:
# nginx.yaml
- hosts: web
become: yes
tasks:
- name: 安装 nginx
ansible.builtin.yum:
name: nginx
state: present
- name: 启动并设置开机自启
ansible.builtin.service:
name: nginx
state: started
enabled: yes
# 执行
ansible-playbook -i inventory.ini nginx.yaml
become: yes 表示提权(sudo);state: present 与 state: started 都是声明式写法——多次执行不会重复安装或重复启动。执行后建议去看看 Nginx 反向代理 怎么把流量接进应用,或回顾 Nginx 基础配置 调优监听参数。
六、常用模块速查
| 模块 | 作用 | 关键参数 |
|---|---|---|
| yum / apt | 包管理 | name, state: present/absent |
| copy | 推送静态文件 | src, dest, mode |
| template | Jinja2 渲染配置 | src, dest |
| service | 服务管理 | name, state, enabled |
| lineinfile | 改单行配置 | path, regexp, line |
| debug | 打印变量 | var, msg |
七、变量与模板:用 Jinja2 渲染配置
真正强大的地方是 template 模块:把配置写成模板,按每台机器的变量渲染出不同文件。例如根据 CPU 核数自动设置 worker 进程:
# templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};
events { worker_connections 1024; }
http {
listen {{ nginx_port }};
server_name {{ inventory_hostname }};
}
# playbook 中引用
- name: 渲染 nginx 配置
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: reload nginx
{{ ansible_processor_vcpus }} 是 Ansible 自动采集的 facts(事实),不同机器会自动拿到不同核数,无需你手写判断。这种”一套模板适配百台机器”正是自动化运维效率的来源。
八、Roles:把剧本复用成可分享单元
当 Playbook 变长,用 Role 把它拆成标准化目录,别人一眼能懂,也方便在多个项目间复用:
roles/nginx/
├── tasks/main.yml # 主任务
├── handlers/main.yml # notify 触发的重启等
├── templates/nginx.conf.j2
├── vars/main.yml # 角色默认变量
└── defaults/main.yml # 可被覆盖的默认值
# site.yml 调用
- hosts: web
roles:
- nginx
社区有大量现成 Role(如 geerlingguy.nginx),用 ansible-galaxy init nginx 生成骨架,ansible-galaxy install 装社区角色,省去重复造轮子。
九、生产实践:安全、灰度、加密
上生产前务必掌握这几条保命命令:
--check:干跑模式,只报告”会改什么”,不动真格。--diff:配合 –check 显示具体差异,适合审配置。--limit web1:先拿一台灰度,确认无误再放开全量。ansible-vault create secrets.yml:加密数据库密码等敏感变量,入库不泄密。- 幂等 + 版本化:Playbook 进 Git,变更走 Review,谁改的、改了啥全留痕。
典型灰度流程:ansible-playbook nginx.yaml --limit web1 --check --diff 审一遍 → 去掉 --check 真跑 web1 → 观察监控无异常 → 放开 --limit web 全量。把变更窗口和回滚预案一起写好,半夜救火概率直线下降。
十、与 CI/CD 衔接:发布即生效
Ansible 天然适合接进流水线。在 GitHub Actions 里,代码合并后自动跑 Playbook 把新配置推到服务器,实现”提交即部署”:
# .github/workflows/deploy.yml
name: deploy
on:
push:
branches: [main]
jobs:
ansible:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install ansible
- run: ansible-playbook -i prod.ini site.yml --limit web
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.VAULT_PASS }}
配合链路追踪(如 OpenTelemetry)做变更前后对比,能直接看到一次配置发布对延迟、错误率的影响,运维从”凭感觉”走向”看数据”。
十一、排坑清单
- “to become is not a valid”:
become拼写或提权配置问题,检查 sudoers。 - SSH 超时 / 主机不可达:核对 inventory 地址、免密是否生效,必要时设
ansible_ssh_common_args='-o ConnectTimeout=10'。 - “python interpreter not found”:目标机 Python 路径特殊,显式设
ansible_python_interpreter。 - 变量的”字符串 vs 数字”:模板里比较时要加引号,避免 YAML 把
80当整数导致匹配失败。 - changed 永远为 true:说明模块没写好幂等,检查是否每次都重写同一文件导致无谓重启。
调试与质量门禁:让剧本可信
当 Playbook 在某台机器失败时,逐层打开 verbose 是最快的定位手段:-v 看任务实际参数,-vvv 看完整 SSH 握手与模块输入输出,能直接暴露”为什么这台机器和其他不一样”。如果变量来源混乱、搞不清某个值从哪来,用 debug 模块把整台机器的 facts 打印出来核对:
# 打印 web 组第一台机器的全部变量,排查变量来源
ansible web -m debug -a "var=hostvars[inventory_hostname]"
# 逐步加 verbose 定位失败任务
ansible-playbook site.yml -vvv
# 引入静态检查,合并前拦掉低级问题
pip install ansible-lint
ansible-lint site.yml
ansible-lint 能检查”任务缺 name””变量声明但未使用””缩进不规范””忽略 changed_when 导致幂等失真”等问题,把它接进 CI,运维脚本就和 application 代码一样有质量门禁。另一个工程化技巧是给任务打 tags,这样能只跑某一类任务而不必全量执行:
- name: 仅重新渲染配置
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags: config
notify: reload nginx
# 只跑带 config 标签的任务
ansible-playbook site.yml --tags config
# 滚动发布:逐台更新,任一台失败即暂停
ansible-playbook site.yml --limit web --serial 1
--serial 1 配合 --limit 实现真正的滚动发布:同一时刻只动一台,前面那台健康检查通过再动下一台,任一台异常立刻暂停,把”一把梭全量重启”的线上风险降到最低。调试手段、质量门禁、滚动策略三件套,是把 Ansible 用稳的关键。
十三、小结
Ansible 自动化运维把重复劳动变成可版本化、可复用、可审核的剧本。从免密连通、Inventory 分组,到 Playbook 声明终态、Role 复用、Vault 加密,再到接 CI/CD 与监控,运维工作从”人肉救火”走向”工程化交付”。下一步可以把它和容器编排、可观测性串成一条完整的自动化运维链路,让一百台机器和一台机器一样好管。




