ansible批量节点执行操作
结论
Ansible 批量节点执行的核心是 "控制端 + SSH + 模块" 的 agentless 模型:控制端无需在目标节点安装任何 agent,只要控制端能 SSH 登录节点,就可以通过一条命令(ad-hoc)或一个剧本(playbook)同时操作 Inventory 清单里的成百上千台机器。批量执行有两条主路径:
- ad-hoc 命令(
ansible):适合一次性、简单的批量操作,如批量 ping、批量执行命令、批量拷贝文件、批量重启服务; - Playbook 剧本(
ansible-playbook):适合多步骤、可复用、带条件判断与回滚逻辑的批量编排,如批量下发配置并重启、批量巡检并汇总。
批量执行的三个关键要素:Inventory(对哪些节点执行)、模块(执行什么操作)、forks / serial(多大并发、如何滚动)。日常批量操作优先用 ad-hoc + 常用模块,复杂的编排才需要写 playbook。
分析环境与版本
本文基于 ansible community package 14.x(ansible-core 2.21.x,2026 年 9 月发布) 编写,示例命令在 Rocky Linux / CentOS 7+ 控制端验证,兼容 ansible-core 2.13 及以上版本。官方支持矩阵要点:
- 控制端:Python 3.12 ~ 3.14(ansible-core 2.21);旧版本要求更宽松(如 2.15 控制端 Python 3.9+);
- 被管节点:Python 3.9 ~ 3.14(ansible-core 2.21),节点无需安装 Ansible;
- 传输协议:SSH(默认端口 22),支持密钥认证与 sudo 提权(become)。
一、批量执行原理
一次批量操作在底层是这样发生的:
- 控制端读取 Inventory 清单,解析出所有目标主机与分组;
- 对每个目标主机建立 SSH 连接(默认并发 5 个,可用
forks调整); - 把要执行的 模块(一个 Python 脚本)连同参数打包,上传到节点临时目录;
- 节点端用 Python 解释器执行模块,把结果序列化为 JSON;
- 控制端回收各节点结果,汇总为 ok / changed / failed 统计。
因此批量执行能否成功,取决于三件事:SSH 能否连上(免密或密码)、节点是否有 Python、模块是否支持该系统的包管理器。这也是排查批量失败时的第一思路。
二、安装与前置条件
控制端安装(任选其一):
# 完整社区版(含常用 collection,推荐)
pip install ansible
# 仅核心(模块较少,按需装 collection)
pip install ansible-core
验证版本:
ansible --version
# ansible [core 2.21.4]
# config file = /etc/ansible/ansible.cfg
安装完成后生成 SSH 密钥并分发到节点(批量执行的前提,只需一次):
ssh-keygen -t ed25519 # 生成密钥,一路回车
ssh-copy-id root@10.0.0.11 # 逐个节点分发公钥
ssh-copy-id root@10.0.0.12
三、Inventory:告诉 Ansible 操作哪些节点
默认清单文件是 /etc/ansible/hosts,更常用的做法是用 -i 指定自己的清单文件。支持 INI 与 YAML 两种格式。
INI 格式示例(hosts.ini):
[web]
10.0.0.11
10.0.0.12 ansible_host=10.0.0.12 ansible_user=root
[db]
10.0.0.21
10.0.0.22
[mysql:children]
db
[all:vars]
ansible_ssh_private_key_file=/root/.ssh/id_ed25519
ansible_python_interpreter=/usr/bin/python3
要点:
[web]、[db]是主机组,执行时可以只针对某个组;[mysql:children]表示子组继承(db组属于mysql组);[all:vars]定义作用于所有主机的变量;- 支持范围简写:
10.0.0.[11:20]表示 11~20; ansible_user、ansible_port、ansible_ssh_private_key_file可写在主机或组变量里,覆盖默认 SSH 连接参数;- 大规模集群可使用动态 Inventory(从云平台 API、CMDB 拉取),本质是输出 JSON 清单的脚本。
验证清单与连通性:
ansible -i hosts.ini all --list-hosts # 列出所有主机
ansible -i hosts.ini all -m ping # 批量连通性测试
四、SSH 免密与 ansible.cfg
批量执行最怕每台机器都输密码。除了 ssh-copy-id,还可以在 ansible.cfg 统一配置。配置文件查找顺序:当前目录 ansible.cfg > ~/.ansible.cfg > /etc/ansible/ansible.cfg。
[defaults]
inventory = ./hosts.ini # 默认清单
forks = 20 # 默认并发数(默认 5)
host_key_checking = False # 首次连接不提示确认指纹
timeout = 30 # SSH 连接超时(秒)
interpreter_python = auto_silent # 节点自动探测 Python,抑制告警
become = True # 默认提权
become_method = sudo
密码方式接入(不推荐用于生产,密码会明文出现在命令或文件里):
ansible all -m ping -u root -k # -k 交互输入 SSH 密码
需要 sudo 密码时:
ansible all -m command -a "id" -b -K # -b 提权,-K 交互输入 sudo 密码
五、ad-hoc 批量执行(日常主力)
通用语法:
ansible <主机组或模式> -m <模块> -a "<模块参数>"
常用参数:
| 参数 | 作用 |
|---|---|
-i <file> |
指定 Inventory 文件 |
--limit <hosts> |
只对部分主机执行(如 --limit 10.0.0.11) |
-f / --forks N |
并发数(默认 5) |
-b / --become |
提权执行(sudo) |
-K / --ask-become-pass |
交互输入 sudo 密码 |
-u <user> |
指定 SSH 用户 |
-k |
交互输入 SSH 密码 |
-v / -vvv |
输出详细信息(排错用) |
--check |
演习模式,不真正改动 |
--list-hosts |
列出将执行的主机 |
常用模块一览
| 模块 | 用途 | 示例 |
|---|---|---|
ping |
连通性测试 | -m ping |
command |
执行命令(不支持管道/重定向/变量) | -m command -a "uptime" |
shell |
执行命令(支持管道等,注意注入风险) | `-m shell -a "df -h |
script |
把控制端本地脚本分发到节点执行 | -m script -a "/opt/check_disk.sh" |
copy |
批量拷贝文件 | -m copy -a "src=/tmp/a.conf dest=/etc/a.conf mode=0644" |
template |
用模板渲染后下发(支持变量) | -m template -a "src=a.j2 dest=/etc/a.conf" |
yum / apt |
批量安装/卸载软件包 | -m yum -a "name=htop state=present" |
systemd / service |
批量启停服务 | -m systemd -a "name=nginx state=restarted" |
file |
批量创建目录/文件、改权限 | -m file -a "path=/data state=directory mode=0755" |
lineinfile |
批量修改配置文件行 | -m lineinfile -a "path=/etc/hosts line='10.0.0.5 node5'" |
cron |
批量添加定时任务 | -m cron -a "name='daily backup' minute=0 hour=2 job='/backup.sh'" |
user |
批量管理用户 | -m user -a "name=ops state=present groups=wheel" |
setup |
批量采集节点系统信息(facts) | -m setup |
gather_facts |
playbook 里采集 facts 用 | 见下文示例 |
实战场景
1. 批量连通性与主机信息
ansible web -m ping
ansible web -m setup -a "filter=ansible_distribution*" # 只看发行版信息
2. 批量执行命令
# 不支持管道
ansible all -m command -a "uptime"
# 支持管道/重定向
ansible all -m shell -a "uptime && free -h | head -3"
3. 批量执行本地脚本(最常用)
把控制端上的脚本分发到所有节点并执行,脚本输出会被收集回来:
ansible all -m script -a "/opt/ops/check_disk.sh"
ansible all -m script -a "/opt/ops/deploy.sh --env=prod" -b
4. 批量下发配置文件
ansible all -m copy -a "src=/opt/ops/nginx.conf dest=/etc/nginx/nginx.conf mode=0644 backup=yes" -b
5. 批量安装软件
ansible all -m yum -a "name=htop,iftop state=present" -b
ansible db -m yum -a "name=mysql-server state=absent" -b # 卸载
6. 批量重启服务(升级后的标准操作)
ansible web -m systemd -a "name=nginx state=restarted enabled=yes daemon_reload=yes" -b
7. 批量加定时任务
ansible all -m cron -a "name='clean tmp' minute=30 hour=3 job='/usr/bin/find /tmp -type f -mtime +7 -delete'"
六、Playbook 批量执行(可复用编排)
当操作超过一条命令、需要条件判断或多步骤时,写 playbook。示例:批量下发 nginx 配置并重启(只对配置变更的机器重启)。
deploy-nginx.yml:
---
- name: 批量部署 nginx 配置
hosts: web
become: true
vars:
nginx_port: 8080
tasks:
- name: 下发配置文件(模板)
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: restart nginx # 只有文件变化才触发 handler
- name: 校验配置
ansible.builtin.command: nginx -t
register: check_result
failed_when: "'successful' not in check_result.stdout"
- name: 打印校验结果
ansible.builtin.debug:
msg: "{{ check_result.stdout }}"
handlers:
- name: restart nginx
ansible.builtin.systemd:
name: nginx
state: restarted
执行与校验:
ansible-playbook deploy-nginx.yml --syntax-check # 语法检查
ansible-playbook deploy-nginx.yml --check # 演习模式
ansible-playbook deploy-nginx.yml --diff # 显示文件差异
ansible-playbook deploy-nginx.yml --limit 10.0.0.11 # 先单台验证
ansible-playbook deploy-nginx.yml -b -K # 正式执行(提权)
Playbook 常用控制项:
tasks:
- name: 循环安装多个包
ansible.builtin.yum:
name: "{{ item }}"
state: present
loop:
- htop
- iftop
- jq
- name: 条件执行(仅当文件存在)
ansible.builtin.command: cat /etc/redhat-release
when: ansible_os_family == "RedHat"
- name: 单台失败不中断其余节点
ansible.builtin.command: /opt/check.sh
ignore_errors: true
- name: 按标签选择性执行
ansible.builtin.systemd:
name: nginx
state: restarted
tags: [restart]
对应命令:ansible-playbook play.yml --tags restart、--tags "restart,config"、--skip-tags restart。
批量巡检示例(采集 facts 并输出摘要):
---
- name: 批量巡检
hosts: all
gather_facts: true
tasks:
- name: 汇总关键信息
ansible.builtin.debug:
msg: "{{ inventory_hostname }} | {{ ansible_distribution }} {{ ansible_distribution_major_version }} | CPU {{ ansible_processor_cores }}c | Mem {{ ansible_memtotal_mb }}MB | IP {{ ansible_default_ipv4.address }}"
执行结果会在控制端逐台打印,配合 register + debug 即可做到"批量执行 + 结果汇总"。
七、并发、分批与滚动
- forks:ad-hoc 与 playbook 的全局并发。
forks = 20表示同时向 20 台节点发起连接。并发越大,控制端与网络压力越大,按节点规模和操作类型权衡; - serial:playbook 中按比例或数量分批执行,适合滚动发布:
- name: 滚动重启
hosts: web
serial: 2 # 每批 2 台;也支持 "30%" 或 [1, 3, "50%"]
become: true
tasks:
- name: 重启服务
ansible.builtin.systemd:
name: app
state: restarted
- throttle:限制单个 task 的并发(如只允许同时重启 5 台),与 serial 配合用于避免雪崩;
- --limit:临时只操作部分主机,常用于灰度验证后全量。
八、结果查看与常见问题
执行结束后控制端会输出统计:ok=5 changed=3 unreachable=1 failed=0。unreachable 是连接不上,failed 是执行出错,两者都要单独排查。
常见问题与对策:
| 报错 / 现象 | 原因 | 对策 |
|---|---|---|
UNREACHABLE! ... Failed to connect to the host via ssh |
免密未配 / 端口不通 / 超时 | ssh-copy-id 重新分发公钥;检查 ansible_port、timeout |
The module failed to execute correctly |
节点没有可用的 Python | 安装 python3;或设置 ansible_python_interpreter=/usr/bin/python3 |
[WARNING]: Platform linux ... uses discovered Python interpreter |
解释器自动探测告警 | ansible.cfg 设 interpreter_python = auto_silent 或显式指定 |
sudo: a password is required |
提权需要密码 | -K 交互输入,或配置 NOPASSWD,或 become_user=root become_method=sudo |
Host key verification failed |
节点指纹变化/未信任 | host_key_checking = False(内网可信环境)或先 ssh-keyscan 录入 |
command 模块里管道不生效 |
command 不支持 shell 特性 |
改用 shell 模块 |
| 中文乱码 / 编码告警 | 节点 locale 非 UTF-8 | 节点设置 LANG=en_US.UTF-8;模块输出一般不影响执行 |
包管理器报 No package ... available |
模块与系统不符 | 确认用 yum(RHEL 系)/ apt(Debian 系)对应模块 |
排错三连:-v(第一层)、-vvv(看到 SSH 实际命令)、--check(确认改动范围)。
快速参考
| 需求 | 命令 |
|---|---|
| 连通性测试 | ansible all -m ping |
| 批量执行命令 | ansible web -m command -a "uptime" |
| 批量执行本地脚本 | ansible all -m script -a "/opt/ops/check.sh" |
| 批量拷贝文件 | ansible all -m copy -a "src=x dest=y mode=0644" |
| 批量安装软件 | ansible all -m yum -a "name=htop state=present" -b |
| 批量重启服务 | ansible all -m systemd -a "name=nginx state=restarted" -b |
| 批量加定时任务 | ansible all -m cron -a "name='x' minute=0 hour=2 job='/x.sh'" |
| 只操作部分主机 | 加 --limit 10.0.0.11 |
| 提高并发 | -f 20 或 ansible.cfg 设 forks=20 |
| 演习不生效 | 加 --check |
| 跑剧本 | ansible-playbook deploy.yml -b |
浙公网安备 33010602011771号