如果Ruby收到TERM信号,它通常会以退出代码143退出,根据this source表示该进程已成功响应该信号。但是如果我让脚本在没有shell的情况下运行,则退出代码为1。
使用shell:
> cat Dockerfile
FROM ruby:alpine
CMD ruby -e "Process.kill('TERM', Process.pid)" # <- shell form
> docker build -t term_shell . > /dev/null
> docker run term_shell
Terminated
> echo $?
143
没有shell:
> cat Dockerfile
FROM ruby:alpine
CMD ["ruby", "-e", "Process.kill('TERM', Process.pid)"] # <- exec form
> docker build -t term_exec . > /dev/null
> docker run term_exec
> echo $?
1
但是如果我用143退出,退出代码就像预期的那样:
> cat Dockerfile
FROM ruby:alpine
CMD ["ruby", "-e", "exit(143)"] # <- exec form
> docker build -t exit_exec . > /dev/null
> docker run exit_exec
> echo $?
143
为什么? ruby收到TERM时的退出代码是不是来自Ruby,而是来自shell?
答案 0 :(得分:4)
第二个示例的退出代码为1
,因为调用Process.kill('TERM', Process.pid)
失败。由于此失败而退出ruby -e
,此案例中的状态代码为1
。
CMD ruby -e "Process.kill('TERM', Process.pid)"
,docker在shell中执行给定的命令。在正在运行的容器中,这意味着具有pid 1的根进程将为/bin/sh -c
,并且ruby -e
命令将在具有另一个pid的子进程中执行(例如6)。CMD ["ruby", "-e", "Process.kill('TERM', Process.pid)"]
,docker直接执行ruby -e
作为pid 1的根进程。Linux上的PID 1与正常情况不同。来自docker documentation:
注意:在容器内作为PID 1运行的进程由Linux专门处理:它忽略具有默认操作的任何信号。因此,除非进行编码,否则进程不会在SIGINT或SIGTERM上终止。
因此,在您的情况下,TERM
信号不会被发送给您。
您可以在本文中找到有关PID 1行为的更多信息: https://hackernoon.com/my-process-became-pid-1-and-now-signals-behave-strangely-b05c52cc551c