
我編寫了一個腳本,可以在後台運行 1000 多個伺服器上的命令。有時腳本會掛在其中一台伺服器上。如果/當伺服器在執行腳本時掛起(由於平均負載較高),則該命令也可能在該伺服器上掛起。有沒有辦法跳過該主機,以便腳本可以轉到下一個主機並繼續運行?
我強調了腳本的兩個主要功能,但沒有給出“ConnectTimeout”和等待關鍵字。
exec_ssh()
{
for i in `cat $file`
do
ssh -q -o "StrictHostKeyChecking no" -o "NumberOfPasswordPrompts 0" -o ConnectTimeout=2 $i $command 2>>/dev/null &
if wait $!; then
echo "" >> /dev/null
else
echo "$i is not reachable over SSH or passwordless authentication is not setup on the server" >> /tmp/not_reachable
fi
done >/tmp/output.csv &
run_command()
{
export -f exec_ssh
export command
nohup bash -c exec_ssh &>>$log_file &
}
答案1
您編寫的腳本會保持同時運行所有遠端命令,但對於您的使用,wait
將明確等待後台任務完成。在您描述的高負載伺服器的情況下,這表示您的ssh
命令沒有逾時,而只是需要很長時間才能完成,因此腳本完全按照您的要求執行。 ConnectTimeout
當您能夠成功建立ssh
連結時就沒有意義了。
如果您確實想使用此類腳本而不是專為分散式遠端執行而設計的工具,例如安西布爾,我可能會修改你的腳本如下:
exec_ssh() {
while read file; do
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$i" "$command" 2>>/dev/null & then
echo "$i is not reachable via non-interactive SSH or remote command threw error - exit code $?" >> /tmp/not_reachable
fi
done < "$file" > /tmp/output.csv &
}
run_command() {
export -f exec_ssh
export command
nohup bash -c exec_ssh &>> "$log_file" &
}
也可能值得考慮將「我可以透過 SSH 連接到主機」測試和「我可以完成工作嗎」測試分開:
if ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" true; then
# connection succeeded
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" "$command" & then
echo "Remote command threw $?"
fi
else
echo "SSH threw $?"
fi
答案2
隨著您的本地和遠端命令變得越來越複雜,您很快就會因為試圖將所有這些都塞進一個連貫的腳本而不知所措,並且由於有數百或數千個後台進程,即使有強大的後台進程,您也可能會遇到資源爭用問題。
您可以使用 來控制這一點xargs -P
。我通常將這樣的任務分成兩個腳本。
本地.sh
一般來說,這個腳本有一個參數,就是主機名,並執行任何必要的驗證、飛行前任務、日誌記錄等。
#!/bin/bash
hostname=$1
# simple
cat remote.sh | ssh user@$hostname
# sudo the whole thing
cat remote.sh | ssh user@$hostname sudo
# log to files
cat remote.sh | ssh user@$hostname &> logs/$hostname.log
# or log to stdout with the hostname prefixed
cat remote.sh | ssh user@$hostname 2>&1 | sed "s/^/$hostname:/"
遠端.sh
您想要遠端運行的腳本,但現在您不必將其塞入引用的單行程式碼中並處理引用逃脫的地獄。
實際命令
cat host_list.txt | xargs -P 16 -n 1 -I {} bash local.sh {}
在哪裡:
-P 16
將分叉最多 16 個子進程-n 1
每個指令只提供一個參數-I {}
將用參數代替{}
[ 此處不必要,但對於建構更複雜的 xargs 呼叫可能有用。
這樣,即使您的本地或遠端腳本之一掛起,您仍然可以讓其他 15 個腳本暢通無阻。