使用PSSH的9条命令在Linux中执行并行SSH的示例
PSSH是Parallel Secure SHell或者Parallel SSH的缩写。
pssh是一个用于在许多主机上并行执行ssh的程序。
它提供的功能包括将输入发送到所有进程,将密码传递给ssh,将输出保存到文件以及超时。
PSSH_NODENUM和PSSH_HOST环境变量被发送到远程主机。
为每个ssh连接分配了" PSSH_NODENUM"变量唯一的编号,该编号从0开始递增。
按照主机列表中的指定,为PSSH_HOST变量分配主机的名称。
注意:建议在Linux节点之间启用ssh密钥对,以便pssh可以更有效地工作。
否则,我们最终将为该工具创建的每个线程编写密码。
PSSH不在RHEL或者CentOS仓库中,因此我们需要从EPEL仓库中手动下载并安装rpm。
为了进行此演示,我在设置中的多个节点之间创建了一个无密码配置。
使用文件传递主机列表
我们可以使用主机列表创建一个文件,该文件可用作PSSH的输入。
# cat /tmp/host_file.txt [email protected]:22 [email protected]:22 [email protected]:22
现在,我们将为该文件中的所有主机调用PSSH以执行date命令。
# /bin/pssh -h /tmp/host_file.txt date [1] 19:29:01 [SUCCESS] [email protected]:22 [2] 19:29:01 [SUCCESS] [email protected]:22 [3] 19:29:01 [SUCCESS] [email protected]:22
因此,如我们所见,该工具能够成功连接所有提供的主机,并且所有主机的"退出状态"为"成功"。
手动传递主机列表
如果我们只希望在其上执行某些命令的主机列表很少,则可以手动传递信息
# /bin/pssh -H "10.43.138.2 10.43.138.3 10.43.138.9" -l root date [1] 19:39:00 [SUCCESS] 10.43.138.3 [2] 19:39:00 [SUCCESS] 10.43.138.2 [3] 19:39:00 [SUCCESS] 10.43.138.9
按主机打印内联输出
我们可能已经注意到,对于上述两个示例,"退出状态"均为"成功",但该工具从未在屏幕上打印任何输出。
当每个主机完成时,使用" -i"显示标准输出和标准错误。
在下面的示例中,我们将看到执行完成后每个主机的输出。
# /bin/pssh -i -H "10.43.138.2 10.43.138.3 10.43.138.9" -l root date [1] 19:39:00 [SUCCESS] 10.43.138.3 Sun Dec 16 19:39:00 IST 2016 [2] 19:39:00 [SUCCESS] 10.43.138.2 Sun Dec 16 19:39:00 IST 2016 [3] 19:39:00 [SUCCESS] 10.43.138.9 Sun Dec 16 19:39:00 IST 2016
提示输入密码
由于我们在主机之间启用了减少密码的通信,因此该工具不会提示我们输入密码。
使用" -A"工具将提示输入密码,并将其传递给ssh。
密码可用于解锁密钥或者密码验证。
密码是以相当安全的方式传输的(例如,它不会显示在参数列表中)。
但是,请注意,系统上的root用户可能会拦截密码。
# /bin/pssh -A -i -H "10.43.138.2 10.43.138.3 10.43.138.9" -l root date Warning: do not enter your password if anyone else has superuser privileges or access to your account. Password: [1] 20:14:06 [SUCCESS] 10.43.138.3 Sun Dec 16 20:14:06 IST 2016 [2] 20:14:06 [SUCCESS] 10.43.138.2 Sun Dec 16 20:14:06 IST 2016 [3] 20:14:06 [SUCCESS] 10.43.138.9 Sun Dec 16 20:14:06 IST 2016
存储STDOUT
使用" -o"或者" --outdir"参数,可以将标准输出保存到给定目录中的文件中。
文件名的格式为" [user @] host [:port] [。
num]",其中用户和端口仅用于明确指定文件名的主机。
该数字是一个计数器,对于多次指定的主机,每次都会递增。
# /bin/pssh -i -o /tmp/out/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root date [1] 19:44:04 [SUCCESS] 10.43.138.3 Sun Dec 16 19:44:04 IST 2016 [2] 19:44:04 [SUCCESS] 10.43.138.2 Sun Dec 16 19:44:04 IST 2016 [3] 19:44:04 [SUCCESS] 10.43.138.9 Sun Dec 16 19:44:04 IST 2016
接下来检查/tmp/out
以获得STDOUT
结果。
# ll /tmp/out/ total 12 -rw-r----- 1 root root 29 Dec 16 19:44 10.43.138.3 -rw-r----- 1 root root 29 Dec 16 19:44 10.43.138.2 -rw-r----- 1 root root 29 Dec 16 19:44 10.43.138.9
# cat /tmp/out/10.43.138.3 Sun Dec 16 19:44:04 IST 2016
存放STDERR
使用-e
或者'--errdir'可以将标准错误保存到给定目录中的文件中。
文件名的格式与-o
选项相同。
我将重复相同的命令
# /bin/pssh -i -o /tmp/out/-e /tmp/err/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root date [1] 19:46:46 [SUCCESS] 10.43.138.3 Sun Dec 16 19:46:46 IST 2016 [2] 19:46:46 [SUCCESS] 10.43.138.2 Sun Dec 16 19:46:46 IST 2016 [3] 19:46:46 [SUCCESS] 10.43.138.9 Sun Dec 16 19:46:46 IST 2016
但是由于所有命令的EXIT STATUS均为SUCCESS,因此STDERR的内容为NULL。
# ll /tmp/err/ total 0 -rw-r----- 1 root root 0 Dec 16 19:46 10.43.138.2 -rw-r----- 1 root root 0 Dec 16 19:46 10.43.138.3 -rw-r----- 1 root root 0 Dec 16 19:46 10.43.138.9
因此,对于演示,让我尝试获得负输出。
其中我试图运行一个不存在的命令'datet'。
所以这意味着我们的PSSH将抛出错误
# /bin/pssh -i -o /tmp/out/-e /tmp/err/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root -x '-q -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes' datet [1] 19:48:19 [FAILURE] 10.43.138.3 Exited with error code 127 Stderr: bash: datet: command not found [2] 19:48:19 [FAILURE] 10.43.138.2 Exited with error code 127 Stderr: bash: datet: command not found [3] 19:48:19 [FAILURE] 10.43.138.9 Exited with error code 127 Stderr: bash: datet: command not found
不出所料,我们收到了除" 0"以外的"退出代码",现在,如果我们检查"/tmp/err",那么我们将为每个主机捕获相同的内容。
# ll /tmp/err/ total 12 -rw-r----- 1 root root 31 Dec 16 19:48 10.43.138.3 -rw-r----- 1 root root 31 Dec 16 19:48 10.43.138.2 -rw-r----- 1 root root 31 Dec 16 19:48 10.43.138.9
/tmp/out为空,因为任何主机上都没有此操作的STDOUT
# ll /tmp/out/ total 0 -rw-r----- 1 root root 0 Dec 16 19:48 10.43.138.2 -rw-r----- 1 root root 0 Dec 16 19:48 10.43.138.3 -rw-r----- 1 root root 0 Dec 16 19:48 10.43.138.9
注意:我们还可以将选项-o和-e组合在一起,以每台主机同时获取STDOUT
和STDERR
值。
将SSHD选项与PSSH一起使用
现在,理想情况下,PSSH仅接受某些受支持的选项列表。
但这并不意味着我们不能将SSHD参数与PSSH一起使用。
使用-x
,我们可以传递额外的SSH命令行参数(有关SSH参数的更多信息,请参见ssh(1)手册页)。
可以多次指定此选项。
将对参数进行处理以在空格上分割,保护引号内的文本以及使用反斜杠进行转义。
传递单个SSHD参数
# /bin/pssh -i -o /tmp/out/-e /tmp/err/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root -x 'StrictHostKeyChecking=no' date [1] 19:46:46 [SUCCESS] 10.43.138.3 Sun Dec 16 19:46:46 IST 2016 [2] 19:46:46 [SUCCESS] 10.43.138.2 Sun Dec 16 19:46:46 IST 2016 [3] 19:46:46 [SUCCESS] 10.43.138.9 Sun Dec 16 19:46:46 IST 2016
传递多个SSHD参数
# /bin/pssh -i -o /tmp/out/-e /tmp/err/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root -x '-q -o StrictHostKeyChecking=no -o GSSAPIAuthentication=no -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes' date [1] 19:53:56 [SUCCESS] 10.43.138.3 Sun Dec 16 19:53:56 IST 2016 [2] 19:53:56 [SUCCESS] 10.43.138.2 Sun Dec 16 19:53:56 IST 2016 [3] 19:53:56 [SUCCESS] 10.43.138.9 Sun Dec 16 19:53:56 IST 2016
获取具有成功和失败退出状态的主机列表
现在使用PSSH时,我面临的一个问题是,当我们在脚本中使用此工具时,会得到一个合并的"退出状态",但是默认情况下我们没有主机特定的退出状态。
因此,如果我们正在使用PSSH运行Shell脚本,那么我们可能不知道10台主机中哪些是成功的,哪些是失败的。
现在,我们可以使用-o和-e作为选项来分析此问题,但这几乎不需要脚本。
我在shell脚本中编写了以下代码,该脚本收集了第一台主机,并显示了包含成功和失败主机列表的" SUMMARY"。
function get_pssh_hosts { err_dir= out_dir= tmp_f_hosts=$(mktemp /tmp/tmp_f_hosts.XXX) tmp_s_hosts=$(mktemp /tmp/tmp_s_hosts.XXX) find $err_dir -type f -not -empty -print | rev | cut -d/-f 1 | rev >> $tmp_f_hosts 2>&1 find $err_dir -type f -empty -print | rev | cut -d/-f 1 | rev >> $tmp_s_hosts 2>&1 if [ ! -z $out_dir ];then for host in `cat $tmp_s_hosts`;do [[ ! -f $out_dir/$host ]] && exit_with_error "Unable to get the exit status for $host" # If file is empty then put to failed hosts if [ ! -s $out_dir/$host ];then if ! egrep -q ^$host$$tmp_f_hosts; then /bin/echo "$host" >> $tmp_f_hosts sed -i "/^$host$/d" $tmp_s_hosts fi else # If file is not empty then search for ERROR string, if found means the execution failed if ! grep -q ERROR $out_dir/$host;then if ! grep -q "^$host$" $tmp_s_hosts;then /bin/echo "$host" >> $tmp_s_hosts fi # if no ERROR string found in the log then put in success and avoid duplicates else /bin/echo "$host" >> $tmp_f_hosts sed -i "/^$host$/d" $tmp_s_hosts fi fi done fi sed -i '/^$/d' $tmp_s_hosts sed -i '/^$/d' $tmp_f_hosts success_hosts=`cat $tmp_s_hosts | tr 'n' ' '` failed_hosts=`cat $tmp_f_hosts | tr 'n' ' '` rm -f $tmp_f_hosts rm -f $tmp_s_hosts } function print_summary { /bin/echo "" /bin/echo "#####" /bin/echo "#" /bin/echo -e "# e[01;37mSUMMARY:e[0m" /bin/echo "#" /bin/echo -e "# e[01;32mSuccess:e[0m $success_hosts" /bin/echo -e "# e[01;31mFailed:e[0m $failed_hosts" /bin/echo "#" /bin/echo "#####" /bin/echo "" }
注意:在我的示例中,我为每个失败的PSSH命令打印一条带有ERROR的消息,因此我可以使用正则表达式获取成功和失败的主机列表。
"这是如何工作的?
"
err_dir=$(mktemp -d /tmp/errdir.XXX) out_dir=$(mktemp -d /tmp/outdir.XXX) /bin/pssh -i -o /tmp/out/-e /tmp/err/-H "10.43.138.2 10.43.138.3 10.43.138.9" -l root `datet || echo "ERROR"` get_pssh_hosts $err_dir $out_dir print_summary
现在其中我们在STDERR
中得到如下输出
# grep ERROR /tmp/err/10.43.138.3 bash: ERROR: command not found ##### ## SUMMARY: ## Success: # Failed: 10.43.138.2 10.43.138.3 10.43.138.9 ######
因此,我们的脚本可以轻松检测并区分成功和失败方案
使用PSCP将文件从一台服务器复制到多台服务器
pscp是一个用于并行复制多个主机文件的程序。
它提供了诸如将密码传递给scp,将输出保存到文件以及超时等功能。
与PSSH一样,该工具还支持几乎所有选项。
在下面的示例中,我将复制服务器上位于/home/hynman /
下的客户端节点上的/tmp/temp.txt
文件。
# /bin/pscp.pssh -H "10.43.138.2 10.43.138.3 10.43.138.9" -l root /tmp/temp.txt /home/hynman/ [1] 20:22:47 [SUCCESS] 10.43.138.3 [2] 20:22:47 [SUCCESS] 10.43.138.2 [3] 20:22:47 [SUCCESS] 10.43.138.9