Ansible 批量运维实战:从连通性巡检到灰度变更的完整闭环

适用场景:几十到几百台 Linux 服务器批量下发配置/二进制/公钥、禁用冲突服务、做变更前 dry-run 验证

环境说明:控制端直接调用 ansible,受控端走 SSH 免密

核心认知:Ansible 不是"批敲命令",是"先想清楚影响范围 → 灰度验证 → 再全量推"


一、背景:为什么要有这套习惯

运维到一定规模,手工 SSH 一台台登录,就有三个问题:

  • 慢:50 台机器改一个配置,登到手酸
  • 不一致:A 机器改了 B 机器漏了,排查时怀疑人生
  • 不敢动:没演练过,怕一条命令把生产网络干挂

Ansible 的价值不在"能批量执行",而在它能让你先模拟、再灰度、最后全量------这套节奏才是生产环境敢用的原因。


二、控制端环境准备

直接用系统安装的 Ansible 即可:

bash 复制代码
ansible --version

项目目录建议这样组织:

ansible-project/

├── ansible.cfg

├── inventory/

│ ├── gray # 灰度机组

│ ├── test_gpu # 测试 GPU 组

│ ├── now_gpu # 当前批次 GPU

│ ├── disk_gpu # 磁盘巡检组

│ ├── dk_test # 驱动测试组

│ ├── remain_gpu # 剩余 GPU 组

│ └── hosts.ini # 总表

├── playbooks/

│ ├── push_conf.yml

│ ├── disable_nm.yml

│ └── push_pubkey.yml

└── files/

├── my.conf

└── my_binary

ansible.cfg 最小可用:

bash 复制代码
[defaults]
inventory = ./inventory/gray
remote_user = root
private_key_file = ~/.ssh/id_rsa
host_key_checking = False
forks = 50

⚠️ host_key_checking = False 只在内网可信环境用,公网机器建议先把指纹写进 known_hosts。


三、第一步永远是连通性巡检

任何批量操作前,先 ping 一遍,把不可达的机器捞出来:

全量连通性检查

bash 复制代码
ansible -i inventory/gray All -m ping

把不可达机器单独落盘,后面单独处理

bash 复制代码
ansible -i inventory/gray All -m ping | grep 'UNREACHABLE!' | awk '{print $1}' > unreachable_hosts.txt

看下有多少台不通

bash 复制代码
wc -l unreachable_hosts.txt

为什么这步不能省:

  • 免密没配好的机器,后面 playbook 跑一半报错,输出里混着成功失败很难看。
  • 新扩容机器没登过,known_hosts 没指纹,直接跑会卡住。
  • 先把不可达的摘出来单修,再跑全量,心里有数。

四、灰度分批:多套 inventory 是核心

别一上来全量推。按风险等级分 inventory:

inventory 用途 机器规模
gray 灰度验证,先推 3~5 台 极小
test_gpu 测试集群,验证业务兼容 小
now_gpu 当前批次生产机 中
disk_gpu 只做磁盘类变更的分组 按需求
dk_test 驱动/内核类变更前验证 小
remain_gpu 前几批跑完后的剩余全量 大

执行节奏:

  1. 先跑灰度
bash 复制代码
ansible-playbook -i inventory/gray push_conf.yml --check
ansible-playbook -i inventory/gray push_conf.yml
  1. 再跑测试集群
bash 复制代码
ansible-playbook -i inventory/test_gpu push_conf.yml
  1. 确认无异常,跑当前批次
bash 复制代码
ansible-playbook -i inventory/now_gpu push_conf.yml
  1. 最后剩余全量
bash 复制代码
ansible-playbook -i inventory/remain_gpu push_conf.yml

五、变更前先 dry-run(这条最值钱)

Ansible 的 --check(简写 -C)模式不会在远端做任何实际修改,支持 check mode 的模块会报告"将会发生什么变化",不支持的模块则不动作也不报。

5.1 基本用法

只模拟,不修改任何内容

bash 复制代码
ansible-playbook -i inventory/now_gpu push_conf.yml --check

配合 --diff 查看具体修改了哪几行

bash 复制代码
ansible-playbook -i inventory/now_gpu push_conf.yml --check --diff

只验证单台主机

bash 复制代码
ansible-playbook -i inventory/now_gpu push_conf.yml --check --diff --limit 192.168.1.11

5.2 为什么这个习惯能救命

  • 配置文件路径写反了 → dry-run 阶段就能看到目标路径不对
  • 模板变量没渲染 → diff 一看就知道
  • 会把服务重启错节点 → --limit 先扔一台上试
  • 条件判断依赖上一步结果 → check mode 是模拟,复杂条件链还是要上灰度机真跑一次

💡 经验法则:任何 playbook 上线前,不管多简单,先 --check 再 --limit 单台,最后才全量。这条习惯比会写多少 module 都重要。

5.3 Check Mode 的边界(必须知道))

  • 不是所有 Module 都支持 Check Mode,不支持的就什么都不做也不报报- 依赖"上一步先创建目录再写文件"的剧本,Dry-Run 可能报不出真实错误误
  • 所以 --check 代替不了灰度机真跑,两者是互补关系

六、常见批量任务实战

6.1 批量下发配置文件

Ad-hoc 方式式

bash 复制代码
ansible -i inventory/now_gpu All -m copy \
  -a "src=./files/my.conf dest=/etc/myapp/my.conf mode=0644 owner=root group=root backup=yes" \
  --become

Playbook 方式(推荐,可复用))

push_conf.yml

• name: push my.conf

hosts: All

become: yes

tasks:

◦ name: backup and copy conf

复制代码
  ansible.builtin.copy:
    src: ../files/my.conf
    dest: /etc/myapp/my.conf
    mode: '0644'
    owner: root
    group: root
    backup: yes
  notify: reload myapp

handlers:

◦ name: reload myapp

复制代码
  ansible.builtin.systemd:
    name: myapp
    state: reloaded

backup=yes / backup: yes 一定加上------改挂了还能退回到 Ansible 自动备份的那个时间戳文件。

6.2 批量下发 RPM / 二进制制

推 RPM 包包

bash 复制代码
ansible -i inventory/now_gpu All -m copy \
  -a "src=./packages/xxx.rpm dest=/tmp/xxx.rpm" --become

推完再装

bash 复制代码
ansible -i inventory/now_gpu All -m yum \
  -a "name=/tmp/xxx.rpm state=present" --become

推二进制到 /usr/local/bin

bash 复制代码
ansible -i inventory/now_gpu All -m copy \
  -a "src=./files/my_binary dest=/usr/local/bin/my_binary mode=0755 owner=root group=root" \
  --become

6.3 批量下发公钥(给新机器开免密)

控制端先有公钥。

用 authorized_key 模块,比手动追安全得多。多

push_pubkey.yml

• name: ensure ansible control pubkey present

hosts: All

become: yes

tasks:

◦ name: add control pubkey

复制代码
  ansible.posix.authorized_key:
    user: root
    state: present
    key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

6.4 批量执行巡检命令

查看所有机器的 uptimee

bash 复制代码
ansible -i inventory/now_gpu All -m command -a "uptime"

查看磁盘盘

bash 复制代码
ansible -i inventory/disk_gpu All -m shell -a "df -h grep -E 'Use
90%'"

查看某个进程是否存在在

bash 复制代码
ansible -i inventory/now_gpu All -m shell -a "ps aux grep mmnetverify
 grep -v grep"

运行自研校验脚本本

bash 复制代码
ansible -i inventory/now_gpu All -m command -a "/usr/local/bin/netverify"

七、真实场景:批量禁用 NetworkManager

7.1 为什么要禁

在跑分布式文件系统 / 高性能网络 / 多网卡绑定的服务器上,NetworkManager 和传统的 network 服务容易抢网络接口的管理权,常见表现:

  • IP 配置被 NM 覆盖
  • 接口频繁 up/down
  • 路由表被改、DNS 被重置
  • 重启后网络起不来,报 RTNETLINK answers: File exists

这类环境里通常选关掉 NM,让传统 network 或 systemd-networkd 接管。

7.2 批量禁用 playbook

disable_nm.yml

• name: disable NetworkManager for stable networking

hosts: All

become: yes

tasks:

◦ name: stop NetworkManager now

复制代码
  ansible.builtin.systemd:
    name: NetworkManager
    state: stopped
  ignore_errors: yes

◦ name: disable NetworkManager on boot

  ansible.builtin.systemd:
    name: NetworkManager
    enabled: no
    masked: no
  ignore_errors: yes

◦ name: make sure network service is up

  ansible.builtin.systemd:
    name: network
    state: started
    enabled: yes
  ignore_errors: yes

7.3 执行顺序(关键)

  1. 先 dry-run
bash 复制代码
ansible-playbook -i inventory/gray disable_nm.yml --check
  1. 灰度机真跑,重启验证网络不丢
bash 复制代码
ansible-playbook -i inventory/gray disable_nm.yml
ssh 192.168.1.10 "reboot"    # 观察能不能正常起来、IP 在不在
  1. 再推全量
bash 复制代码
ansible-playbook -i inventory/now_gpu disable_nm.yml

⚠️ 关 NM 前一定确认:受控端有其他管理方式能拿回网络(比如带外 BMC / 控制台)。纯 SSH 关 NM 如果配置不对,重启后可能连不上。


八、幂等:Ansible 和批量 Shell 脚本的本质区别别

写 Ansible 最忌写成这样:

反例:非幂等,跑几次加几行

• name: add sudo rule

shell: echo "myuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

正确写法:

• name: ensure sudo rule present

ansible.builtin.lineinfile:

path: /etc/sudoers.d/myuser

line: "myuser ALL=(ALL) NOPASSWD:ALL"

create: yes

mode: '0440'

validate: "visudo -cf %s"

判断标准:同一个 playbook 跑第二遍,changed 数应为 0。不为 0 说明剧本有逻辑漏洞。


九、踩坑清单

现象 根因 解决
UNREACHABLE! 大量报错 免密没配 / 指纹没录 / 用户不对 先捞不可达清单单修,别硬推全量
--check 显示 ok,真跑却报错 有 task 不支持 check mode,或依赖前一步建目录 必须再上灰度机真跑一次
改完配置服务没生效 没写 handler / 没 notify 用 notify + handlers 触发 reload
第二次跑还是 changed 剧本非幂等 换用 lineinfile / template 等声明式模块
关了 NetworkManager 重启断网 传统 network 没配好或接口没释放 先留 BMC 通道,灰度机重启验证
批量执行特别慢 forks 太小 / SSH 超时 调大 forks=50,设 timeout=30
敏感变量明文提交到 git 没用 ansible-vault 密钥类统一 ansible-vault 加密
新机器 Python 找不到 没装 python3 或解释器路径不对 inventory 里加 ansible_python_interpreter=/usr/bin/python3

十、小结

Ansible 批量运维的生产级节奏就五步:

  1. 先 ping:把不可达机器捞出来单独处理
  2. 分 inventory:灰度 / 测试 / 当前批 / 剩余全量,分层推进
  3. 必 dry-run :--check --diff --limit 单台先验证,再去掉 --check 真跑
  4. 写幂等:用 module 声明终态,别用 shell 硬怼
  5. 高危操作留后路 :backup=yes、关 NM 前留 BMC、回滚命令先想好

Ansible 入门看的是 module 怎么写,成熟看的是变更纪律------先想清楚搞砸了怎么退回来,再动手推全量。

有问题的在评论区贴你的 playbook 和 --check 输出,我看到会回。

相关推荐
colinu1 小时前
Docker 容器自启动策略说明与常用命令
运维·docker·容器
灯澜忆梦1 小时前
【docker】#3 | 数据卷挂载
运维·docker·容器
像风一样自由202010 小时前
52.Docker部署大模型应用从本地开发到服务化运行
运维·人工智能·docker·容器·大模型·智能体
sxgzzn10 小时前
如何利用电缆故障定位在线监测系统提升供电安全?
运维·重构·无人机·开关柜局放在线监测·gis局放在线监测
mengchanmian11 小时前
VSFTP 服务器搭建(Centos)
运维·服务器·centos
别动我齐刘海12 小时前
Linux 系统调试学习1
linux·运维·服务器·c++·学习·机器学习·机器人
不像程序员的程序媛13 小时前
linux常见文本操作命令
linux·运维·服务器
wangbing112514 小时前
开发指南149-IotDB-常用命令
linux·运维·iotdb
Dovis(誓平步青云)14 小时前
常用命令藏得太深?怎么做一个快捷命令坞
运维·前端·自动化·音视频·prometheus