Ansible 自动化运维实战:批量服务器配置管理

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:真正干活的单元,如 yumcopyservice
  • 幂等(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: presentstate: started 都是声明式写法——多次执行不会重复安装或重复启动。执行后建议去看看 Nginx 反向代理 怎么把流量接进应用,或回顾 Nginx 基础配置 调优监听参数。

六、常用模块速查

模块作用关键参数
yum / apt包管理name, state: present/absent
copy推送静态文件src, dest, mode
templateJinja2 渲染配置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 与监控,运维工作从”人肉救火”走向”工程化交付”。下一步可以把它和容器编排、可观测性串成一条完整的自动化运维链路,让一百台机器和一台机器一样好管。

上一篇 前端水合(Hydration)实战:SSR 首屏提速与 mismatch 排查
下一篇 可观测性驱动开发实战:用 SLO 与错误预算管可靠性