![Bash 脚本入口点(PID=1)仅当存在假陷阱(不执行任何操作)时才会终止“tail”子进程](https://linux22.com/image/709360/Bash%20%E8%84%9A%E6%9C%AC%E5%85%A5%E5%8F%A3%E7%82%B9%EF%BC%88PID%3D1%EF%BC%89%E4%BB%85%E5%BD%93%E5%AD%98%E5%9C%A8%E5%81%87%E9%99%B7%E9%98%B1%EF%BC%88%E4%B8%8D%E6%89%A7%E8%A1%8C%E4%BB%BB%E4%BD%95%E6%93%8D%E4%BD%9C%EF%BC%89%E6%97%B6%E6%89%8D%E4%BC%9A%E7%BB%88%E6%AD%A2%E2%80%9Ctail%E2%80%9D%E5%AD%90%E8%BF%9B%E7%A8%8B.png)
Bash
我在我的脚本中遇到了一个奇怪的行为,我有这个Bash
正在运行的脚本PID 1
(它是一个entrypoint
容器Docker
,如果你不熟悉 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
能让一切正常(虽然它实际上什么也没做,但它能正常工作,因为它只是在那里)。
我只是仍然想说一下,使用空的trap
:trap "" SIGTERM
没有帮助,陷阱中应该有一些东西可以起作用(即使它什么都不做)。
希望有人能帮助我,谢谢!
答案1
实际上,在运行容器时添加t
参数(分配 tty)可以解决问题。我以前使用-d
参数运行它,现在使用-td
。
我不知道为什么,但它就是这么做的。如果有人能解释为什么会发生这种情况就太好了。
答案2
您没有提供您的信息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"]
构建容器:
$ docker build -f Dockerfile -t test_image .
每次更改入口点脚本时,请不要忘记重建容器。
用以下命令运行容器:
$ docker run --rm -it --name test_trap test_image
现在,让我们看看每次运行发生的情况。
1)使用脚本trap
中的以下行Bash
:
# 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
信号的进程(并且SIGINT
)。
有关此问题的更多信息:
任何进程都可以注册自己的 TERM 处理程序,并在退出前使用它们执行清理工作。如果进程尚未注册自定义信号处理程序,内核通常会恢复 TERM 信号的默认行为:终止进程。
但是,对于 PID 1,内核在转发 TERM 时不会恢复任何默认行为。如果您的进程尚未注册自己的处理程序(大多数进程都没有),则 TERM 将对进程没有影响。
来源 -https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html
更新
我暂时无法发表评论,因此我将在此发表评论。这是同一个PID 1
问题。使用和时-d
,-td
信号处理工作正常:TERM
被忽略,因为入口点进程被分配PID 1
,而KILL
终止进程。如果添加该trap
行,则TERM
信号将在两种情况下被捕获。如果它因任何原因对您不起作用,那么您应该发布您的Dockerfile
、您执行的确切命令并相应地更新您的问题。