SSH::Batch,在公有云中使用 ssh 工具箱

Stobbymayob 9年前發布 | 15K 次閱讀 SSH Linux命令 Nginx Linux

來自: https://yq.aliyun.com/articles/4244

就像之前的博文中講的那樣,我買了兩臺阿里云的 ECS,一臺在香港,一臺在新加坡。由于總所周知的網絡原因,從大陸 ping 這兩臺服務器的 RTT 一直都在兩三百毫秒,之前只有一臺位于香港的 ECS 的時候,我 ssh 上去部署一些服務,碰上網絡抖動的時候都能卡出翔,敲擊一個按鍵之后許久才出現在屏幕上。(之前寫這篇博文的時候網絡狀況確實如此,現在網絡狀況已經好了很多很多,親測杭州 ping 香港和新加坡的 ECS RTT 在 100ms 以內)

如今我有了兩臺服務器,如果還像之前那樣直接用 ssh 去維護的話,簡直就是不敢想象的事情。且不說一樣的配置文件我要修改兩遍,僅僅想象一下剛剛在 A 機器卡成翔的情況下完成維護,又要去 B 機器上再次被卡成翔,就會讓我懷疑人生。不要問為什么卡成翔了還不用 mosh ,我也不知道

其實說起來,雖然過去一年多,我做的是服務端開發,但是也涉足一些簡單的運維工作。應用服務器從我剛入職時候的幾臺擴容到幾十臺到現在的一百多臺,一次又一次的自主發布,偶爾的手動批量重啟、下線服務器,捕獲線程快照、內存快照、大批量處理應用日志,經歷過虛擬機宕機、物理機宕機,不勝枚舉……當 AppOps 的日子,其實就是不那么規范的 DevOps 的日子。

在工作中,當我需要批量地在集群中執行命令時,我會使用一個叫 pgm 的內部腳本。這個腳本是 Python 寫的,基于 pssh ,用起來很不錯,能夠并發地在集群中執行命令。這個命令應該是我到目前為止會用的唯一一個內部腳本,其他的像開源的 tsar 反而不會用。

離開了公司的環境,我就沒有 pgm 用了。昨天我嘗試尋找一個能夠在集群中批量執行 ssh 命令的工具,這樣我能夠比較輕松地管理我的 ECS 們。那時候我還不知道 pgm 是基于 pssh 實現的。隨便 Google 了一下 「ssh batch」,就找到一個 Github repo, agentzh/sshbatch

進去看了一下 README,這是一個用 Perl 實現的工具箱,4 個命令分別實現如下功能:

  1. fornodes 計算機器列表
  2. atnodes 在指定機器集上執行命令
  3. tonodes 把文件或目錄上傳到指定機器集
  4. key2nodes 把公鑰上傳到指定機器集

看起來很厲害的樣子,不過 agentzh 是誰?點開主頁一看,我當時就跪了,有眼不識泰山,這不是傳說中的春哥「章亦春」么!幾個月前孤陋寡聞的我是不知道春哥的存在的,直到我出差去北京參加 Velocity,在大會上見識了王院生對的 OpenResty 的簡介1,當時就驚為天人。后來通過各種渠道加深了對 Nginx 和 OpenResty 的學習和了解,更是對春哥頂禮膜拜。

sshbatch 的文檔寫的很詳細,從安裝到使用面面俱到,因此我這里就不再贅述,雖然文檔用英文寫的。

這里主要介紹一下 sshbatch 中讓我感覺驚艷的地方。

首先是機器列表的管理方式。之前用 pgm 的時候,一個應用分組的機器放在一個文件里面,在執行批處理的時候指定存放機器列表的文件。fornodes 則是把機器列表看做是一個個的集合,集合與集合之間可以做交并補等運算,通過集合運算得到不同的機器列表。這靈活性簡直不能更贊。

其次是批量推送文件的 tonodes。之前用 pgm 只能批量執行命令,我在內網一直沒有找到科學的批量向服務器推送文件的腳本。tonodes 很好地滿足了我的需求。

于是我用 tonodes 和 atnodes 把我兩臺 ECS 上的 Nginx 配置文件重新維護了一遍,之前是直接登錄服務器修改的,如今變成本地使用一個 git repo 去維護這些配置文件,修改完成后批量推送并重啟 Nginx。

事情并沒有想象中的一帆風順。

由于服務器位于公有云,出于安全考慮,我禁止了 root 登錄,禁止了密碼登錄,只允許公鑰登錄。于是我沒法直接把 nginx.conf 放到 /etc/nginx/ 中。因為我懶,不想在啟動 nginx 的時候指定配置文件,于是只好把 nginx.conf 放到 /tmp/,然后再把它移動到 /etc/nginx/ 并重啟。

tonodes ./nginx/nginx.conf '{ecs}:/tmp/'
atnodes 'sudo mv /tmp/nginx.conf /etc/nginx/ && sudo nginx -t && sudo service nginx restart' '{ecs}' -w

根據文檔中的描述,atnodes 加了 -w 參數,會要求用戶輸入密碼,作為登錄密碼和 sudo 密碼。抱著試一試的心態執行了一下,果然跪了。

  sshbatch git:(master)  atnodes 'sudo mv /tmp/nginx.conf /etc/nginx/ && sudo nginx -t && sudo service nginx restart' '{ecs}' -w
Password:
Permission denied (publickey).
===================== server ip =====================
ERROR: unable to establish master SSH connection: bad password or master process exited unexpectedly

唉,我都把密碼登錄禁用了,這里還強行要密碼登錄,不跪才怪了。從文檔中發現似乎把 -w 替換為 -tty 也可以實現遠程執行 sudo 命令,趕緊試試。結果發現,用了 tty 倒是能輸入密碼執行 sudo 了,但是,每臺機器都得輸入一次密碼,這是什么鬼!

目前我只有兩臺機器,輸密碼就忍了,假如哪天我有 10 臺機器了,光輸密碼就得累死。

其實這個問題在企業環境甚至私有云環境應該都不是問題。哪個運維會閑著蛋疼把服務器禁止密碼登錄啊!反正機器都在局域網,IP 不暴露在公網就是相對安全的,只要守護好邊界出口就好。所以說在內網批量執行 sudo 命令的時候,直接用 -w 參數就好了。

問題來了,就要解決問題。最直接暴力的方案是,把我的賬號設置為 sudo 免密碼模式,很黃很暴力,我并不喜歡。第二種方法,就是修改 atnodes,支持 -w 參數輸入的密碼僅作為 sudo 密碼,不作為登錄密碼。

于是我 fork 了代碼,拉到本地做了些修改。雖然是完全沒用過的 Perl,但還是分分鐘就改好了~通過增加參數 -W 來表達「passowrd for sudo only」的含義。

隨便執行一個 sudo 命令看看效果。

  sshbatch git:(master)  atnodes 'sudo ls' '{ecs}' -W
Password:
===================== server ip =====================
sudo: no tty present and no askpass program specified
Remote command returns status code 1.

居然,出錯了……根據報錯信息,給之前的命令追加一個 -tty 參數,于是我終于能在服務器上使用 sudo 了!不幸的是,開啟 tty 之后,批處理就沒法并發執行了,只能按順序一個一個來。不過想想也是,開啟 tty 之后一般是要做一些交互操作的,而標準輸入流就只有一個,所以只好一個一個來了。

  sshbatch git:(master)  atnodes 'sudo ls /etc/nginx/sites-enabled/' '{ecs}' -W -tty -q
Password:
===================== server ip =====================
[sudo] password for admin:
blog.jamespan.me  blog.xuminzheng.com  default  hatta  wekan

===================== server ip ===================== [sudo] password for admin: blog.jamespan.me default</code></pre>

然后我又嘗試了一下 pssh,似乎它沒法很好地應對類似于我的機器這種禁止密碼登陸之后還要執行 sudo 命令的場景。

最后的最后,今天我發現了一個叫 Ansible 的運維工具,感覺有點強大,而且對系統毫無入侵,正在看文檔學習中。

</code></code></code></code></div>

 本文由用戶 Stobbymayob 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!