Docker SIGTERM 未传送到节点。js/coffee 应用程序以标志启动
Docker SIGTERM not being delivered to node.js/coffee app when started with flags
我已经在我的应用程序中设置了侦听器来捕获 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.
下具有分叉进程的信号的技术细节
require('coffee-script').register();
require('./whatever.coffee').run();
然后
node --max_old_space_size=384 app.js
现在,进入技术细节...
Docker 和信号
容器中的初始进程是容器名称空间中的 PID 1。 PID 1(或 init 进程)被内核视为信号处理的特殊情况。
- 如果 init 进程没有安装信号处理程序,则不会向其发送该信号。
- 信号不会从 init 进程自动传播,进程必须对此进行管理。
所以 docker 进程应该自己处理信号。
Coffeescripts --nodejs
选项
正如您所注意到的,coffee
将 fork a child node
process when it has the --nodejs
选项能够传递额外的选项。
这最初在 外部 的 docker 信号处理方面表现出一些奇怪的行为(至少在 osx 上)。 SIGINT
或 SIGTERM
将被转发到 child 但也会立即终止 parent coffee
进程,无论您如何处理代码中的信号(这是 运行ning 在 child).
一个简单的例子
process.on 'SIGTERM', -> console.log 'SIGTERM'
process.on 'SIGINT', -> console.log 'SIGINT'
cb = -> console.log "test"
setTimeout cb, 5000
当你运行这个和ctrl-c时,信号被转发到child处理和处理。 parent 进程立即关闭,returns 到 shell。
$ coffee --nodejs --max_old_space_size=384 block_signal_coffee.coffee
^C
SIGINT
$ <5ish second pause> test
然后使用您的代码的 child 进程在后台继续 运行ning 5 秒并最终输出 test
.
Docker 和 coffee --nodejs
主要问题是 parent coffee
进程不处理代码中的任何信号,因此信号不会到达,也不会转发到 child。这可能需要更改 coffeescript's launcher code 才能修复。
在 Docker 之外出现的信号怪癖 coffee --nodejs
如果它发生在 Docker 之下也可能是坏的。如果主容器进程(fork 的 parent)在您的信号处理程序有机会在 child 中完成之前退出,容器将在它们周围关闭。如果通过将信号转发到 child.
解决上述问题,则这种情况不太可能发生。
使用建议的 javascript 加载器或修复咖啡脚本加载器的替代方法是使用实际的初始化进程,如 runit or supervisor 但这在 [=88] 之间增加了另一层复杂性=] 和您的服务。
我已经在我的应用程序中设置了侦听器来捕获 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.
require('coffee-script').register();
require('./whatever.coffee').run();
然后
node --max_old_space_size=384 app.js
现在,进入技术细节...
Docker 和信号
容器中的初始进程是容器名称空间中的 PID 1。 PID 1(或 init 进程)被内核视为信号处理的特殊情况。
- 如果 init 进程没有安装信号处理程序,则不会向其发送该信号。
- 信号不会从 init 进程自动传播,进程必须对此进行管理。
所以 docker 进程应该自己处理信号。
Coffeescripts --nodejs
选项
正如您所注意到的,coffee
将 fork a child node
process when it has the --nodejs
选项能够传递额外的选项。
这最初在 外部 的 docker 信号处理方面表现出一些奇怪的行为(至少在 osx 上)。 SIGINT
或 SIGTERM
将被转发到 child 但也会立即终止 parent coffee
进程,无论您如何处理代码中的信号(这是 运行ning 在 child).
一个简单的例子
process.on 'SIGTERM', -> console.log 'SIGTERM'
process.on 'SIGINT', -> console.log 'SIGINT'
cb = -> console.log "test"
setTimeout cb, 5000
当你运行这个和ctrl-c时,信号被转发到child处理和处理。 parent 进程立即关闭,returns 到 shell。
$ coffee --nodejs --max_old_space_size=384 block_signal_coffee.coffee
^C
SIGINT
$ <5ish second pause> test
然后使用您的代码的 child 进程在后台继续 运行ning 5 秒并最终输出 test
.
Docker 和 coffee --nodejs
主要问题是 parent coffee
进程不处理代码中的任何信号,因此信号不会到达,也不会转发到 child。这可能需要更改 coffeescript's launcher code 才能修复。
在 Docker 之外出现的信号怪癖 coffee --nodejs
如果它发生在 Docker 之下也可能是坏的。如果主容器进程(fork 的 parent)在您的信号处理程序有机会在 child 中完成之前退出,容器将在它们周围关闭。如果通过将信号转发到 child.
使用建议的 javascript 加载器或修复咖啡脚本加载器的替代方法是使用实际的初始化进程,如 runit or supervisor 但这在 [=88] 之间增加了另一层复杂性=] 和您的服务。