需求


日常工作中,我们常需要同时在多台服务器上执行同样的命令,如对比日志、检查服务等。这就需要我们有服务器批量操作的能力。

两年前写过一篇文章,shell实现SSH自动登陆 使用 shell 的 expect 命令进行 ssh 登陆,这种方式的灵活性确实非常高,但实现起来比较麻烦,而且单进程阻塞的特性也是它的硬伤,如果使用它进行批量操作,就需要启动多个 expect 进程,涉及到各个进程和主进程的双向通信,处理起来非常麻烦。

不过我们可以借用 ssh 公钥登陆 的能力,方便地实现在多个服务器上批量执行命令。

转载随意,文章会持续修订,请注明来源地址:https://zhenbianshu.github.io 。

SSH 协议


说公钥登陆之前,先来说一下 SSH 协议。

SSH 是一种网络协议,我们常说的 ssh 一般指其实现,即 OpenSSH,在 shell 中,也就是 ssh 命令。

SSH

Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。 SSH通过在网络中建立安全隧道来实现SSH客户端与服务器之间的连接。

SSH 的原理跟 HTTPS 差不多,都是基于 TCP 和 非对称加密进行的应用层协议。它跟 HTTPS 的不同之处在于 HTTPS 通过 数字证书 和 数字证书认证中心 来防止中间人攻击,而 ssh 服务器的公钥没有人公证,只能通过其公钥指纹来人工确定其身份。

如下图所示,我们第一次使用 ssh 登陆某台服务器时, ssh 会提示我们验证服务器的公钥指纹。

当我们验证此公钥指纹是我们要登陆的服务器后,服务器的公钥会被添加到 ~/.ssh/known_hosts 里,再登陆时,ssh 检测到是已认证服务器后就会跳过公钥验证阶段。

建连过程

关于通信加密的概念,我在之前的文章也有所介绍,参见:再谈加密-RSA非对称加密的理解和使用。至于 SSH 协议的建连过程,则可以参阅:Protocol Basics: Secure Shell Protocol

总结起来主要包括以下步骤:

  • TCP 三次握手
  • SSH 协议版本协商
  • 客户端与服务端的公钥交换
  • 加密算法协商
  • 客户端使用对称加密的密钥认证
  • 客户端与服务端安全通信

我使用 tcpdump + wireshark 抓包并查看了一下其 SSH 的建连过程,如下图所示:

不得不再次感叹 tcpdump + wireshark 是学习网络协议的真神器。

ssh 工具


ssh

作为工具, ssh 分为服务端和客户端,在服务端,它是 sshd,一般占用 22 端口。我们平常使用的是其客户端,一般用法为 ssh user@host,然后根据 ssh 的提示,我们输入密码后登陆到服务器。

它的功能非常强大,看其支持参数就知道了。

ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]

介绍完了 SSH 协议和 ssh 命令,终于说到公钥登陆了。

公钥登陆

理解了非对称加密的原理后,再公钥登陆会非常简单。由于公私钥是唯一的一对,在客户端保障自己私钥安全的情况下,服务端通过公钥就可以完全确定客户端的真实性,所以要实现公钥登陆,我们就要先生成一个公私密钥对。

通过 ssh-keygen 命令来生成密钥对,为了让步骤更完整,我把它们暂时保存到工作目录,默认会保存到 ~/.ssh 目录。

~ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/zbs/.ssh/id_rsa): ./test
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ./test.
Your public key has been saved in ./test.pub.
The key fingerprint is:
SHA256:xxxxx/B17z/xxxxxx zbs@zbs.local
The key's randomart image is:
+---[RSA 2048]----+
| o+*.. EO* |
| .... |
| oo+ .o++.o|
+----[SHA256]-----+
~ ls ./test*
./test ./test.pub

把私钥文件 ./test 的内容放到 客户端的 ~/.ssh/id_rsa,再使用密码试登陆到服务器后,将公钥内容 ./test.pub 里的内容放到 服务器的 ~/.ssh/authorized_keys

再次登陆时,ssh 会自动使用自己的私钥来认证,也就避免了输出密码。

批量操作

公钥登陆帮我们避免了每次登陆服务器要输出密码的麻烦,它同时也解决了每个登陆会话都会同步阻塞的问题,这样我们就可以利用 ssh 的 ssh user@host command 方式来直接在服务器上执行命令。

同时,在我们拥有一个 ip 列表的情况下,使用 for 循环遍历 ip 列表,在多个服务器上批量执行命令也就成为了可能。

关于批量执行,已经有很多开源工具了,如使用 python 编写的 pssh,C++ 编写的 hss(帮同事做个广告)等。

多服务器文件合并


前几天,帮同事在多个服务器上查找日志,需要把在多个服务器上查到的日志都汇总到同一台机器上进行统计分析。我是用 pssh 登陆的多个服务器,由于日志量太大,查出来的结果输出到终端上再复制有些不现实,而使用重定向,结果又会重定向到各自的服务器。

scp

这时候可以使用 scp,scp 跟 ssh 是同一家族的命令,也是基于 SSH 协议实现的安全传输协议。只要在各个服务器之间互相保存着对方的公钥,就可以跟 ssh 命令一样,实现免密操作。

scp 的常见用法是 scp src dst,其中远程路径可以表示为 user@host:/path。在批量登陆的情况下,可以使用 grep 等命令先把结果文件输入到一个文件中,再使用 scp 命令将其复制到同一台服务器。

为了避免各个服务器的文件名冲突,可以使用 uuidgen | xargs -I {} scp result.log root@ip:/result/{} 将各个服务器的结果复制到不同的文件中,再使用 cat 将 result 文件夹中的文件合并到一块。

nc

当然,大多数情况下,我们的服务器之间并不会互相保存公钥,不过 nc 命令可以完美解决这个问题。

nc 的 -k 选项,可以让 nc 服务端在文件传输结束后保持连接不关闭。这样,我们使用 nc -k -4l port > result.log 启动一个 nc 服务端,再使用 grep xxx info.log | nc ip port 即可实现结果数据的合并。

小结


本文介绍的各个工具还是属于开发的小打小闹,了解多一些工具总是好的。如果做运维工作的话,还是需要依赖 OPS 平台集成更多功能,实现完整的自动化。

关于本文有什么疑问可以在下面留言交流,如果您觉得本文对您有帮助,欢迎关注我的 微博 或 GitHub 。您也可以在我的 博客REPO 右上角点击 Watch 并选择 Releases only 项来 订阅 我的博客,有新文章发布会第一时间通知您。

使用 shell 在多服务器上批量操作的更多相关文章

  1. Java代码调用服务器上的Shell脚本

    Java代码调用服务器上的Shell脚本 这里主要是因为我们报表平台有用到用户手工录入的数据作为结果数据且需要纳入saiku去展示 如我们所知,saiku不会自动刷新,所以需要在数据更新接口中调用服务 ...

  2. Shell脚本实现超简洁的在Linux服务器上安装nginx、resin、java、tomcat、redis等程序

    说明: 用平常的方式在Linux服务器上安装程序,需要下载安装包.进入安装包位置.给安装包文件赋予可执行权限.执行安装.设置环境变量--等等一系列复杂的操作.并且如果有关联也需要一个一个的挨着安装.耗 ...

  3. 通过Shell脚本来创建批量服务器上的MySQL数据库账号

    1.项目背景 因监控需要,我们需要在既有的每个MySQL实例上创建一个账号.公司有数百台 MySQL 实例,如果手动登入来创建账号很麻烦,也不现实.所以,我们写了一个简单的shell脚本,用来创建批量 ...

  4. 在远程服务器上执行本地的shell脚本

    在远程服务器上执行本地的shell脚本 [root@localhost zzx]# sh echoip.sh 192.168.67.131[root@localhost zzx]# ssh root@ ...

  5. shell脚本实现自动压缩一天前的日志文件 ,并传到ftp服务器上

    shell脚本实现自动压缩一天前的日志文件 ,并传到ftp服务器上 naonao_127关注2人评论19401人阅读2012-06-08 11:26:16         生产环境下脚本自动备份脚本是 ...

  6. 【Shell实战】批量在多台服务器上执行命令

    功能说明:批量在多台服务器上执行命令 #!/bin/bash # ========================================== # 功能:批量在多台服务器上执行命令 # 方法: ...

  7. jenkins 把包传到远程服务器上

    首先我们在 一台服务器上部署svn,maven,jdk,tomcat,nexus,还有Jenkins. 这里我主要记录Jenkins. 首先我们从网上下载Jenkins的包 wget http://m ...

  8. Web启动服务器上的某一个服务

    情景是这样的.. 网页打开一个数据列表..数据要求实时从其他多个平台上获取.. 所以就有了一个Web页面..还有个WinService的服务来定时获取这些数据... 问题来了.. 发现Service有 ...

  9. 如何在服务器上搭建git服务器

    参考文章: http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00137583770 ...

随机推荐

  1. Winform文本框只能输入限定的文本

    比如WInform中的文本框只能输入数字活着字母和退格键,e.kaychar(按下键盘的值)

  2. 压缩软件WinRar 5.5 x64去广告方式【窗口类名下断】

    工具及使用软件逆向逻辑原始软件使用效果:查看软件窗口类名查看WinRAR.exe信息x64dbg逆向破解软件(非附加调试)处理掉广告注册函数处理掉广告创建函数保存修改后的镜像破解效果 工具及使用软件 ...

  3. 关于项目里server清楚缓存的代码

    Venk proc存在很多问题,不能应对高并发的情况,所以提供了这个 方法来清理cache, 但是前提是需要有prod的权限: 要想验证是否通过URL清楚了缓存,就要 removeCache url执 ...

  4. 最大流当前弧优化Dinic分层模板

    最大流模板: 普通最大流 无向图限制:将无向图的边拆成2条方向相反的有向边 顶点有流量限制:拆成2个点,连接一条容量为点容量限制的边 无源汇点有最小流限制的最大流:理解为水管流量形成循环 有源汇点的最 ...

  5. JS require and import

    作者:寸志链接:https://www.zhihu.com/question/56820346/answer/150724784来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  6. composer 镜像地址

    composer config -g repo.packagist composer https://packagist.composer-proxy.orgcomposer config -g re ...

  7. laravel-debugbar安装

    第一步:找到debugbar扩展包 扩展包的链接:https://packagist.org/packages/barryvdh/laravel-debugbar 第二步:安装 我测试的环境larav ...

  8. oo第四次博客总结

    1.论述测试与正确性论证的效果差异,比较其优缺点 测试:通过大量测试样例覆盖测试代码,来检测代码功能的实现是否正确是否完善.测试一个程序的正常输入比较容易,但难点就在于大量的非法输入,测试只能发现bu ...

  9. thymelead入门 git地址在文档最后

    流程:##### 流程###### 1:pom添加依赖 <dependency> <groupId>org.springframework.boot</groupId&g ...

  10. Naïve Media Player

    我的GitHub链接:https://github.com/Joyce45/hwt 一.播放器?怎么做? 提到播放器,首先想到的就是XAML控件库里的MediaElement,于是我又大致阅读了一下该 ...