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

Ruby exits with exit code 1 responding to TERM if running without shell

如果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,因为调用 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:

Note: A process running as PID 1 inside a container is treated specially by Linux: it ignores any signal with the default action. So, the process will not terminate on SIGINT or SIGTERM unless it is coded to do so.

因此在您的情况下,TERM 信号不会发送给您的进程。

您可以在本文中找到有关 PID 1 行为的更多信息: https://hackernoon.com/my-process-became-pid-1-and-now-signals-behave-strangely-b05c52cc551c