web-dev-qa-db-ja.com

SSHセッション内のSSH中の複数のコマンド

リモート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)その後、セッションを終了して続行します。私に何ができる?

10
mgus

&&は論理演算子です。 ではないは、「このコマンドも実行する」という意味であり、「他のコマンドが成功した場合にこのコマンドを実行する」という意味です。

つまり、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に渡される文字列です。ローカルマシンを確認してください。これを実行していたディレクトリInputOutputPartitionがあるかもしれません。

15
Centimane

ジャンプボックスでいつでも定義できます 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
10
Rui F Ribeiro

すべてのコマンドを「マスター」サーバー上の別のスクリプトに入れることができます。

マスタースクリプト

#!/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
4
jesse_b

少し前に、私は他の回答が推奨するようにコントロールソケットを使用する機会がありました(この回答は基本的に this answer のようなコントロールソケットの使用と this answer のようなスクリプトの組み合わせです) 。

ユースケースはハックでした。ターゲットユーザーのauthorized_keysは、スケジュールされたタスクによって定期的に上書きされ、そのファイルに何かを追加するために必要な赤テープを経由せずにすばやくテストしたいと考えました。そのため、必要に応じてそのファイルにキーを追加するwhileループをセットアップし、テストを実行してループをキャンセルします。ただし、スケジュールされたタスクがファイルを上書きする小さなウィンドウがあり、私のループはsleepingのままです。したがって、最初に制御ソケットを設定すると、後で問題なくスクリプトを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オプションを使用して必要な場所でのみ制御ソケットを使用できるようになります。
  • セットアップスクリプトは、テスト実行スクリプトもサーバーにコピーします。実行スクリプト自体にはたくさんのコマンドが含まれています。実行スクリプトをコピーしたので、SSHのクォートの追加レイヤー(および何が拡張されるかを理解するための追加の認識オーバーヘッド)を心配する必要はありません。
  • 次に、メインスクリプトはxargsを使用して、実行中のジョブが終了するとすぐに新しいジョブを開始することにより、サーバーにワークロードを分散します。
1
muru