首页 > 解决方案 > Catching SIGTERM from alpine image

问题描述

I was trying to catch SIGTERM signal from a docker instance (basically when docker stop is called) but couldn't find a way since I have different results for each try I performed.

Following is the setup I have

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

Now I build the docker image

$ 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

Run the docker

$ docker run -it dockertrapcatch

Now when I run docker stop <<container_id_here>> or docker kill --signal=SIGTERM <<container_id_here>>, my deregister_runner function is not called.

After that I changed the start.sh script as following (SIGKILL ==> EXIT)

#!/bin/bash

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

while true; do
    sleep 10
done

After this change and creating the docker image and running it docker stop <<container_id_here>> still does not work but docker kill --signal=SIGTERM <<container_id_here>> works!

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

I read that actually docker stop sends a SIGTERM but I think this time it is not working? Any idea?

标签: dockerdockerfilegitlab-ci-runneralpinesigkill

解决方案


我可以重现您提出的问题,但是当我用 替换基本图像时它不会出现debian:10,例如。

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

STOPSIGNAL SIGQUIT

更准确地说,上面的行意味着docker stop将向正在运行的容器发送SIGQUIT信号(并在杀死容器之前等待“优雅终止时间”,就好像docker kill最后发出了 a 一样)。

如果不使用此 Dockerfile 指令,则发送的默认信号docker stop是 SIGTERM

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

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

trap deregister_runner SIGINT SIGQUIT SIGTERM

这样,您的清理功能deregister_runner将在您发出 adocker stop或使用Ctrl-C键绑定时触发(感谢SIGINT)。

最后,与 和 的问题相关的两个附加Docker说明bash

  • 可以自定义“优雅终止时间”(在停止和终止之间),并且在使用 Bash 入口点时存在一些陷阱(关于“信号传播”)。我在这个 SO 答案中更详细地解释了这两个问题:加速 docker-compose shutdown

  • 请注意,在许多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包:)


推荐阅读