我家里有一个跑着 Docker Swarm 的树莓派集群。为了方便维护,它们使用相同的配置——用户、Docker 版本等等。

有时候某些更新需要在集群的所有节点上执行同样的操作,比如创建一个新的 Docker macvlan 网络。

要做到这一点,要么就得在所有节点上手动执行相同的命令:挨个 ssh 进去,跑完命令,再换下一台。

既然我想着从长远来看少干点活、把一切弄得尽可能井井有条,我就开始研究怎么同时在所有节点上执行命令。

第一轮:自己写 Python 脚本

第一次尝试是自己写一个 Python 脚本。一方面是想顺便把 Python 学得更扎实一点,另一方面是我找不到一种更原生的方式来执行命令。

可想而知(嘿,我对这门语言还没多少经验 🙂),它很快就变成了一团臃肿的乱麻,而且特别容易出问题。

我得找个别的办法,不用再去重新理解三周前写的东西,也不用再琢磨上次到底是什么搞崩了。

第二轮:pssh

四处搜索的时候,我偶然发现了 [pssh](https://linux.die.net/man/1/pssh),它可以通过 SSH 并行执行任务。

总的来说,把它跑起来还挺容易的。

问题在于,有些操作需要通过 sudo 来执行。到处传递密码可不是什么好主意,所以我又得去找办法,弄清楚怎么在远程服务器要求输入密码时把 sudo 密码发过去。

结果发现,只要你碰巧看到对的 StackOverflow 评论,这事儿就简单得很。

太长不看版:

stty -echo; printf "Password: "; read PASS; stty echo; echo "${PASS}" | \
pssh -h <HOSTFILE> -o /tmp/output -t 0 -I "`cat ./commands.sh`"

-I "`cat ./commands.sh`" 必须写成这样(用引号和反引号包起来),否则命令无法正确执行。密码会作为单独的一条命令发送,而不会被当作 sudo 的输入。

另一个要注意的地方是,由于这样的设置方式,执行 sudo 时需要加上 -S 参数,才能正确读取密码输入。