我正在通过脚本创建一些虚拟机。作为其中的一部分,我使用 ssh 更改虚拟机的名称。由于某种原因,当我对三个虚拟机运行以下命令时,它可以工作,而对于创建七个虚拟机时的幻数,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
我对正在运行的进程之一进行了跟踪。
...
--- 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
这听起来像是一个竞争条件,看看你的脚本,我想我明白了。
根据我的理解,您有一个脚本,其中包含以下两行(除其他外):
ssh-keygen -f ~/.ssh/known_hosts -R $IP
ssh-keyscan $IP >> ~/.ssh/known_hosts
然后您多次启动该脚本。
这一系列事件可以解释您的问题:
- 其中一个脚本将打开
~/.ssh/known_hosts
以执行ssh-keygen -R
命令。此时,该ssh-keygen
命令已将整个文件读入内存,以便可以删除目标行。 - 另一个脚本刚刚完成执行
ssh-keyscan
并将该行写入文件。 - 第一个脚本的
ssh-keygen
进程(步骤 #1 中的进程)开始写出文件,但由于它在步骤 #2 完成之前读取了文件,因此它写出的文件不包含步骤 #2 添加的行。因此,步骤 #2 中的行被擦除。 - 第二个脚本执行,只是由于步骤 #3 中提到的问题
ssh
而未输入主机密钥。known_hosts
因此 ssh 挂起,要求用户确认密钥。
更多详细信息:
后台程序无法从终端读取数据,尝试这样做会导致该程序收到 SIGTTIN。然而在你的 strace 中,它显示程序收到了 SIGTTOU。通常后台程序可以毫无问题地写入终端,但是 OpenSSH 显式打开一个名为 的终端设置,tostop
这会导致此行为。更进一步,OpenSSH 在 SIGTTOU(以及其他)上有一个信号处理程序,这会导致 OpenSSH 代码进入无限循环,直到您将进程置于前台(此时它可以显示提示,并停止收到信号)。
你想如何解决这个问题是另一回事。
- 一种解决方案是添加锁定(
flock
您可以使用一个实用程序)并在这两行之前锁定known_hosts
文件,然后在完成后解锁。 - 另一个解决方案是添加 ssh 选项
StrictHostKeyChecking=no
。您已经用脚本的这两行破坏了文件的用途known_hosts
,因此您不妨将其全部禁用。