“docker stop”命令用于停止crond时超时

5

我正在努力理解为什么我的Docker容器无法优雅地停止,而只是超时。该容器正在运行crond

FROM alpine:latest

ADD crontab /etc/crontabs/root
RUN chmod 0644 /etc/crontabs/root

CMD ["crond", "-f"]

crontab 文件是:

* * * * * echo 'Working'
# this empty line required by cron

使用命令 docker build . -t periodic:latest 进行构建,
使用命令 docker run --rm --name periodic periodic:latest 运行,
但是,如果在另一个终端尝试使用命令 docker stop periodic 停止容器时,它无法正常停止。会出现超时并被强制终止。就好像crond 未响应 SIGTERM 一样。
请注意,crond 明确地被分配为 PID 1。
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 crond -f
    6 root      0:00 ash
   11 root      0:00 ps

然而,如果我这样做:

docker run -it --rm --name shell alpine:latest ash 并在另一个终端中使用 docker exec -it shell crond -f,我就可以使用 SIGTERM 从第一个 shell 来终止 crond ,所以我知道它可以用 SIGTERM 进行停止。

感谢任何帮助。

2个回答

6
将一个 init 进程添加到容器中(在 docker-compose.yml 中设置 init: true)可以解决这个问题。
编辑:我阅读了这篇文章 https://blog.thesparktree.com/cron-in-docker 以了解在 Docker 中运行 cron 的问题和解决方案。文章中提到:
“最后,当你玩耍时,你可能会发现很难杀死运行 cron 的容器。你可能不得不使用 docker kill 或 docker-compose kill 命令来终止容器,而不是使用 ctrl + C 或 docker stop 命令。
不幸的是,似乎当在前台运行时,cron 实现并不总是正确处理 SIGINT 信号。
经过研究几个替代方案后,唯一可行的解决方案似乎是使用进程监视器(如 tini 或 s6-overlay)。由于 tini 已合并到 Docker 1.13 中,因此从技术上讲,您可以通过在 docker run 命令中传递 --init 参数来透明地使用它。但实际上,您通常无法这样做,因为您的集群管理器不支持它。”
自从我发布原帖并回答之后,我已经迁移到了Kubernetes,因此在docker-compose.yml中的init将不起作用。我的容器基于Debian Buster,因此我现在在Dockerfile中安装了tini,并将ENTRYPOINT更改为["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"](我的entrypoint.sh最终执行exec cron -f)。

1
Cron有什么特殊之处,需要init:true才能优雅地停止?图像/容器是否有解决问题的方法,而不需要更改docker-compose? - chrisinmtown
@chrisinmtown 答案已更新 - Steve Folly

0

关键是你不能停止在docker中的pid=1进程。它假设docker停止(或者如果使用--rm启动,则杀死)。

这就是为什么如果你运行-it ... ash,shell有pid 1,你可以杀死其他进程。

如果你想让你的cron可被杀死而不停止/杀死docker,只需启动另一个进程作为入口点:

在docker入口点之后启动cron(例如,作为cmd运行tail -F /dev/null,然后启动cron docker run -d yourdocker service cron start


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接