解决 ssh 不转发信号的问题
Work around ssh does not forward signal
如何解决 ssh
不转发 SIGTERM
信号的问题?
我希望print-signal.py
终止ssh root@localhost
进程终止:
ssh root@localhost /root/print-signal.py
不幸的是,只有 ssh 进程本身得到信号,而不是远程命令 (print-signal.py
)。远程命令不终止:-(
由于 openssh 不会将 SIGTERM
转发到远程命令,我正在寻找解决方法。
如果 ssh root@localhost
... 终止,如何终止 print-signal.py
?
这是以下问题的后续问题:Forwarding SIGTERM over ssh
您可以编写一个包装器,如果父进程是 init 进程则终止:
ssh root@localhost terminate-command-if-parent-is-lost print-signal.py
工具 terminate-command-if-parent-is-lost
需要执行此操作:
将 argv 作为子进程启动(在本例中 print-signal.py
)。然后它每秒检查其父 pid 的状态(在 Python os.getppid()
)。
如果 ppid 为 1(init 进程),则 print-signal.py 进程已失去其父进程。这意味着 "ssh root@localhost ..." 已终止(或连接已关闭)。
现在 terminate-command-if-parent-is-lost
终止子进程。
免责声明:下面的答案不是针对 SIGTERM,而是针对 SIGINT。由于疏忽,这不是问题的答案。
您观察到的问题是由于缺少 tty 造成的,它应该控制您尝试 运行 的进程。如果没有可用的 tty,则 ssh 无法将信号发送到进程。当您对 ssh
命令使用选项 -t
时,它将强制分配伪终端,这使得通过 ssh 发送信号成为可能:
ssh -t root@localhost /root/print-signal.py
man ssh
-t
Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t
options force tty allocation, even if ssh has no local tty.
很好地解释了如何以及为什么
在这里你可以看到它是如何工作的:
[terminal 1]% ssh server ./print_signal.py
在另一个终端上,您会看到 print_signal.py
在 ssh
下 PID=26992
上 运行ning PID=26991
没有 tty(username@notty
)
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 26991 26989 0 17:06 ? 00:00:00 sshd: username@notty
username 26992 26991 0 17:06 ? 00:00:00 python ./print_signal.py
username 27347 27345 0 17:07 ? 00:00:00 sshd: username@notty
username 27348 27347 0 17:07 ? 00:00:00 ps -f
使用 kill 或 CTRL-C 终止 ssh 进程后,该进程仍然处于活动状态,但现在 运行s在 /sbin/init
(PPID=1
)
下
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 26992 1 0 17:06 ? 00:00:00 python ./print_signal.py
username 27453 27451 0 17:08 ? 00:00:00 sshd: username@notty
username 27454 27453 5 17:08 ? 00:00:00 ps -f
使用 -t
标志可以很好地终止另一端的进程:
[terminal 1]% ssh -t server ./print_signal.py
在另一个终端上,您会看到 print_signal.py
在 ssh
下的 PID=39277
上 运行ning,PID=39276
绑定到 tty(username@pts/10
)
[terminal 2]% ssh server ps -U username -f
UID PID PPID C STIME TTY TIME CMD
username 39276 39274 0 17:22 ? 00:00:00 sshd: username@pts/10
username 39277 39276 1 17:22 pts/10 00:00:00 python ./print_signal.py
username 39317 39314 0 17:22 ? 00:00:00 sshd: username@notty
username 39318 39317 5 17:22 ? 00:00:00 ps -U username -f
杀掉ssh进程后
[terminal 1]% ssh -t server ./print_signal.py
My PID: 39277
^CCaught signal SIGINT (2), exiting.
Connection to server closed
该进程现在已在另一台服务器上明确终止
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 39768 39765 0 17:26 ? 00:00:00 sshd: username@notty
username 39769 39768 6 17:26 ? 00:00:00 ps -U username -f
如果 shell 支持一些内置变量( $! ),它可以轻松帮助您解决此类问题。
这是一个基本的 shell 解决方案,将您的命令替换为长时间睡眠。
ssh server '(sleep 100000 & (MID=$!; A=n; while [ "$A" != y ];do echo "i am process $$ want kill "$MID" y/n?"; read A; done; kill -TERM $MID))'
命令中发送的脚本是远程主机上的运行。
我刚刚遇到了这个问题。虽然我还没有弄清楚确切的原因,但当 ssh
终止时发生的事情是您的进程被重新设置为 init
。您可以告诉您的进程在父进程死亡时请求信号,而不是使用 prctl.
如果您使用 python-prctl,请将以下内容提前放在 /root/print-signal.py
import signal
import prctl
prctl.set_pdeathsig(signal.SIGTERM)
如何解决 ssh
不转发 SIGTERM
信号的问题?
我希望print-signal.py
终止ssh root@localhost
进程终止:
ssh root@localhost /root/print-signal.py
不幸的是,只有 ssh 进程本身得到信号,而不是远程命令 (print-signal.py
)。远程命令不终止:-(
由于 openssh 不会将 SIGTERM
转发到远程命令,我正在寻找解决方法。
如果 ssh root@localhost
... 终止,如何终止 print-signal.py
?
这是以下问题的后续问题:Forwarding SIGTERM over ssh
您可以编写一个包装器,如果父进程是 init 进程则终止:
ssh root@localhost terminate-command-if-parent-is-lost print-signal.py
工具 terminate-command-if-parent-is-lost
需要执行此操作:
将 argv 作为子进程启动(在本例中 print-signal.py
)。然后它每秒检查其父 pid 的状态(在 Python os.getppid()
)。
如果 ppid 为 1(init 进程),则 print-signal.py 进程已失去其父进程。这意味着 "ssh root@localhost ..." 已终止(或连接已关闭)。
现在 terminate-command-if-parent-is-lost
终止子进程。
免责声明:下面的答案不是针对 SIGTERM,而是针对 SIGINT。由于疏忽,这不是问题的答案。
您观察到的问题是由于缺少 tty 造成的,它应该控制您尝试 运行 的进程。如果没有可用的 tty,则 ssh 无法将信号发送到进程。当您对 ssh
命令使用选项 -t
时,它将强制分配伪终端,这使得通过 ssh 发送信号成为可能:
ssh -t root@localhost /root/print-signal.py
很好地解释了如何以及为什么
man ssh
-t
Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple-t
options force tty allocation, even if ssh has no local tty.
在这里你可以看到它是如何工作的:
[terminal 1]% ssh server ./print_signal.py
在另一个终端上,您会看到 print_signal.py
在 ssh
下 PID=26992
上 运行ning PID=26991
没有 tty(username@notty
)
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 26991 26989 0 17:06 ? 00:00:00 sshd: username@notty
username 26992 26991 0 17:06 ? 00:00:00 python ./print_signal.py
username 27347 27345 0 17:07 ? 00:00:00 sshd: username@notty
username 27348 27347 0 17:07 ? 00:00:00 ps -f
使用 kill 或 CTRL-C 终止 ssh 进程后,该进程仍然处于活动状态,但现在 运行s在 /sbin/init
(PPID=1
)
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 26992 1 0 17:06 ? 00:00:00 python ./print_signal.py
username 27453 27451 0 17:08 ? 00:00:00 sshd: username@notty
username 27454 27453 5 17:08 ? 00:00:00 ps -f
使用 -t
标志可以很好地终止另一端的进程:
[terminal 1]% ssh -t server ./print_signal.py
在另一个终端上,您会看到 print_signal.py
在 ssh
下的 PID=39277
上 运行ning,PID=39276
绑定到 tty(username@pts/10
)
[terminal 2]% ssh server ps -U username -f
UID PID PPID C STIME TTY TIME CMD
username 39276 39274 0 17:22 ? 00:00:00 sshd: username@pts/10
username 39277 39276 1 17:22 pts/10 00:00:00 python ./print_signal.py
username 39317 39314 0 17:22 ? 00:00:00 sshd: username@notty
username 39318 39317 5 17:22 ? 00:00:00 ps -U username -f
杀掉ssh进程后
[terminal 1]% ssh -t server ./print_signal.py
My PID: 39277
^CCaught signal SIGINT (2), exiting.
Connection to server closed
该进程现在已在另一台服务器上明确终止
[terminal 2]% ssh server ps -f
UID PID PPID C STIME TTY TIME CMD
username 39768 39765 0 17:26 ? 00:00:00 sshd: username@notty
username 39769 39768 6 17:26 ? 00:00:00 ps -U username -f
如果 shell 支持一些内置变量( $! ),它可以轻松帮助您解决此类问题。 这是一个基本的 shell 解决方案,将您的命令替换为长时间睡眠。
ssh server '(sleep 100000 & (MID=$!; A=n; while [ "$A" != y ];do echo "i am process $$ want kill "$MID" y/n?"; read A; done; kill -TERM $MID))'
命令中发送的脚本是远程主机上的运行。
我刚刚遇到了这个问题。虽然我还没有弄清楚确切的原因,但当 ssh
终止时发生的事情是您的进程被重新设置为 init
。您可以告诉您的进程在父进程死亡时请求信号,而不是使用 prctl.
如果您使用 python-prctl,请将以下内容提前放在 /root/print-signal.py
import signal
import prctl
prctl.set_pdeathsig(signal.SIGTERM)