Bash脚本入口点(PID = 1)杀死`尾巴`subprocess只有当一个假陷阱(没有什么)在那里

我正在面对一个奇怪的行为,我的Bash脚本,我有这个Bash脚本运行与PID 1 (这是一个Docker容器的entrypoint ,如果你不熟悉Docker,我认为你可以忽略这个信息)。

当我运行下面的脚本时, SIGTERM很快终止一切,并且一切似乎都没有问题(请记住, sshd服务不存在!我的整个系统只启动这个只运行tail脚本,但直到现在它不是问题)。

 #!/bin/bash trap "pkill sshd" SIGTERM export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH if [ -f /usr/local/samba/etc/smb.conf ]; then exec /usr/local/samba/sbin/samba -i else tail -f /dev/null & wait ${!} fi 

当我删除该trap时,问题出现了。 现在我的系统挂起了,似乎因为tail仍在运行,并且由于某种原因而不会结束(如果您熟悉Docker,Docker会等待10秒钟,然后终止容器,因为它没有响应SIGTERM ,再次如果你不熟悉Docker,请忽略此信息)。

 #!/bin/bash export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH if [ -f /usr/local/samba/etc/smb.conf ]; then exec /usr/local/samba/sbin/samba -i else tail -f /dev/null & wait ${!} fi 

有人能向我解释究竟是什么问题? 为什么这个假的trap使一切工作(虽然它几乎没有什么,但它的作品,因为它只是在那里)。

我只是还想提一下,使用一个空的traptrap "" SIGTERM没有帮助,应该有什么工作陷阱(即使它什么都不做)。

希望有人能帮助我,谢谢!

实际上在运行容器时添加t参数(来分配tty)解决了这个问题。 我用-d参数运行它,现在用-td

我不知道为什么,但它做到了。 如果任何人都能解释为什么会这样,那将是非常棒的。

你还没有提供你的Dockerfile ,也不清楚你如何发送SIGTERM信号到容器。

但是,这是我想出来的,试图重现你的问题:

我的Dockerfile

 FROM ubuntu ADD ./entrypoint.sh /opt/entrypoint.sh # Using the exec form here, so that the process is assigned PID 1. ENTRYPOINT ["/opt/entrypoint.sh"] 

构build容器:

 $ docker build -f Dockerfile -t test_image . 

每次更改入口点脚本时都不要忘记重新构build容器。

使用以下命令运行容器:

 $ docker run --rm -it --name test_trap test_image 

现在,让我们看看每次运行中发生了什么。

1)用你的Bash脚本中的trap行:

 # The main process will receive SIGTERM, trap it and exit. $ docker stop test_trap # The main process will receive SIGTERM, trap it and exit. $ docker kill -s=TERM test_trap # The main process will receive SIGKILL and will be stopped immediately. $ docker kill -s=KILL test_trap 

2)没有trap线:

 # The main process will receive SIGTERM which will be ignored. # After a grace period (10s by default) it will receive SIGKILL and will be stopped. $ docker stop test_trap # The main process will receive SIGTERM which will be ignored. # Container will continue running. $ docker kill -s=TERM test_trap # The main process will receive SIGKILL and will be stopped immediately. $ docker kill -s=KILL test_trap 

原因是内核专门用PID 1来处理一个进程,而不会SIGTERM接收SIGTERM信号的进程(还有SIGINT )。

有关此问题的更多信息:

任何进程都可以注册自己的TERM处理程序,并在退出之前使用它们执行清理。 如果一个进程没有注册一个自定义信号处理程序,内核通常会回退到TERM信号的默认行为:终止进程。

对于PID 1,内核在转发TERM时不会回退到任何默认行为。 如果您的stream程没有注册自己的处理程序(大多数stream程没有),TERM将不会对stream程产生任何影响。

来源 – https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html

UPDATE

我还不能评论,所以我会在这里留言。 这是相同的PID 1问题。 对于-d-td ,信号处理如预期的那样工作: TERM被忽略,因为入口点处理被赋予PID 1 ,而KILL终止处理。 如果添加trap线,则TERM信号将被困在两种情况下。 如果由于任何原因它不适合你,那么你应该发布你的Dockerfile ,执行确切的命令并相应地更新你的问题。