优雅地停止 Docker 容器

amp*_*amp 6 signals tcsh docker 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"]
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

使docker-entrypoint.sh可执行:

chmod 744 docker-entrypoint.sh
Run Code Online (Sandbox Code Playgroud)

构建图像:

docker build -t my-dummy-img .
Run Code Online (Sandbox Code Playgroud)

请注意,我正在使用tcshshell。

如果您看一下 ,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>
Run Code Online (Sandbox Code Playgroud)

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

Starting
cleanup on going
Run Code Online (Sandbox Code Playgroud)

而不是只有

Starting
Run Code Online (Sandbox Code Playgroud)

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

另一方面,如果我运行:

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

然后点击CTRL+C,我可以看到预期的输出。

我在这里缺少什么?我希望这个问题足够清楚。

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

优雅地停止 Docker 容器

在 Docker 容器中捕获信号

amp*_*amp 7

终于解决了问题。

Tcsh shell 不会收到大多数信号,例如 SIGTERM,这是docker在停止容器时发送的信号。

因此,我将脚本更改为使用 bash shell,每当我想运行 tcsh 命令时,我就这样做:

/bin/tcsh ./my-command
Run Code Online (Sandbox Code Playgroud)

所以,我的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
Run Code Online (Sandbox Code Playgroud)

  • 你能详细解释一下吗?`tail -f /dev/null & 等待 ${!}` (2认同)
  • `tail -f /dev/null &` 在后台运行 tail 命令,然后 `wait ${!}` 等待它完成。`tail -f /dev/null` 或 `sleep 1000` 不够好,因为它们会阻止信号处理。相反,`wait` 是可中断的。 (2认同)