当 docker 以 PID 1 运行时,为什么我不能在 docker 中 CTRL-C 睡眠无穷大

Ott*_*tto 5 bash sleep sigkill sigint docker

案例:我们有一个运行 bash 脚本的 docker 容器,该脚本需要永远“阻塞”(因为它为另一个容器公开了一个卷,但有时我们需要这样做还有其他原因)。

我当时认为这可以工作:

exec sleep infinity;
Run Code Online (Sandbox Code Playgroud)

ps aux 然后将“睡眠”作为 PID 1。太好了,我想,然后它将接收我们从容器外部发送的信号。例如:

docker kill -s INT container_name
Run Code Online (Sandbox Code Playgroud)

但这不起作用,容器继续运行(也适用于 SIGTERM)。正常的杀戮确实有效,但我不明白为什么会有区别(这让我很恼火):

docker kill container_name
Run Code Online (Sandbox Code Playgroud)

当它在我的容器中作为 PID 1 运行时,为什么我不能用 SIGINT/SIGTERM 杀死“睡眠”?我相信当它们在容器中作为 PID 1 运行时,我可以使用 SIGINT/SIGTERM 杀死其他东西(如 bash 脚本)。

Han*_*nnu 6

这有什么用吗? https://www.fpcomplete.com/blog/2016/10/docker-demons-pid1-orphans-zombies-signals

基本上问题是进程号 1。Linux/unix 内核不愿意以常规方式向该进程发出信号,因为它应该是 init。如果 init 进程终止,系统会立即发出恐慌并重新启动。如果您的进程 1 没有信号处理程序,则该信号就会被丢弃。Sleep 没有任何信号的处理程序,但您可以构建一个 bash 脚本。

基本上你需要做的是在你的 dockerfile 中使用 exec 形式,并将你的 sleep 无限分割成一个循环,因为当 shell 执行命令时 bash 陷阱不会被触发。这会向正在运行的进程 1 发送一个信号并捕获它:

Dockerfile:

FROM ubuntu
ADD foo.sh /tmp
RUN ["/tmp/foo.sh"]
Run Code Online (Sandbox Code Playgroud)

foo.sh:

#!/bin/bash

trap "echo signal;exit 0" SIGINT 

while :
do
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

这将对 docker Kill --signal=SIGINT 做出反应。