我有一个在 Docker 容器内运行的 cronjob,它会检查所有服务是否按预期运行。如果 cronjob 确定存在问题,我想停止 Docker 容器(从内部...)
不幸的是,exit
只会停止我的 cronjob 脚本。
我有一个在 Docker 容器内运行的 cronjob,它会检查所有服务是否按预期运行。如果 cronjob 确定存在问题,我想停止 Docker 容器(从内部...)
不幸的是,exit
只会停止我的 cronjob 脚本。
基本上,你需要 PID 1 退出以停止容器。
执行 kill -s SIGKILL 1
无法生效,因为 PID 1 受到保护。
如 @Thomasleveil 建议的,你可以在 PID 1 脚本中添加代码,例如 trap "exit" SIGINT SIGTERM
,这将意味着当发送 kill -s SIGINT 1
时,进程会退出。我稍微倾向于这种方法,而不是你提出的方法(直接杀死子进程),因为它给父进程一个机会来清理,并且父进程应该能够找到子进程的 PID,而不需要使用 awk。
处理这个问题最简单的方法是使用某种监督进程,而 Docker 现在提供了一个名为 "tini" 的监督进程。只需在 docker run
中添加参数 --init
,Docker 将在容器中设置 tini 作为 PID 1。完整的描述在这里:https://docs.docker.com/engine/reference/run/#specify-an-init-process
trap "exit" SIGINT SIGTERM
添加到我的shell脚本中,使我能够在PID 1
上使用kill
命令。我想,除非我们知道正在使用哪个docker镜像,否则无法回答OP的特定情况。 - Thomasleveilpkill
命令。 - Thomasleveilkill -s SIGINT 1
还是kill -s SIGKILL 1
都不起作用。虽然我后来发现将PID更改为负数以杀死整个PID组似乎可以工作,例如kill -s SIGINT -1
或kill -s SIGKILL -1
。这似乎与您的经验相反...我想知道您的入口脚本是否有所不同。 - StockB我遇到了同样的问题,通过使用docker的healthcheck功能解决了它。
您可以在类似于heahthcheck.sh
的文件中添加检查以验证您的服务。然后将以下内容附加到您的Dockerfile
:
# Healthcheck
COPY healthcheck.sh /
RUN chmod +x /healthcheck.sh
HEALTHCHECK --interval=10s --retries=5 CMD /healthcheck.sh
这样可以确保Docker通过在指定的时间间隔内运行脚本来检查容器的健康状况,如果连续5次失败,则将状态标记为不健康。
现在,为了在状态变为不健康时重新启动容器,您可以像这样使用autoheal:
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autoheal
每当容器状态不健康时,这将重新启动您的容器。
/bin/bash -c "while true; do sleep infinity || exit 0; done"
这将在一个小于1的PID上执行sleep。一旦您杀死它,循环将退出。为此,请在docker中使用以下命令:
pkill -f sleep
docker exec...
,那么它不起作用,只会冻结,也许他的意思是在容器启动时将其作为开头命令运行,那么它就可以工作了。 - jave.webENTRYPOINT ["/entrypoint.sh"]
然后,提供这样一个脚本。它不需要做任何事情,只需调用您的应用程序。您可以随意向脚本添加其他设置,但请注意,如果脚本在调用您的应用程序之后执行任何操作,可能会掩盖您的应用程序返回代码。如果这对您有影响,请确保脚本捕获返回代码并将其作为自己的返回代码传播出去。
注意:不要使用exec
来调用您的应用程序!
结果是PID 1属于entrypoint.sh,而您的应用程序将具有一些其他PID。我的应用程序通常落在PID 9或10上。
然后,当您需要终止您的应用程序时,只需确定其PID并调用kill -SIGKILL $PID
或pkill -SIGKILL yourapp
。您的进程不是PID 1,将接收到信号并立即退出。您的entrypoint.sh
将立即退出,因为这是您设计它在您的进程退出后所做的事情。
docker kill
杀死它们,并用更新后的镜像替换它们。 - JakeRobb以下是我自杀 /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....
ps -afx |grep npm | awk '{print $1}' | xargs kill -9
- gearcoded我试图杀死进程1,但没有成功。
尝试使用@zero323的评论中的shutdown -h now
。它可以正常工作(抱歉,我无法直接为它投票,因为它不在答案列表中)。
root@b968bf313300:/# shutdown -h now 无法连接总线:没有这样的文件或目录 无法与init守护程序通信。并且什么也没发生。 - Kevin Buchs
shutdown
命令与 initd
/systemd
/等等通信,而在非容器场景下,这些进程是 PID 1。但在容器中,它们不存在。同样的情况也适用于 reboot
命令。 - JakeRobbbash: shutdown: command not found
的错误提示。 - andrew lorien
ps -afx
列出进程,使用kill PIDNUMBER
(通常是kill 1
)杀死进程),这似乎也适用于Mariadb /mysqld
。 - jave.web