问题集锦
其实标题的内容就是很常见的集群操作,当有一个脚本或者一个命令需要很多个机器同时(或者说接近同时)执行时,就涉及到几个问题:
- 怎么通知每个主机?
- 每个主机收到通知后,怎么让主机执行命令?
- 怎么让上面的过程同时发生?
上面其实可以分为两步:
- 登录到单个机器
- 让单个机器执行命令
重复上面的两个操作,执行多进程或者创建子进程都能达到目标。
接下来的问题:
- ssh登录需要密码,怎么设置无需密码就可以登录
- 登录后怎么让登录的机器执行命令
ssh免密码登录
关于这个问题,可以参考这篇博客ssh免密码登录配置
大致的过程:
ServerA 的UserA用户 希望使用ServerB 中UserB的账号免密登录ServerB
→ ~ $ ssh-keygen -t rsa #使用RSA加密算法生成密钥对 → ~ $ ssh-copy-id UserB@ServerB #将自己生成的公钥复制到远程主机的authorized_keys文件上
设置完成后,就可以在本地使用ssh UserB@ServerB来免密登录了。
让远程机执行命令
登录远程机之后,让远程机执行命令,在ServerB
你可能你会说下面这个命令
→ ~ $ ssh UserB@ServerB && echo "hello world" > index
然而上面这个命令并不会像我们期望的那样执行,过程如下:
- 在ServerA的终端执行上面这条命令
- 会先使用UserB免密登录到ServerB
- 接着会进入ServerB的终端
- 那条命令中的echo命令就被挂起了,因为ssh进程还没执行结束呢
- 在ServerB的终端中执行exit,退出ServerB
- 回到ServerA的终端,继续执行echo命令,然后命令执行结束
查看ServerA中UserA的子目录,会多出一个index文件,但是ServerB中UserB的家目录中却不会有index文件。
正确做法
→ ~ $ ssh UserB@ServerB 'echo "hello world" > index'
没错,只是单纯的用引号将命令括起来就行了,这样会被当做位置参数传递给ssh,然后就能成功在远程机上运行了
同时对多个机器发指令(多进程并行)
Linux里面的多进程有一个特别方便的方法:在命令后面加一个&符号,那么该命令就会在后台执行,也就是多进程了。
所以要有了前面几步基础之后,可以下面这样做,实现向所有机器同时发送指令:
#!/bin/bash #多进程对多个机器同时发指令 #注意下面的用户和ip是一一对应的,顺序不要搞错,额否则不能登录 #user1登录server1 server=( "192.168.1.1" "192.168.1.2" "192.168.1.3" "192.168.1.4" ) user=( "test1" "test2" "test3" "test4" ) #服务器和用户账号对应关系 tot_s=${#server[*]} tot_u=${#user[*]} if [ $tot_s -ne $tot_u ];then echo "服务器和用户账号数量不对应,请检查server列表和user列表" exit fi i=0 while [ $i -lt $tot_u ];do (ssh ${user[$i]}@${server[$i]} "command1;command2" & ) 2>> ~/Desktop/log.txt #注意一定要在最后面加&符号,否则就是串行执行,不能体现并行。 #将错误重定向到日志文件中 if [ $? -ne 0 ];then echo "${user[$i]}@${server[$i]}执行过程中出现异常" fi #注意迭代器别忘了自增 i=$[ $i + 1 ] done
注意:前提是已经可以无密登录,否则每次连接都要输入密码。