优雅地停止 Docker 个容器
Gracefully Stopping Docker Containers
我在理解如何在容器停止时进行清理时遇到一些问题。
为了方便起见,我准备了一个示例来重现该问题。
以下是我的文件内容:
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-entrypoint.sh
#!/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
,您会发现我正在等待 cath 中断 (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
,我可以看到预期的输出。
我在这里错过了什么?我希望问题足够清楚。
顺便说一句,我使用以下文章作为指南:
这可能是因为您在分离模式下启动它:see documentation。
onintr is ignored if the shell is running detached
你必须找到替代方案,比如使用 bash 和陷阱 as seen here
终于解决了问题
Tcsh shell doesn't receive most of the signals like SIGTERM这是docker停止容器时发出的信号。
所以我将脚本更改为使用 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
我有一个简单的陷阱 bash 脚本,运行 main
函数调用所有其他程序,shutdown
函数 运行优雅关闭它的脚本:
trap "shutdown" SIGTERM
main
停止容器时无法Docker触发关闭函数。在命令前添加 exec,使用 tini 作为 init,更改 STOPSIGNAL 都无济于事。原因是程序main
运行没有return控件
在末尾添加 & wait
使其工作正常:
trap "shutdown" SIGTERM
main & wait
我在理解如何在容器停止时进行清理时遇到一些问题。
为了方便起见,我准备了一个示例来重现该问题。
以下是我的文件内容:
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-entrypoint.sh
#!/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
,您会发现我正在等待 cath 中断 (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
,我可以看到预期的输出。
我在这里错过了什么?我希望问题足够清楚。
顺便说一句,我使用以下文章作为指南:
这可能是因为您在分离模式下启动它:see documentation。
onintr is ignored if the shell is running detached
你必须找到替代方案,比如使用 bash 和陷阱 as seen here
终于解决了问题
Tcsh shell doesn't receive most of the signals like SIGTERM这是docker停止容器时发出的信号。
所以我将脚本更改为使用 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
我有一个简单的陷阱 bash 脚本,运行 main
函数调用所有其他程序,shutdown
函数 运行优雅关闭它的脚本:
trap "shutdown" SIGTERM
main
停止容器时无法Docker触发关闭函数。在命令前添加 exec,使用 tini 作为 init,更改 STOPSIGNAL 都无济于事。原因是程序main
运行没有return控件
在末尾添加 & wait
使其工作正常:
trap "shutdown" SIGTERM
main & wait