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

时间:2015-12-23 18:52:28

标签: linux node.js docker docker-compose

当我的Dockerfile以

结尾时
CMD node .

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进程,因此在10秒宽限期后,每次都会SIGKILL强行杀死它。不太好。

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

3 个答案:

答案 0 :(得分:6)

我认为您必须了解ENTRYPOINTCMD的角色,并在ENTRYPOINT中使用Dockerfile(exec表单)方式。

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

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

ENTRYPOINT有两种形式: exec form shell form

  • 执行形式:ENTRYPOINT ["可执行文件"," param1"," param2"]
  • shell form:命令param1 param2

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

  

shell表单可防止使用任何CMDrun命令行参数,但缺点是您的ENTRYPOINT将作为子命令启动/bin/sh -c,不传递信号。这意味着可执行文件不是容器的PID 1 - 并且不会接收Unix信号 - 因此您的可执行文件将不会从SIGTERM收到docker stop <container>。< / p>

答案 1 :(得分:3)

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

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

使用from selenium.webdriver.common.by import By profile["name"] = member.find_element(By.CSS_SELECTOR, "sv:member_name").get_attribute('innerHTML') 语法,您可以使用https://nodejs.org/api/process.html#process_signal_events并让它退出SIGTERM。我相信这就足够了。

或者使用bash脚本,您可以使用["node", "."]

您还可以使用像http://skarnet.org/software/s6/

这样的流程主管

答案 2 :(得分:0)

我对PID1问题的解决方案:

Dockerfile以:

结尾
ENTRYPOINT ["/bin/bash", "-c"]

或者将ENTRYPOINT完全从Dockerfile中删除。默认值为/bin/sh -c

我使用此shell脚本运行,该脚本的文件名为node并且chmod +x

#!/bin/bash

docker run --rm -it -p 8083:80 -v $HOME/node/work/:/root/node/:rw node_node "echo pid1 > /dev/null && node $@"

诀窍是"echo pid1 > /dev/null && node $@"这是命令。 $@是一个shell脚本,用于接受来自命令行的用户输入。

echo将捕获PID1并将输出发送到/dev/null

例如./node -v将在正在运行的容器中返回Node.js的版本。

使用./node /root/node/hello-world.js命令运行网络服务器,CTRL + C将再次运行。

Here是我的Dockerised Node.js开发环境。

修改

完全疯狂的想法,但将此node命名的bash脚本添加到$ PATH。因此,在主机上,您可以键入node -v而不是./node -v。并且您在Docker容器中运行节点,该容器完全看起来像是在主机上安装的。 :)