当使用标志启动时,Docker SIGTERM未被传递到node.js / coffee应用程序

时间:2016-08-04 20:13:48

标签: javascript node.js docker coffeescript dockerfile

我在我的应用程序中设置了侦听器来捕获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

问题是:为什么?

1 个答案:

答案 0 :(得分:4)

TL; DR 当您需要使用扩展coffee选项时,使用Javascript加载程序文件而不是node可执行文件,以避免Docker下具有分叉进程的信号的技术性。

require('coffee-script').register();
require('./whatever.coffee').run();

然后

node --max_old_space_size=384 app.js

现在,关于技术性......


Docker和信号

容器中的初始进程是容器命名空间中的PID 1。 PID 1(或init进程)被内核视为信号处理的特例。

  1. 如果init进程没有安装信号处理程序,则该信号不会被发送给它。
  2. 信号不会自动从init进程传播,进程必须对此进行管理。
  3. 因此,预期docker进程本身会处理信号。


    Coffeescripts --nodejs选项

    如您所知,coffeefork a child node process when it has the --nodejs选项可以传递额外选项。

    这最初会出现一些奇怪的行为之外的与信号处理(至少在osx上)。无论您如何处理代码中的信号(在子代中运行),SIGINTSIGTERM都会转发到子级,但也会立即终止父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's launcher code才能修复。

    如果在Docker下发生,那么在Docker之外呈现的信号怪coffee --nodejs也可能是坏的。如果主要容器进程(fork的父进程)在信号处理程序有机会在子进程中完成之前退出,则容器将在它们周围关闭。如果仅通过将信号转发到孩子上来解决上述问题,则不太可能发生这种情况。

    使用建议的javascript加载器或修复咖啡脚本加载器的替代方法是使用实​​际的初始化过程,如runitsupervisor,但这会在docker和您之间增加另一层复杂性服务。