获取多台主机命令执行结果

在多台主机之间批量执行shell语句的效果

之前在主产品用过一个运维同事写的工具,devpssh。可以通过指定主机列表来执行一条shell命令,然后获取到所有的返回结果,输出到屏幕上。

我个人觉得这个工具很实用,尤其是在有多台Nginx服务器的时候,由于负载均衡策略下,不同的请求可能会被下放到不同的get机,因此产生的日志文件就可能分布在多台机器上。如果我们一个个地到每台get机上去执行shell语句。首先工作量会很大,另外获取到的结果也不容易整理。而此时用一下devpssh,就没有这些负担了。

在正式介绍如何写一个这样的工具之前,先来看看需要哪些基础的知识。

  • 主机间信任
  • shell脚本

主机间信任

说到主机之间的信任,还是要将历史往前追溯一下。谈谈SSH。简单来说SSH是一种网络协议,用于计算机之间的加密登录。之所以是加密登录就是应为原始的用户远程登录是明文的,一旦被截获,信息就泄露了。

SSH是协议,具体有很多实现。有商业实现的,也有开源实现。不过大致来看,用法是一致的。

先来看看安装了ssh的机器有什么不同吧。

执行过ssh-keygen后

id_rsa是使用RSA算法得到的私钥 id_rsa.pub是对称的RSA算法得到的公钥。 了解过对称加密算法的应该都知道,妥善保存好私钥是一件很重要的事情。

一般来说,第一次使用ssh登录到远程主机的时候,会有如下提示信息:

The authenticity of host 'host (12.18.429.21)' can't be established.
  RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
  Are you sure you want to continue connecting (yes/no)?

这段话的大致意思是说,无法确认你即将登录的远程主机的真实性,但是可以了解的就只有它的公钥指纹,如果确定要进行连接,选择yes即可。 然后会出现如下字样:

  Warning: Permanently added 'host,12.18.429.21' (RSA) to the list of known hosts.

然后ssh会提示你使用密码进行登录了。正确输入密码后,就可以正常的登录了。这个时候,其实远程主机的公钥就被保存到了~/.ssh/known_hosts文件中了。内容如下:

known_hosts文件内容

其中每一行都代表了一个曾经成功连接过的远程主机的公钥信息。

但是每次远程登录都需要输入一遍密码,感觉次数多了,总是感觉有点麻烦。而ssh也支持使用公钥进行登录,这样就省去了每次登陆都要输入一遍密码的步骤了。

具体的做法如下: 将自己的电脑的公钥发送到目标主机的.ssh/authorized_keys中,这样登录的时候ssh协议通过对称加密,解密的验证过程,就可以实现公钥登录了。

这个对称加密,解密大致有这么个流程。

  • 本地主机使用ssh进行远程登录
  • 远程主机借助authorized_keys里面本地主机的信息生成一个随机字符串发给本地主机
  • 本地主机用自己的私钥将这个字符串进行加密,发给远程主机。
  • 远程主机使用本地主机的公钥进行 解密,如果成功,身份验证也就通过了。

最后来一个小总结:

  • known_hosts里面是已经成功远程登录过的主机的公钥信息。
  • authenrized_keys是已经授权的,可以免密码登录到本机的“主机”的公钥信息。

公钥免密登录也会是待会主机间的信任的基础。再来回顾下需求,我要在某一台主机上执行一条命令,然后获取全部的get机上相对应的内容。那么这台主机就可以作为master。

在master上,将通过ssh-keygen命令生成的公钥发送到要进行远程登录的get机的.ssh/authenrized_keys中。 比如: master机器为192.168.30.100 get机列表是: 192.168.32.102 192.168.32.105 192.168.32.109 192.168.32.110 我们就可以依次将100的公钥使用SCP命令或者其他的上传工具,上传到对应的get机的authenrized_keys文件中。

ssh-keygen -t rsa //此处一路回车,生成秘钥

scp .ssh/id_rsa.pub 192.168.32.102:~/ //把秘钥拷贝到其他远程机器

ssh 192.168.30.102 ‘cat id_rsa.pub >> .ssh/authorized_keys’ //(远程执行命令)在远程机器上生成认证文件

这样,将master的公钥就成功的添加到102这台get机上了。其他的get机就可以按照同样的方法做下处理。处理完之后,就可以使用公钥进行免密码登录到远程主机了。

至此,主机间的信任就算结束了。


shell脚本编写

目标需求是获取所有get机上执行的shell命令,并进行整合输出。我在网上找了一个shell脚本,大致的内容如下:

#!/usr/bin bash
docommand()
{
    hosts=`sed -n '/^[^#]/p' hostlist`
    for host in $hosts
        do
            echo "" # 换个行
            ssh $host "$@"
        done
    return 0
}
if [ $# -lt 1  ]
then
    echo "$0 cmd"
    exit
fi
docommand "$@"

然后需要在同级目录下创建一个get主机列表。

192.168.32.102
192.168.32.105
192.168.32.109
192.168.32.110

然后懒得输入bash前缀来执行命令的话,就可以写一个alias了在~/.bashrc 文件末尾添加如下内容:

alias devpssh='bash /home/developer/runcommand.sh'

然后**source ~/.bashrc*

这样就可以通过如下格式,来批量在主机之间执行shell命令了,具体的格式如下:

devpssh 'cat /var/log/nginx/api_acces.log | grep curuserid=2614677 | tail -1'

在多台主机之间批量执行shell语句的效果

至此,在多台主机之间执行shell命令也就得以实现了。


总结

本次内容比较少,单纯的了解了下ssh的一些相关知识点。然后是利用公钥免密登录并执行相关的shell命令。

麻雀虽小,但是却很实用。