Bash 脚本入口点(PID=1)仅当存在假陷阱(不执行任何操作)时才会终止“tail”子进程

Bash 脚本入口点(PID=1)仅当存在假陷阱(不执行任何操作)时才会终止“tail”子进程

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能让一切正常(虽然它实际上什么也没做,但它能正常工作,因为它只是在那里)。

我只是仍然想说一下,使用空的traptrap "" 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、您执行的确切命令并相应地更新您的问题。

相关内容