使用标志启动时,Docker SIGTERM 未传递到 node.js/coffee 应用程序
问题:使用标志启动时,Docker SIGTERM 未传递到 node.js/coffee 应用程序 我在我的应用程序中设置了监听器来捕捉 SIGTERM、SIGINT 和 SIGUSR2: # kill process.on 'SIGTERM', -> killExecutors 'SIGTERM' # ctrl + c process.on 'SIGINT', -> killExecutors
问题:使用标志启动时,Docker SIGTERM 未传递到 node.js/coffee 应用程序
我在我的应用程序中设置了监听器来捕捉 SIGTERM、SIGINT 和 SIGUSR2:
# kill
process.on 'SIGTERM', ->
killExecutors 'SIGTERM'
# ctrl + c
process.on 'SIGINT', ->
killExecutors 'SIGINT'
# nodemon signal
process.on 'SIGUSR2', ->
killExecutors 'SIGUSR2'
它按预期工作。当我在 docker 实例中运行它时:
FROM node:4.4.7
MAINTAINER Newborns <newborns@versul.com.br>
COPY . /src
EXPOSE 7733
WORKDIR /src
RUN npm install
CMD ["./node_modules/.bin/coffee", "feeder.coffee"]
一切正常,也是。但是,当我在执行中添加节点标志时
FROM node:4.4.7
MAINTAINER Newborns <newborns@versul.com.br>
COPY . /src
EXPOSE 7733
WORKDIR /src
RUN npm install
CMD ["./node_modules/.bin/coffee", "--nodejs", "--max_old_space_size=384", "feeder.coffee"]
它停止捕捉信号。我试图将 de CMD exec 表单更改为
CMD ./node_modules/.bin/coffee --nodejs --max_old_space_size=384 feeder.coffee
但仍然无法正常工作。有和没有标志的执行之间有什么变化?
编辑:
实际上,发生的事情是 docker 在没有传递任何标志时启动一个进程
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 4.2 1.0 960940 85424 ? Ssl 20:21 0:01 node ./node_modules/.bin/coffee feeder.coffee
root 16 0.1 0.0 20220 2884 ? Ss 20:22 0:00 bash
root 20 0.0 0.0 17500 2064 ? R+ 20:22 0:00 ps -aux
以及传递标志时的两个进程
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.3 707704 25272 ? Ssl 20:17 0:00 node ./node_modules/.bin/coffee --nodejs --max_old_space_size=384 feeder.coffee
root 10 1.7 1.1 965900 90068 ? Sl 20:17 0:01 /usr/local/bin/node --max_old_space_size=384 /src/node_modules/.bin/coffee feeder.coffee
问题是:为什么?
解答
TL;DR 当您需要使用扩展的node
选项以避免 Docker 下的分叉进程的信号技术问题时,请使用 Javascript 加载程序文件而不是coffee
可执行文件。
require('coffee-script').register();
require('./whatever.coffee').run();
然后
node --max_old_space_size=384 app.js
现在,进入技术细节......
Docker 和信号
容器中的初始进程是容器命名空间中的 PID 1。 PID 1(或 init 进程)在信号处理方面被内核视为特殊情况。
-
如果 init 进程没有安装信号处理程序,则不会向它发送该信号。
-
信号不会从初始化进程自动传播,进程必须对此进行管理。
因此,docker 进程应该自己处理信号。
Coffeescripts--nodejs
选项
正如您所注意到的,当--nodejs
](https://github.com/jashkenas/coffeescript/blob/88192c197a86759e25e1a0d8a31909b72a96cbc8/src/command.coffee#L439-L447)选项能够传递额外的选项时,coffee
将[派生一个子node
进程。
这最初提出了一些带有信号处理的 docker outside 的奇怪行为(至少在 osx 上)。SIGINT
或SIGTERM
将被转发到子进程,但也会立即终止父coffee
进程,无论您如何处理代码中的信号(在子进程中运行)。
一个简单的例子
process.on 'SIGTERM', -> console.log 'SIGTERM'
process.on 'SIGINT', -> console.log 'SIGINT'
cb = -> console.log "test"
setTimeout cb, 5000
当你运行这个和 ctrl-c 时,信号被转发到子进程并被处理。父进程立即关闭并返回到 shell。
$ coffee --nodejs --max_old_space_size=384 block_signal_coffee.coffee
^C
SIGINT
$ <5ish second pause> test
然后带有你代码的子进程继续在后台运行5秒,最终输出test
。
Docker 和coffee --nodejs
主要问题是父coffee
进程不处理代码中的任何信号,因此信号不会到达并且不会转发给子进程。这可能需要更改coffeescript 的启动器代码才能修复。
如果它发生在 Docker 下,那么在 Docker 之外出现的信号怪癖coffee --nodejs
也可能是坏的。如果主容器进程(fork 的父进程)在您的信号处理程序有机会在子进程中完成之前退出,则容器将围绕它们关闭。如果仅通过将信号转发给孩子来解决上述问题,则这种情况不太可能发生。
使用建议的 javascript 加载器或修复咖啡脚本加载器的替代方法是使用实际的 init 进程,例如runit或supervisor但这在 docker 和您的服务之间增加了另一层复杂性。
更多推荐
所有评论(0)