批量执行命令核心分为4 大类方案:原生 Shell 批量、轻量 Agentless(Ansible)、Agent 模式(SaltStack/Puppet)、自研平台(Go/Python 封装)。生产最常用是 Ansible,简单临时场景用 Shell 脚本 + sshpass/expect。
核心诉求:批量下发命令、回显收集、失败重试、超时控制、权限管控、日志留存、禁止高危命令(rm -rf、格式化等)。
一、无 Agent 方案(Agentless,推荐优先)
不需要在目标机器安装客户端,通过 SSH 协议远程执行,适合 Linux 服务器。
1. 简易 Shell 批量(临时应急,不适合大规模)
方式 1:ssh + 循环(需要免密 ssh)
# host.txt 每行一个IP
while read ip; do
echo "===== $ip ====="
ssh root@$ip "hostname; df -h"
done < host.txt
优点:零依赖,服务器自带 ssh
缺点:串行执行慢;没有超时、失败隔离;输出混杂;无并发控制
方式 2:并行版本(GNU parallel)
cat host.txt | parallel -j 10 "ssh root@{} 'hostname; free -h'"
-j 10:并发 10 台,防止打爆跳板机
免密不方便时,可用
sshpass传入密码,但安全风险极高,生产禁止,仅测试环境临时用。
2. Ansible(企业主流首选)
底层基于 SSH,YAML 描述任务,支持并发、过滤主机、重试、日志、变量、权限控制。
1)inventory 主机清单 hosts.ini
[web]
192.168.1.10
192.168.1.11
[db]
192.168.1.20
2)Ad-hoc 临时批量执行命令(一行命令,最常用)
# 对web分组所有机器执行命令,并发5台
ansible web -i hosts.ini -m command -a "df -h" -f 5
# shell模块(支持管道、重定向)
ansible web -m shell -a "ps -ef | grep java"
command:不经过 shell,更安全,不支持管道;shell:调用系统 shell,支持管道,有注入风险。
3)Playbook 剧本(复杂批量配置,可复用)
# batch_cmd.yml
- hosts: web
gather_facts: false
tasks:
- name: 查看磁盘
shell: df -h
register: disk_res
- debug: msg="{{ disk_res.stdout_lines }}"
执行:
ansible-playbook batch_cmd.yml -f 8
Ansible 优势
并发、超时、错误处理、主机分组、黑白名单
模块丰富:拷贝文件、修改配置、重启服务
结果结构化输出,可导出日志
支持密码、密钥、堡垒机跳转
缺点
大规模上千台时,SSH 连接开销大;
Windows 需要 WinRM 配置。
二、Agent 模式(需要在目标机器安装客户端)
1. SaltStack
Master/Minion 架构,目标机器部署 minion agent,长连接,下发指令速度快,适合几千台规模。
# master端执行,批量执行命令
salt 'web*' cmd.run 'df -h'
优点:长连接,并发极强;支持事件返回;可做状态配置管理。 缺点:每台机器装 agent,维护成本;agent 进程安全管理。
2. Puppet / Chef
偏向配置收敛(保证目标机器配置符合预期),不是 “临时跑一条命令”,更适合持续配置管理,临时批量执行不推荐。
三、自研批量执行平台(企业内部运维平台)
很多大厂自研运维平台,底层两种实现:
跳板机 + 并发 SSH(类似封装 Ansible/paramiko)
自研 Agent(Go 写轻量 agent,grpc/http 长连接,接收指令执行,回传结果)
Python 简易 Demo(paramiko,SSH 并发执行,仅原理演示,生产不要直接裸用)
import paramiko
from concurrent.futures import ThreadPoolExecutor
def run_cmd(ip, cmd):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, username="root", key_filename="/root/.ssh/id_rsa")
stdin, stdout, stderr = ssh.exec_command(cmd, timeout=10)
out = stdout.read().decode()
err = stderr.read().decode()
ssh.close()
return ip, out, err
if __name__ == "__main__":
hosts = ["192.168.1.10", "192.168.1.11"]
with ThreadPoolExecutor(max_workers=5) as pool:
res = pool.map(lambda x: run_cmd(x, "df -h"), hosts)
for ip, out, err in res:
print(f"==== {ip} ====\n{out}\n{err}")
生产自研必须加:超时、命令白名单、审计日志、权限、限流、命令语法校验,防止高危操作。
四、Windows 机器批量执行
WinRM:Ansible 通过 WinRM 管理 Windows
PowerShell Remoting:
Invoke-Command批量执行
Invoke-Command -ComputerName server01,server02 -ScriptBlock {Get-Process}
五、生产落地必须考虑的安全 & 稳定性要点
命令白名单:禁止直接下发任意命令。高危命令(rm、mkfs、dd、halt)拦截,支持参数校验。
并发控制 & 限流:不能一次性几百台并发,防止雪崩;按业务分组分批执行。
超时机制:单台命令必须设置超时,防止卡死。
审计日志:记录执行人、时间、主机、命令、返回结果,全链路审计。
权限最小化:不要全部 root 执行,按需账号;优先 SSH 密钥,禁用密码登录。
失败策略:支持失败阈值,比如超过 10% 机器失败,自动终止任务。
预检查机制:执行前先做连通性检查;高危操作支持dry-run 预览,不真正执行。
输出收集:区分 stdout/stderr,保存日志,支持结果筛选。
方案选型建议
常见坑
SSH 连接数打满,跳板机报错:调 sshd MaxSessions,降低并发数;
机器时间不同步、主机密钥变更导致 SSH 失败;
命令里特殊字符、管道、引号转义问题;
大输出回显内存溢出,限制回显长度;
忽略命令注入风险,用户输入直接拼接执行命令。
本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。
原文链接
欢迎访问 小易撩挨踢