私はバックグラウンドで1000を超えるサーバーでコマンドを実行するスクリプトを作成しました。時々、スクリプトがサーバーの1つで中断されることがあります。スクリプトの実行中にサーバーが停止した場合(より高い負荷平均のため)、そのサーバーでもコマンドが停止する可能性があります。スクリプトが次のホストに移動して実行を続けるように、そのホストをスキップする方法はありますか?
私のスクリプトの2つの主な機能を強調しましたが、「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
。私は通常、このようなタスクを2つのスクリプトに分割します。
local.sh
通常、このスクリプトはホスト名という1つのパラメータを使用して、必要な検証、実行前の操作、ロギングなどを実行します。たとえば、
#!/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
コマンドごとに1つのパラメータのみを提供してください。-I {}
引数に置き換えられます{}
。ここでは必要ありませんが、より複雑なxargs呼び出しを設定するのに役立ちます。
これにより、ローカルスクリプトまたはリモートスクリプトのいずれかが中断されても、他の15個のスクリプトをブロック解除されたままにすることができます。