从内部停止docker容器
我在docker容器中运行了一个cronjob,它检查是否所有服务都按预期运行。如果此cronjob确定存在问题,我希望停止docker容器(从内部…)从内部停止docker容器,docker,Docker,我在docker容器中运行了一个cronjob,它检查是否所有服务都按预期运行。如果此cronjob确定存在问题,我希望停止docker容器(从内部…) 不幸的是,退出只是停止了我的cronjob脚本基本上,您需要PID 1退出才能停止容器 我最初认为kill-s SIGKILL 1可以工作,但PID 1是受保护的,所以它不能工作 正如@thomaslevel所建议的,您可以向PID 1脚本添加代码,例如trap“exit”SIGINT SIGTERM,这意味着当发送kill-s SIGINT
不幸的是,
退出
只是停止了我的cronjob脚本基本上,您需要PID 1退出才能停止容器
我最初认为kill-s SIGKILL 1
可以工作,但PID 1是受保护的,所以它不能工作
正如@thomaslevel所建议的,您可以向PID 1脚本添加代码,例如trap“exit”SIGINT SIGTERM
,这意味着当发送kill-s SIGINT 1
时,进程将退出。与您提出的方法(直接杀死子进程)相比,我更喜欢这种方法,因为它给了父进程一个清理的机会,并且父进程应该能够在没有awk的情况下找到子进程的PID
处理这个问题最简单的方法是使用某种监管流程,Docker现在提供了一个名为“tini”的流程。只需运行将参数
--init
添加到docker run
中,docker就会在容器中将tini设置为PID 1。完整描述如下:我试图终止进程1,但没有成功
用shutdown-h now
尝试@zero323的注释。它工作正常(抱歉,我不能直接投票支持它,因为它不在答案列表中)。我杀死了“阻塞进程”,即docker正在运行的主进程;像这样(我认为docker正在运行sleep infinity命令进行演示)
ps-afx | grep sleep | awk{print$1}| xargs kill-9我最近不得不弄清楚这一点。在经历了许多挫折之后,我发现: 在dockerfile中,指定入口点:
ENTRYPOINT ["/entrypoint.sh"]
然后,提供这样一个脚本。它不需要做任何事情,只需要调用您的应用程序。可以随意向脚本添加其他设置,但请注意,如果脚本在调用应用程序后执行任何操作,它可能会屏蔽应用程序的返回代码。如果这与您相关,请确保脚本捕获返回代码并将其作为自己的返回代码传播出去
注意:不要使用exec
调用应用程序
结果将是PID 1属于entrypoint.sh,并且您的应用程序将有一些其他PID。地雷倾向于降落在PID 9或PID 10上
然后,当您需要终止应用程序时,只需确定其PID并调用kill-SIGKILL$PID
,或pkill-SIGKILL-yourapp
。您的进程(不是PID 1)将收到信号并立即退出。您的entrypoint.sh
将立即退出,因为这是您在流程退出后设计它的目的。受@JakeRobb的启发:
您可以使用以下命令执行docker:
/bin/bash -c "while true; do sleep infinity || exit 0; done"
这将在低于1的PID上执行睡眠。一旦你杀死它,循环就会退出。为此,从docker内部使用:
pkill -f sleep
我也遇到了同样的问题,我用docker的特性解决了这个问题 您可以在类似
heahtchcheck.sh
的文件中添加检查以验证您的服务。然后在Dockerfile
中添加如下内容:
# Healthcheck
COPY healthcheck.sh /
RUN chmod +x /healthcheck.sh
HEALTHCHECK --interval=10s --retries=5 CMD /healthcheck.sh
这确保docker通过在指定的时间间隔内运行脚本来检查容器的运行状况,如果脚本连续失败5次,则会将状态标记为“不健康”
现在,为了在状态不正常时重新启动容器,您可以使用以下方法:
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autoheal
这将在每次容器状态变为不正常时重新启动容器。我的self-kill/usr/local/bin/docker-entrypoint.sh示例
#!/bin/sh
#
# Following guard prevents to stuck containers in DIND GitLab Runner
# If container still works in 300 seconds, this will kill yourself
THE_PID=$$
if [ $THE_PID -eq 1 ]; then
# Docker does not allow kill process 1, so restart as child process
/usr/local/bin/docker-entrypoint.sh
exit $?
fi
(sleep 300; echo "Killing process: $THE_PID"; kill -9 $THE_PID) &
YOUR_SCRIPT_TEXT....
你的容器是基于什么图像的?它来自ubuntu:12.04这看起来像是一张图片。您可能希望使用流程管理器作为入口点来管理多个流程,并使用事件侦听器在特定条件下终止supervisord。我也想到了这一点,但无法使其工作。你想要一个用于展示的Dockerfile吗?将
trap“exit”SIGINT SIGTERM
添加到我的shell脚本允许我在PID1
上使用kill
命令。我想我们无法解释OP的具体情况,除非我们知道使用了什么docker图像,实际上对我有效的只是扼杀了每一个进程。我有一个作为PID 1运行的shell脚本,它有一个长时间运行的子进程。子进程不受保护,仅杀死该子进程即可让我退出计算机。ps x|awk{{print$1}}awk'NR>1'| xargskill@NilsZiehn你应该详细回答自己的问题,这将有助于其他人了解实际问题以及克服问题的不同方法。另外,请看一下pkill
命令,如果有人到了这里,一种直接正确的方法是使用tini for init,它内置于docker中。查看:这是最新ubuntu图片中发生的事情:>root@b968bf313300:/#shutdown-h现在无法连接到总线:没有这样的文件或目录无法与init守护进程通信。它什么也没做,因为这不起作用而被否决<代码>关闭与initd
/systemd
/etc通信,在非容器场景中,这是PID 1。在容器中,它不存在。对于我来说,使用node:10映像,我得到bash:shutdown:command not found
这对于杀死入口点非常有效,但是不允许杀死可能在没有入口点的情况下运行的容器。当然,但是你可以为任何容器创建自己的Dockerfile。以原始Dockerfile为基础(如果有),编写并复制相应的entrypoint.sh,然后包含相应的entrypoint。这对已经运行的容器没有帮助,因此,docker会杀死来自外部的容器,并用更新的图像替换它们。@JakeRobb,谢谢你的想法。我已经发布了一个受此启发的答案