前排切入

在自己做Docker镜像的时候会发现,使用docker stop停掉容器的时候,有时候并不会立即停掉,而是会等待超时,然后被docker-daemon强制kill掉。其实这种情况是不正常的(或者说不优雅的),假如该进程在写着文件,突然kill掉进程可能会导致文件破损,甚至其他更严重的情况。

docker stop出现超时的原因应该很多,但比较常见的原因是,我们自己写的入口Bash脚本没有对docker stop发送给容器的SIGTERM信号传递给子进程。

举两颗栗子带上车吧

1号栗子

创建三个文件:
– Dockerfile
– entrypoint.sh
– server-daemon

Dockerfile

FROM debian:sid

COPY entrypoint.sh /
COPY server-daemon /usr/bin/

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/bash

server-daemon

server-daemon

#!/bin/bash

loop(){
    while true; do
        echo hello deepin
        sleep 1
    done
}

loop

文件创建完之后,构建镜像:

docker build -t test-image-1 .

启动:

docker run -it --rm --name test-1 test-image-1
# hello deepin
# hello deepin
# ...

停止容器:

docker stop test-1

发现容器在10s(docker stop默认10秒超时)后停止了
(其实是被docker daemon发送SIGKILL杀掉了)

2号栗子

也是创建三个文件:
– Dockerfile
– entrypoint.sh
– server-daemon

Dockerfile

FROM debian:sid

COPY entrypoint.sh /
COPY server-daemon /usr/bin/

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/bash

_term() {
    echo "Caught SIGTERM signal, forward to child"
    kill -TERM "$child"
    exit 0
}

trap _term SIGTERM

server-daemon &

child=$!
wait "$child"

server-daemon

#!/bin/bash

loop(){
    while true; do
        echo hello deepin
        sleep 1
    done
}

loop

文件创建完之后,构建镜像:

docker build -t test-image-2 .

启动:

docker run -it --rm --name test-2 test-image-2
# hello deepin
# hello deepin
# ...

停止容器:

docker stop test-2

发现这个时候就可以直接停掉容器,而不用等待超时被kill掉了

简单总结下

bash在子进程执行的时候会忽略所有的信号,2号栗子的entrypoint.sh使用&server-daemon放到后台执行,并使用$!记录server-daemon的PID。使用wait $PID等待server-daemon进程结束,或者当bash收到SIGTERM信号后也向该进程发送SIGTERM信号,让其结束。

1号栗子 和 2号栗子 的区别只是entrypoint.sh文件不一样而已。

参考

发表评论

电子邮件地址不会被公开。 必填项已用*标注