从高山图像中捕获 SIGTERM

Catching SIGTERM from alpine image

我试图从 docker 实例(基本上是在调用 docker 停止时)捕获 SIGTERM 信号,但找不到方法,因为我每次尝试都有不同的结果。

以下是我的设置

Dockerfile

FROM gitlab/gitlab-runner:alpine

COPY ./start.sh /start.sh

ENTRYPOINT ["/start.sh"]

start.sh

#!/bin/bash

deregister_runner() {
    echo "even if nothing happened, something happened"
    exit
}
trap deregister_runner SIGTERM

while true; do
    sleep 10
done

现在我构建 docker 图像

$ docker build -t dockertrapcatch .
Sending build context to Docker daemon  51.71kB
Step 1/3 : FROM gitlab/gitlab-runner:alpine
 ---> 9f8c39873bee
Step 2/3 : COPY ./start.sh /start.sh
 ---> Using cache
 ---> ebb3cac0c509
Step 3/3 : ENTRYPOINT ["/start.sh"]
 ---> Using cache
 ---> 7ab67fe5a714
Successfully built 7ab67fe5a714
Successfully tagged dockertrapcatch:latest

运行 docker

$ docker run -it dockertrapcatch

现在当我 运行 docker stop <<container_id_here>>docker kill --signal=SIGTERM <<container_id_here>> 时,我的 deregister_runner 函数不会被调用。

之后,我将 start.sh 脚本更改为如下 (SIGKILL ==> EXIT)

#!/bin/bash

deregister_runner() {
    echo "even if nothing happened, something happened"
    exit
}
trap deregister_runner EXIT

while true; do
    sleep 10
done

进行此更改并创建 docker 图像并 运行 将其 docker stop <<container_id_here>> 仍然无法正常工作,但 docker kill --signal=SIGTERM <<container_id_here>> 有效!

$ docker run -it dockertrapcatch
even if nothing happened, something happened
$ docker kill --signal=SIGTERM 6b667af4ac6c
6b667af4ac6c

我读到实际上 docker stop 发送了一个 SIGTERM 但我认为这次它不起作用?有什么想法吗?

我可以重现你提出的问题,但是当我用 debian:10 替换基本图像时它没有出现。

碰巧问题不是由于 alpine 而是由于 gitlab/gitlab-runner:alpine 图像本身,即 this Dockerfile 包含以下行:

STOPSIGNAL SIGQUIT

更准确地说,上面的行意味着 docker stop 将向 运行 容器发送 SIGQUIT 信号(并在终止容器之前等待 "graceful termination time" , 好像最后发出了一个docker kill).

如果不使用这个 Dockerfile 指令,the default signal sent by docker stop is SIGTERM.

请注意,SIGKILL 对于 STOPSIGNAL 来说是一个非常糟糕的选择,因为无法捕获 KILL 信号。

因此,如果您使用以下行,您的第一个示例应该可以工作:

trap deregister_runner SIGINT SIGQUIT SIGTERM

这样,只要您发出 docker stop 或使用 Ctrl-C 键绑定(感谢 SIGINT),您的清理功能 deregister_runner 就会被触发。

最后,与Dockerbash和信号这个问题相关的另外两个注释:

  • 可以自定义 "graceful termination time"(停止和终止之间),使用 Bash 入口点(关于 "signal propagation")时有一些陷阱。我在这个 SO 答案中更详细地解释了这两个问题:.

  • 请注意,在许多 alpine 图像中,bash 未预安装,例如:

    $ sudo docker run --rm -it alpine /bin/bash
      /usr/bin/docker: Error response from daemon: OCI runtime create failed:
      container_linux.go:346: starting container process caused
      "exec: \"/bin/bash\": stat /bin/bash: no such file or directory": unknown.
    

    (幸运的是,gitlab/gitlab-runner:alpine 并非如此,它确实包含 bash 包 :)