怎样实现SSH批量运维脚本
目录导读
- 批量运维的核心痛点与解决思路
- 基础环境准备与密钥认证配置
- SSH批量执行脚本的三种主流实现方式
- 1 基于
for循环与sshpass的简易方案 - 2 使用
pssh(Parallel SSH)工具集 - 3 自定义Bash脚本封装
expect实现交互自动化
- 1 基于
- 企业级注意事项:安全、日志与错误处理
- 常见问题与问答
- 结语与最佳实践推荐
批量运维的核心痛点与解决思路
当服务器规模从几台扩展到几十、上百台时,手动逐个SSH登录执行命令会变得低效且易出错,批量运维脚本的核心目标就是:一次编写,多机并行执行,常见的场景包括:批量更新系统补丁、分发配置文件、检查服务状态、收集日志等。

核心解决思路:
- 免密认证:消除交互式密码输入,推荐使用SSH密钥对。
- 并行执行:避免串行等待,利用多进程或工具并发。
- 统一输出:区分每台主机的执行结果,便于排查错误。
基础环境准备与密钥认证配置
在编写脚本前,必须完成以下步骤:
生成SSH密钥对(控制节点)
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N "" # 将公钥分发到所有目标主机 ssh-copy-id user@host1_ip ssh-copy-id user@host2_ip # ... 依次分发
注意:批量分发公钥本身也可以用脚本循环实现。
建立主机列表文件(hosts.txt)
168.1.101
192.168.1.102
node3.example.com
验证连接
ssh -o StrictHostKeyChecking=no user@192.168.1.101 "hostname"
通过-o参数跳过首次连接确认,避免脚本卡住。
SSH批量执行脚本的三种主流实现方式
1 基于for循环与sshpass的简易方案
适用场景:临时性任务,对安全性要求不高(密码明文存储有风险)。
代码示例:
#!/bin/bash USER="root" PASS="your_password" COMMAND="uptime; free -h" while IFS= read -r ip do sshpass -p "$PASS" ssh -o StrictHostKeyChecking=no "$USER@$ip" "$COMMAND" done < hosts.txt
缺点:串行执行,速度慢;密码泄露风险大。
改进建议:仅用于内网测试环境,生产环境必须用密钥。
2 使用pssh(Parallel SSH)工具集
pssh是专门为批量SSH设计的工具,默认并行执行,效率高。
安装:
# CentOS/RHEL yum install epel-release -y && yum install pssh -y # Ubuntu/Debian apt install pssh -y
常用命令:
pssh -h hosts.txt -l root -i "df -h":执行命令并显示输出(-i表示交互式输出)。pscp -h hosts.txt -l root /etc/hosts /tmp/:批量分发文件。
高级用法:结合-p参数控制并发数(默认32),-o指定输出目录。
pssh -h hosts.txt -l root -o /tmp/logs -p 10 "systemctl status nginx"
优势:内建超时、错误处理,适合生产环境。
3 自定义Bash脚本封装expect实现交互自动化
当目标主机未配置密钥,且必须自动输入密码时,expect可用。
脚本模板:
#!/usr/bin/expect -f
set timeout 10
set host [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set command [lindex $argv 3]
spawn ssh $user@$host $command
expect {
"password:" { send "$password\r"; exp_continue }
"yes/no" { send "yes\r"; exp_continue }
eof
}
配合Bash调用:
while read ip; do ./expect_ssh.sh $ip root your_password "uptime" & done < hosts.txt wait
注意:&实现后台并发,但需控制进程数以防资源耗尽。
企业级注意事项:安全、日志与错误处理
安全措施
- 禁用密码登录:全部使用密钥认证,禁止
sshpass或expect密码明文。 - 限制来源IP:在安全组或防火墙中,仅允许控制节点IP连接SSH端口(默认22)。
- 使用非root账户:通过
sudo执行高权限操作,提升审计能力。
日志策略
- 每条命令的输出重定向到以主机命名的文件:
ssh user@host "command" > logs/$host.log 2>&1
- 使用
ts(moreutils包)为输出添加时间戳。
错误处理
- 超时控制:
ssh -o ConnectTimeout=5避免死等。 - 重试机制:失败后重试3次,间隔2秒。
- 状态码检测:检查值,非零则记录错误。
完整脚本示例:
#!/bin/bash
HOSTS="hosts.txt"
USER="opsuser"
KEY="/home/opsuser/.ssh/id_rsa"
LOG_DIR="./logs"
mkdir -p "$LOG_DIR"
while IFS= read -r ip; do
(
( ssh -i "$KEY" -o StrictHostKeyChecking=no -o ConnectTimeout=5 "$USER@$ip" "
sudo systemctl status nginx || echo 'FAILED';
free -m | grep Mem
" ) > "$LOG_DIR/${ip}.log" 2>&1
if [ $? -ne 0 ]; then
echo "$ip: error" >> "$LOG_DIR/error_summary.txt"
fi
) &
# 控制并发数(最多20个后台进程)
while [ $(jobs -r | wc -l) -ge 20 ]; do
sleep 1
done
done < "$HOSTS"
wait
echo "All tasks completed. Check logs in $LOG_DIR"
常见问题与问答
Q1:脚本执行过程中,部分主机突然断开连接怎么办?
A:配置ServerAliveInterval和ServerAliveCountMax保持心跳,同时启用自动重连:
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 ...
Q2:如何批量复制文件而不是执行命令?
A:使用scp配合循环,或直接用pscp(pssh工具集的一部分):
pscp -h hosts.txt -l user /local/file /remote/path
Q3:有没有更现代化的替代工具?
A:可考虑Ansible(基于Python,无需代理)或Fabric(轻量级Python库),它们提供更丰富的模块和错误处理能力。
Q4:如何验证脚本在数百台主机上的执行结果?
A:汇总日志后,用grep -c "FAILED" *.log统计失败数量,或编写分析脚本提取关键字段。
结语与最佳实践推荐
综合来看,实现SSH批量运维脚本的最优路径是:
- 优先使用密钥认证,从根源消除密码交互。
- 对于简单命令执行,选择
pssh(高效、内置并行)。 - 对于复杂编排,迁移至
Ansible(声明式配置管理)。 - 始终包含日志、错误处理、超时控制三个安全网。
最后提醒:在生产环境运行批量脚本前,务必先在测试环境的小规模主机上验证,并考虑分批次灰度执行,避免全网操作失误导致服务中断,对于超过1000台的集群,建议使用配置管理工具(如Puppet、SaltStack)替代简单脚本,以实现更细粒度的状态管理。