如果没有shell运行,Ruby退出时退出代码1响应TERM

时间:2018-05-04 07:31:16

标签: ruby docker signals exit exit-code

如果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?

1 个答案:

答案 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