当我的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发送的信号?
答案 0 :(得分:6)
我认为您必须了解ENTRYPOINT
和CMD
的角色,并在ENTRYPOINT
中使用Dockerfile
(exec表单)方式。
ENTRYPOINT
,指定容器的起始可执行文件,是Docker容器的核心部分。每个容器必须都有一个入口点来决定从哪里开始。默认情况下,该值为/bin/bash -c
。此外,CMD
设置的所有内容都将作为参数附加到ENTRYPOINT
。
因此,如果您未在ENTRYPOINT
中指定Dockerfile
,则实际入口点将为/bin/bash -c {your_command_in_CMD}
,遗憾的是不会传递信号。
ENTRYPOINT
有两种形式: exec form 和 shell form
正如Docker reference指出:建议使用exec表单,而shell表单的缺点是/bin/bash -c
执行 command ,这可能不适用于信号:
shell表单可防止使用任何
CMD
或run
命令行参数,但缺点是您的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", "."]
答案 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容器中运行节点,该容器完全看起来像是在主机上安装的。 :)