优雅地停止Docker容器

问题描述 投票:4回答:3

我很难理解如何在容器停止时进行一些清理工作。

为了方便起见,我准备了一个样本来重现问题。

以下是我的文件内容:

Dockerfile

FROM opensuse:latest

# Install tcsh (non-interactive mode)
RUN zypper -n in tcsh

# Create user
RUN useradd -ms /bin/tcsh dummyuser

# Set the user
USER dummyuser

# Change Working Dir
WORKDIR /home/dummyuser

# Copy entrypoint script
COPY docker-entrypoint.sh $HOME

# Starter Script
ENTRYPOINT ["./docker-entrypoint.sh"]

docker-entry point.是

#!/bin/tcsh

echo "Starting"

onintr cleanup

# Running something in foreground, otherwise the container will stop
while (1)
   sleep 1000
end
exit 0

cleanup:
   onintr -
   echo "cleanup on going"
   exit 0

使docker-entrypoint.sh可执行:

chmod 744 docker-entrypoint.sh

构建图像:

docker build -t my-dummy-img .

请注意,我正在使用tcsh shell。

如果你看看docker-entrypoint.sh,你可以看到我正在等待中断(onintr cleanup)并调用清理方法。

现在,这些是我运行的命令:

mstack/dummy-project> docker run --name my-service -ti -d my-dummy-img ps -eaf
da1dc21281a58e384f2ff34aa49a82019214e204e6d7a77ff54e8c96e005f913
mstack/dummy-project> docker logs my-service
Starting
mstack/dummy-project> docker stop my-service
my-service
mstack/dummy-project> docker logs my-service
Starting
mstack/dummy-project>

这是问题,我希望在第二个docker logs my-service后输出将是:

Starting
cleanup on going

而不仅仅是

Starting

因为docker应该在停止时发送信号......

另一方面,如果我跑:

docker run --name my-service-attached -ti my-dummy-img ps -eaf

并打了CTRL+C,我可以看到预期的输出。

我在这里错过了什么?我希望这个问题足够清楚。

顺便说一下,我使用以下文章作为指导:

Gracefully Stopping Docker Containers

Trapping signals in Docker containers

docker signals dockerfile tcsh
3个回答
4
投票

终于解决了这个问题。

Tcsh shell doesn't receive most of the signals like SIGTERM是停靠集装箱时码头发出的信号。

所以我改变了脚本以使用bash shell,每当我想运行tcsh命令时,我就这样做:

/bin/tcsh ./my-command

所以,我的docker-entrypoint.sh是这样的:

#!/bin/bash

# SIGTERM-handler this funciton will be executed when the container receives the SIGTERM signal (when stopping)
term_handler(){
   echo "***Stopping"
   /bin/tcsh ./my-cleanup-command
   exit 0
}

# Setup signal handlers
trap 'term_handler' SIGTERM

echo "***Starting"
/bin/tcsh ./my-command

# Running something in foreground, otherwise the container will stop
while true
do
   #sleep 1000 - Doesn't work with sleep. Not sure why.
   tail -f /dev/null & wait ${!}
done

1
投票

这可能是因为您以分离模式启动它:see documentation

如果shell正在运行分离,则忽略onintr

你将不得不寻找替代方案,比如使用bash和陷阱as seen here


0
投票

我有一个简单的陷阱bash脚本运行调用所有其他程序的main函数,shutdown函数运行脚本以优雅地关闭它:

trap "shutdown" SIGTERM

main

停止容器时,我无法让Docker触发关闭功能。在命令之前添加exec,使用tini作为init,更改STOPSIGNAL并没有帮助它。原因是因为程序main运行没有返回控件。

添加& wait到最后使它工作正常:

trap "shutdown" SIGTERM

main & wait
© www.soinside.com 2019 - 2024. All rights reserved.