要在Linux下把文件复制到多台服务器,最实用的办法是组合使用scp、rsync、pssh或Ansible,按服务器数量和运维习惯选型。
先用for循环加scp,解决小规模分发
手里只有三五台机器,没必要上重工具,写个for循环,把IP列表塞进去,一条命令跑完一轮,这是Linux运维最常见的起步操作,简单、直接、看得懂。
for ip in 192.168.1.11 192.168.1.12 192.168.1.13; do scp /data/app.tar.gz root@$ip:/opt/ done
这个命令会把app.tar.gz逐个推到三台服务器的/opt目录,每推完一台,终端会提示输入一次root密码,机器少可以接受,机器多了手会抽筋。
把IP列表抽出来,放进文件循环
IP太多写在一行太挤,建议把目标IP存成文件,一行一个,循环读取:
for ip in $(cat /root/iplist.txt); do scp /data/app.tar.gz root@$ip:/opt/ done
这样加机器只需改iplist.txt,不用动脚本。
免密登录才是批量分发的第一步
每次输入密码太累,也不利于后续无人值守,生成密钥对,把公钥推送到各台机器上:
ssh-keygen -t rsa -b 4096 ssh-copy-id root@192.168.1.11 ssh-copy-id root@192.168.1.12
之后scp和ssh都不再问密码,行业共识认为,免密登录是所有批量操作的前置条件,这一步没做,后面用什么都费劲。
小规模机器复制文件,scp够用但有两个短板
第一,scp不支持断点续传,网络抖动断了,整个文件重传,大文件尤其吃亏,第二,scp每次都是全量复制,不管目标机器上有没有相同文件,都从头传一遍,机器少还能忍,机器多了效率上不去。
这就引出一个问题:linux批量分发文件到多台服务器的方法,有没有更省带宽、更抗中断的版本?有,rsync。
服务器数量多的时候,换rsync做增量同步
rsync最大的优势是增量传输,文件没变化就不传,只传改动过的部分,配合ssh隧道,安全性跟scp一个级别。
for ip in $(cat /root/iplist.txt); do rsync -avz --progress /data/app/ root@$ip:/opt/app/ done
-a归档模式保留权限和时间戳,-v显示过程,-z开启压缩,第一次全量,之后每次只传增量,带宽压力明显小。
rsync分发的细节处理
如果目标目录里有过期文件需要清理,加--delete参数:
rsync -avz --delete /data/app/ root@$ip:/opt/app/
这句的意思是,源目录删了什么,目标目录同步删掉什么,注意别用错方向,用反了会清空源目录。
指定端口和限速要写清楚
有些机房开了特殊ssh端口,rsync要额外指定:
rsync -avz -e "ssh -p 2222" /data/app/ root@$ip:/opt/app/
内网带宽有限时,加上--bwlimit限速,单位是KB/s:
rsync -avz --bwlimit=1024 /data/app/ root@$ip:/opt/app/
每秒只跑1MB,避免把线上业务带宽吃满,这个参数在内网批量传文件怎么保证速度和安全的场景里很实用,既能控速,又不影响其他服务。
并行分发,pssh比for循环快出量级
for循环是串行的,一台传完才传下一台,100台机器,每台传10秒,光等待就将近17分钟,pssh和pscp是并行工具,同时向多台机器发起连接,一轮下来时间约等于最慢那台耗时。
pscp一条命令推送到全部机器
先装工具,Debian系用apt,RedHat系用yum:
yum install pssh -y
然后准备好机器列表文件:
cat /root/iplist.txt 192.168.1.11 192.168.1.12 192.168.1.13
pscp并行推送:
pscp -h /root/iplist.txt -l root /data/app.tar.gz /opt/
-h指定机器列表,-l指定登录用户,几十台机器同时接收,速度肉眼可见地提升。
pssh做远程执行同样方便
不光传文件,批量执行命令也能用:
pssh -h /root/iplist.txt -l root -i "systemctl restart nginx"
每台机器的执行结果会直接打印到屏幕上,想保存结果,加-o /root/log/指定输出目录。
大并发注意ssh连接数限制
上百台机器同时连接,源服务器的MaxStartups限制可能被触发,需要调大sshd配置:
MaxStartups 100:30:200
改完重启sshd服务,否则会出现部分机器连接被拒绝的情况,表现为“connection closed by remote host”。
linux批量分发文件到多台服务器,生产环境标配Ansible
如果说前面几个工具还停留在“手工加半自动化”阶段,Ansible就是把分发变成真正的运维任务,无需在目标机器装客户端,只要控制机能ssh到对方就行。
Ansible安装和主机清单
控制机上安装:
yum install ansible -y
编辑/etc/ansible/hosts:
[web] 192.168.1.11 192.168.1.12 192.168.1.13 [db] 192.168.2.11 192.168.2.12
[web]和[db]就是分组名,后面可以按组操作。
copy模块推文件
批量复制文件到web组所有机器:
ansible web -m copy -a "src=/data/app.tar.gz dest=/opt/app.tar.gz owner=root group=root mode=0644"
这条命令会同时向web组三台机器推送文件,并自动设置属主和权限。
大批量复制目录用synchronize模块
文件多、目录嵌套深,copy模块效率不高,synchronize模块底层调用rsync,增量传输,更适合大目录:
ansible web -m synchronize -a "src=/data/app/ dest=/opt/app/ delete=yes"
delete=yes对应rsync的--delete,保证目标目录跟源目录完全一致。
Ansible的优势在于可编排,复制完还能接着干活
复制文件只是开头,后面往往跟着解压、改配置、重启服务,Ansible支持写在playbook里一气呵成:
- hosts: web
tasks:
- name: 复制压缩包
copy:
src: /data/app.tar.gz
dest: /opt/app.tar.gz
- name: 解压
unarchive:
src: /opt/app.tar.gz
dest: /opt/app
remote_src: yes
- name: 重启服务
systemd:
name: app
state: restarted
一次执行,全部搞定,这就是linux批量分发文件到多台服务器用什么工具的完整答案:单机用scp,批量用pssh,生产环境用Ansible。
四种工具怎么选,一张表看明白
| 工具 | 并发能力 | 断点续传 | 增量同步 | 适合规模 | 上手难度 |
|---|---|---|---|---|---|
| scp+for循环 | 串行 | 不支持 | 不支持 | 1-10台 | 最低 |
| rsync+for循环 | 串行 | 支持 | 支持 | 1-50台 | 低 |
| pscp/pssh | 并行 | 不支持 | 不支持 | 10-200台 | 中 |
| Ansible | 并行 | 支持(synchronize) | 支持 | 任意规模 | 中高 |
几个常见坑提前避开
第一,防火墙,目标机器selinux开着,rsync推文件后属主和权限可能错乱,加-p参数保留属性能缓解部分问题。
第二,磁盘空间,目标机器磁盘满了,传输会卡住或者报错No space left on device,批量分发前先确认各机器可用空间,用一条命令扫一遍:
pssh -h iplist.txt -l root -i "df -h /opt"
第三,文件一致性,分发完别急着跑,抽查两台看下md5:
md5sum /opt/app.tar.gz
对不上说明传输过程有异常,重推一次。
内网批量传文件怎么保证速度和安全
内网环境机器之间互信一般已经配置好,速度瓶颈主要在磁盘IO和网卡,建议压缩后再传,小文件塞进tar包里再分发,比逐个传小文件快得多:
tar czf app.tar.gz /data/app/
大文件超过10GB的,整包传输不现实,可以用rsync的--partial保留部分传输的文件,断了接着传。
安全方面,行业共识是尽量不用默认的22端口对外,改用密钥认证,并限制root直接登录,尤其内网批量传文件这种操作,一旦密钥泄露,所有机器门户大开,把密钥文件权限设为600,并且不要随便拷到开发机上。
常见问题解答
没有免密认证的情况下,批量传文件怎么输密码?
可以用sshpass在命令行直接指定密码:
yum install sshpass -y sshpass -p 'yourpassword' scp /data/app.tar.gz root@192.168.1.11:/opt/
配合for循环一样能批量推,注意密码会暴露在shell历史记录里,生产环境不建议这么干,更安全的做法是用Ansible的-k参数交互式输入密码,只输一次。
linux怎么复制文件到多台服务器,这条命令能不能用bash脚本封装?
完全可以,把常用的IP列表、源路径、目标路径抽成变量,写成函数放在~/.bashrc里:
mcopy() {
for ip in $(cat $1); do
scp $2 root@$ip:$3
done
}
之后执行mcopy /root/iplist.txt /data/app.tar.gz /opt/就能复用。
目标服务器操作系统不一样,分发命令有啥区别?
路径和权限管理不同,比如CentOS用systemctl,Ubuntu也用systemctl,但老版本SysVinit用service,分发文件本身不受影响,scp和rsync按字节复制,跟系统发行版无关,关键在执行后续命令时要区分系统类型,playbook里可以用when: ansible_os_family == "RedHat"之类的条件判断做分支。
批量分发文件是Linux运维的基本功,从for循环到Ansible,路径是逐渐从手工走向编排的过程,先把scp和rsync用熟练,再上pssh提速,最后用Ansible统一管理,这套组合下来,几千台机器的文件下发也能从容应对。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/778667.html


