スクリプトから起動された ssh プロセスがハングする

スクリプトから起動された ssh プロセスがハングする

スクリプトを使用していくつかの VM を作成しています。その一環として、SSH を使用して VM の名前を変更しています。何らかの理由で、以下のコマンドを 3 つの VM に対して実行すると動作しますが、7 つの VM を作成するときのマジック ナンバーに対しては、SSH がハングします。この動作について説明してもらえますか?

スクリプトの一部。このスクリプトは指定された X 台の仮想マシンに対して同時に実行されます。

...
ssh-keygen -f ~/.ssh/known_hosts -R $IP
ssh-keyscan $IP >> ~/.ssh/known_hosts
SSH="ssh -i $SSH_KEY -o PasswordAuthentication=no"

echo "hostname $hostname && 
    echo HOSTNAME=$hostname >> /etc/sysconfig/network && 
    echo 127.0.0.1 $hostname >> /etc/hosts " | ssh -i $SSH_KEY -o PasswordAuthentication=no root@IP
...

終了しない ssh プロセス

rag       2867  2808  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm4
rag       2869  2812  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm7
rag       2872  2818  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm1
rag       2875  2811  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm6
rag       2879  2814  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm5
rag       2881  2813  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm3
rag       2884  2807  0 01:05 pts/5  T  00:00:00 ssh -i ssh_key -o PasswordAuthentication=no root@vm2

実行中のプロセスの 1 つで strace を取得しました。

...
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
rt_sigreturn(0x16)                      = -1 EINTR (Interrupted system call)
rt_sigaction(SIGALRM, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTSTP, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
rt_sigaction(SIGTTOU, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, NULL, 8) = 0
close(4)                                = 0
kill(2867, SIGTTOU)                     = 0
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
open("/dev/tty", O_RDWR)                = 4
rt_sigaction(SIGALRM, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGHUP, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGINT, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGPIPE, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_IGN, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGQUIT, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTERM, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTSTP, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTTIN, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
rt_sigaction(SIGTTOU, {0x7fd26e1ef540, [], SA_RESTORER, 0x7fd26cd9d4a0}, {SIG_DFL, [], SA_RESTORER, 0x7fd26cd9d4a0}, 8) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, SNDCTL_TMR_CONTINUE or TCSETSF, {B38400 opost isig icanon echo ...}) = ? ERESTARTSYS (To be restarted)
...

答え1

これは競合状態のように思えますが、あなたのスクリプトを見ると、どこが競合状態なのかがわかると思います。

私の理解では、次の 2 行 (など) を含むスクリプトがあります。

ssh-keygen -f ~/.ssh/known_hosts -R $IP
ssh-keyscan $IP >> ~/.ssh/known_hosts

そして、そのスクリプトを複数回起動します。

次の一連のイベントにより、問題が説明できます。

  1. スクリプトの 1 つが開き、コマンド~/.ssh/known_hostsを実行しますssh-keygen -R。この時点で、ssh-keygenコマンドはファイル全体をメモリに読み込んで、対象の行を削除できるようになります。
  2. 別のスクリプトが実行を完了しssh-keyscan、行をファイルに書き出しました。
  3. 最初のスクリプトのssh-keygenプロセス (ステップ #1 のプロセス) はファイルの書き込みを開始しますが、ステップ #2 が完了する前にファイルを読み取ったため、書き出すファイルにはステップ #2 で追加された行が含まれません。そのため、ステップ #2 の行は消去されます。
  4. 2 番目のスクリプトは を実行しますが、手順 3 で説明した問題のため、 sshホスト キーが存在しません。そのため、ssh はハングし、ユーザーにキーの確認を求めます。known_hosts

詳細:
バックグラウンド プログラムは端末から読み取ることができません。読み取ろうとすると、そのプログラムに SIGTTIN が送信されます。ただし、strace では、プログラムが SIGTTOU を取得していることが示されています。通常、バックグラウンド プログラムは問題なく端末に書き込むことができますが、OpenSSH は明示的に と呼ばれる端末設定をオンにするtostopため、この動作が発生します。さらに、OpenSSH には SIGTTOU のシグナル ハンドラー (など) があり、その結果、プロセスをフォアグラウンドにするまで OpenSSH コードが無限ループに陥ります (その時点でプロンプトが表示され、シグナルが送信されなくなります)。

これをどう解決するかは別の問題です。

  • 1 つの解決策としては、ロックを追加し (flock使用できるユーティリティがあります)、known_hostsその 2 行の前にファイルをロックし、完了後にロックを解除することです。
  • 別の解決策としては、 ssh オプションを追加することですStrictHostKeyChecking=no。スクリプトのこの 2 行ですでにファイルの目的が達成されていないknown_hostsので、完全に無効にしてしまったほうがよいでしょう。

関連情報