リモートmaster
マシンへのSSHセッション、次にmaster
からリモートslaves
のそれぞれへの別の内部SSHセッションを行うことになっているローカルマシンがあります。次に、2つのコマンドを実行して、特定のディレクトリを削除して再作成します。
ローカルマシンにはマスターへのパスワードなしのSSHがあり、マスターにはスレーブへのパスワードなしのSSHがあることに注意してください。また、すべてのホスト名は.ssh/config
ローカル/マスターマシンとスレーブのホスト名はslaves.txt
ローカルで、そこから読みました。
だから私がやっていることはこれです:
username="ubuntu"
masterHostname="myMaster"
while read line
do
#Remove previous folders and create new ones.
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition""
ssh -n $username@$masterHostname "ssh -t -t $username@$line "mkdir -p EC2_WORKSPACE/$project Input Output Partition""
#Update changed files...
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""
done < slaves.txt
このクラスターはAmazon EC2上にあり、反復ごとに6つのSSHセッションが作成され、大幅な遅延が発生していることに気付きました。これらの3つのコマンドを1つにまとめて、SSH接続を減らしたいと思います。だから私は最初の2つのコマンドを組み合わせてみました
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""
しかし、期待どおりに動作しません。最初のものを実行しているようです(rm -rf Input Output Partition
)その後、セッションを終了して続行します。私に何ができる?
&&
は論理演算子です。 ではないは、「このコマンドも実行する」という意味であり、「他のコマンドが成功した場合にこのコマンドを実行する」という意味です。
つまり、rm
コマンドが失敗した場合(3つのディレクトリのいずれかが存在しない場合に発生します)、mkdir
は実行されません。これは、希望する動作のようには聞こえません。ディレクトリが存在しない場合は、作成してもかまいません。
- 使用する ;
セミコロン;
は、コマンドを区切るために使用されます。コマンドは順次実行され、次のコマンドに進む前に待機しますが、コマンドの成功または失敗は互いに影響を及ぼしません。
内側の引用符をエスケープする
他の引用符内の引用符はエスケープする必要があります。そうしないと、追加の終点と始点が作成されます。あなたのコマンド:
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""
になる:
ssh -n $username@$masterHostname "ssh -t -t $username@$line \"rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input OutputPartition\""
エスケープされた引用符がないため、現在のコマンドは実行されているはずです。
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition
それが成功した場合:
mkdir -p EC2_WORKSPACE/$project Input Output Partition"" # runs on your local machine
ここでは、構文の強調表示によってコマンド全体が赤で表示されています。つまり、コマンド全体がsshに渡される文字列です。ローカルマシンを確認してください。これを実行していたディレクトリInput
Output
とPartition
があるかもしれません。
ジャンプボックスでいつでも定義できます OpenSSHでの多重化
多重化は、単一の回線または接続を介して複数の信号を送信する機能です。多重化により、OpenSSHは既存のTCP接続を複数の同時SSHセッションに再利用でき、毎回新しいものを作成するのではありません。
SSH多重化の利点は、新しいTCP接続を作成することによるオーバーヘッドが排除されることです。マシンが受け入れる可能性のある接続の総数は有限のリソースであり、一部のマシンでは制限がより顕著です。負荷と使用状況の両方によって大きく異なります。また、新しい接続を開くときに大幅な遅延があります。新しい接続を繰り返し開くアクティビティは、多重化を使用すると大幅に高速化できます。
そのためには/etc/ssh/ssh_config
:
ControlMaster auto
ControlPath ~/.ssh/controlmasters/ssh_mux_%h_%p_%r
ControlPersist 30m
このようにして、次の30分間に同じサーバーに対して連続して行われる接続は、前のssh接続を再利用して行われます。
マシンまたはマシンのグループに定義することもできます。提供されたリンクから取得。
Host machine1
HostName machine1.example.org
ControlPath ~/.ssh/controlmasters/%r@%h:%p
ControlMaster auto
ControlPersist 10m
すべてのコマンドを「マスター」サーバー上の別のスクリプトに入れることができます。
マスタースクリプト
#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"
次に、sshスクリプトで次のように呼び出します。SSH Script
username="ubuntu"
masterHostname="myMaster"
while read line
do
ssh -n $username@$masterHostname "ssh -t -t $username@$line < /path/to/masterscript.sh"
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""
done < slaves.txt
[〜#〜] or [〜#〜]すべてのファイルが最初のマシン上になければならない場合、次のようなことができます:
script1
script2="/path/to/script2"
username="ubuntu"
while read line; do
cat $script2 | ssh -t -t $username@line
done < slaves.txt
script2
#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"
rsync --delete -avzh "/EC2_NFS/$project/* EC2_WORKSPACE/$project"
sshスクリプト
script1="/path/to/script1"
username="ubuntu"
masterHostname="myMaster"
cat $script1 | ssh -n $username@$masterHostname
少し前に、私は他の回答が推奨するようにコントロールソケットを使用する機会がありました(この回答は基本的に this answer のようなコントロールソケットの使用と this answer のようなスクリプトの組み合わせです) 。
ユースケースはハックでした。ターゲットユーザーのauthorized_keys
は、スケジュールされたタスクによって定期的に上書きされ、そのファイルに何かを追加するために必要な赤テープを経由せずにすばやくテストしたいと考えました。そのため、必要に応じてそのファイルにキーを追加するwhileループをセットアップし、テストを実行してループをキャンセルします。ただし、スケジュールされたタスクがファイルを上書きする小さなウィンドウがあり、私のループはsleep
ingのままです。したがって、最初に制御ソケットを設定すると、後で問題なくスクリプトをSSHで実行できるようになります。
#! /bin/bash -xe
. "${CONFIG_DIR}/scripts/setup-ssh.sh"
# Build and test
export TEST_LABEL="${_started_by}-${BUILD_TAG%-BUILD*}"
#...
xargs --arg-file test-list \
--no-run-if-empty \
--process-slot-var=NUM \
--max-procs=${#SERVERS[@]} \
--max-args="${BATCH_SIZE:-20}" \
"${CONFIG_DIR}/scripts/run-test.sh"
setup-ssh.sh
は次のとおりです。
export SSH_CONFIG="${CONFIG_DIR}/scripts/.ssh-config"
mapfile -t SERVERS < "${CONFIG_DIR}/scripts/hosts"
for SERVER in "${SERVERS[@]}"
do
while ! ssh -F "${SSH_CONFIG}" "${SERVER}" -fnN; do sleep 1; done
scp -F "${SSH_CONFIG}" "${CONFIG_DIR}/scripts/ssh-script.sh" "${SERVER}":"${TEST_LABEL}.sh"
done
そして.ssh-config
:
Host test-*
User test
StrictHostKeyChecking no
ControlMaster auto
ControlPath /tmp/ssh-%h-%p-%r
そしてrun-test.sh
:
mapfile -t TEST_SERVERS < "${CONFIG_DIR}/scripts/hosts"
ssh -F "${SSH_CONFIG}" "${TEST_SERVERS[$NUM]}" "./${TEST_LABEL}.sh"
シーケンスは次のようになります。
setup-ssh.sh
をソースとします。setup-ssh.sh
サーバーすべてに制御ソケットが設定されるまでサーバーをビジーループします。 hosts
ファイルは、サーバーのホスト名を1行に1つずつリストするだけです。${CONFIG_DIR}/scripts/.ssh-config
にのみあるため、-F
を使用してそのファイルを指定しない限り、SSH接続はそれを使用しません。したがって、これにより、F
オプションを使用して必要な場所でのみ制御ソケットを使用できるようになります。xargs
を使用して、実行中のジョブが終了するとすぐに新しいジョブを開始することにより、サーバーにワークロードを分散します。