1. 程式人生 > >ssh無密碼登入遠端主機執行特定命令的注意事項

ssh無密碼登入遠端主機執行特定命令的注意事項

最近的一個專案要結合使用rabbitmq、keepalived、supervisor。其中的一個場景為某個keepalived例項被提升為MASTER後需要到部署了rabbitmq client的遠端主機上kill掉這些client程序。

一般的思路為配置keepalived所在主機與部署了client的主機之間的無密碼ssh登入,然後通過ssh執行遠端命令,先獲取各client程序的程序號,然後逐個kill掉這些程序。

大體思路很簡單,但過程中卻碰到了不少問題。配置無密碼ssh至遠端主機的步驟比較簡單。在此不多說。配置好後可以直接在指令碼中使用:
ssh -p PORT IP "command"
或者
ssh -p PORT IP 'command'
來在遠端主機執行命令了。

先說說總設計問題。
剛開始是直線式的思維:先通過ssh遠端獲取client程序號,對於每個程序號分別ssh至遠端執行kill操作。因為有多臺keepalived例項分別運行於不同主機,這就需要在每個主機上維護一份需要處理的client列表,且需要多次通過ssh到遠端部署client的主機執行獲取程序號、殺程序的命名。這對於維護和效能來講都是比較噁心的。

換一種思維方式,既然查程序後和kill程序號的操作都是在遠端主機中完成的。為何不只在該遠端主機維護一份需處理的client列表且把獲取程序號和殺程序的這些操作封裝成一個指令碼放在該遠端主機?這樣其餘的各keepalived例項所在主機只需在ssh命名中呼叫一次遠端主機的指令碼便可。省去了很多不必要的步驟。

上邊是應用設計上的問題,可見在進行一個專案之前考慮清楚最優方案可為後續的實施減少多少的麻煩。遇到一個問題一定要從多個方面考慮。且儘量使用最簡單的方式而不是最高大上的最複雜的的方式。

再來說所碰到的一些細節問題。
ssh -p PORT IP "command"
或者
ssh -p PORT IP 'command'
的command中若包含變數的話,變數要用對應的引號引起來才能得以正確解析(實際上是shell中的字串拼接)。
如:
consumer=worker_for_summary.py

ssh -p PORT IP "ps -ef | grep "$consumer" |grep -v grep"

ssh -p PORT IP 'ps -ef | grep '$consumer' |grep -v grep'
使用如下命令時不行的
ssh -p PORT IP 'ps -ef | grep $consumer |grep -v grep'

另外在ssh中使用awk也需要注意,因為awk命令中使用單引號表明要執行的動作,所以相應的ssh中包圍command的引號要改成雙引號且awk中的“$”值為引數要加轉移符
如:
consumer=worker_for_summary.py

ssh -p PORT IP "ps -ef | grep "$consumer" |grep -v grep | awk '{print \$2}'"
使用其他任何方式是不行的。

最後說說在shell指令碼中使用ssh的注意
一般情況下執行ssh -p PORT IP "command" 預設是使用當前使用者到遠端主機執行命令的。
若將ssh -p PORT IP "command" 封裝進了指令碼,則會使用執行指令碼時使用的使用者登入至遠端主機執行命令。
我們的應用中將ssh -p PORT IP "command"封裝進了指令碼,該指令碼會在keepalived例項進入MASTER狀態後由keepalived呼叫,而keepalived是由root使用者啟動的所以實際上會以root使用者至遠端主機執行命令。而我們配置的無密碼ssh至遠端主機用的是非root使用者的工作(一般情況下是當前使用者的公鑰),因此遠端命令不能成功執行,提示需要密碼,即使是在ssh -p PORT IP "command"中加入使用者資訊變為ssh -p PORT
[email protected]
"command"也不行。因此通過生成root使用者的公鑰並配置無密碼ssh到遠端主機來規避了該問題。

在試密碼的時候,記錯了密碼導致賬戶被鎖定不能登入,可以通過faillog命令檢視失敗記錄並設定登入失敗限制。
如:
檢視使用者登入失敗情況
sudo faillog -u op1
重置使用者
sudo faillog -u op1 -r