当docker使用`/ bin/sh -c`运行时,SIGTERM不会到达节点脚本

Rom*_*man 6 linux node.js docker docker-compose

当我的Dockerfile结束时

CMD node .
Run Code Online (Sandbox Code Playgroud)

docker使用命令运行该容器/bin/sh -c "node ."而不是简单node .(我知道,我可以这样做CMD ["node", "."]).

我认为,这种行为其实是不错的,因为这意味着容器内部PID1/bin/sh,而不是我谦虚节点脚本.

如果我理解正确PID1负责收割孤儿僵尸进程,我真的不想对此负责......所以如果/bin/sh能做到这一点,那就太好了.(我实际上认为这就是为什么docker会重写我的原因CMD).

问题是,当我向SIGTERM容器发送(开始/bin/sh -c "node .")时,无论是通过docker-composer stop还是docker-composer kill -s SIGTERM,信号都没有到达我的node进程,因此每次SIGKILL在10秒宽限期后都会被强制杀死.不太好.

有没有办法让某人管理我的僵尸并让我的节点实例接收由docker发送的信号?

小智 6

我认为你必须理解和的角色,ENTRYPOINT并在你的角色中CMD使用ENTRYPOINT(exec形式)方式Dockerfile.

ENTRYPOINT,指定容器的起始可执行文件,是Docker容器的核心部分.每个容器必须有一个入口点来决定从哪里开始.默认情况下,该值为/bin/bash -c.此外,设置的所有内容都CMDENTRYPOINT作为参数附加.

因此,如果您未能ENTRYPOINT在您的指定中指定Dockerfile实际的入口点,那么/bin/bash -c {your_command_in_CMD}遗憾的是它不会传递信号.

ENTRYPOINT有两种形式:exec形式shell形式

  • exec形式:ENTRYPOINT ["executable","param1","param2"]
  • shell form:命令param1 param2

正如Docker引用所指出的那样:建议使用exec表单,而shell表单的缺点是命令执行/bin/bash -c,这可能不适用于信号:

所述壳形式防止任何CMDrun被使用命令行参数,但是具有你的缺点ENTRYPOINT将被开始作为一个子命令/bin/sh -c,其不通过信号.这意味着可执行文件不会是容器PID 1- 并且不会收到Unix信号 - 因此您的可执行文件将不会收到SIGTERM来自docker stop <container>.


dne*_*hin 4

有一些工具可以解决这个问题:

我认为如果你只有一个进程,你需要做的就是使用信号处理程序显式处理信号,而 bash 不适合你。

使用["node", "."]语法,您可以使用https://nodejs.org/api/process.html#process_signal_events并让它在 SIGTERM 上退出。我相信这就足够了。

或者使用 bash 脚本,您可以使用trap "exit 0" TERM

您还可以使用流程管理程序,例如http://skarnet.org/software/s6/