我有一个在docker容器中运行的cronjob,它检查所有服务是否按预期运行。如果这个cronjob确定有问题,我想停止docker容器(从内部...)不幸的是,exit只是停止了我的cronjob脚本
exit
l7wslrjt1#
基本上,您需要PID 1退出以停止容器。执行kill -s SIGKILL 1将不起作用,因为PID 1受到保护。正如@Thomasleveil所建议的那样,您可以将trap "exit" SIGINT SIGTERM这样的代码添加到PID 1脚本中,这意味着当发送kill -s SIGINT 1时,进程将退出。比起你提出的方法(直接杀死子进程),我更喜欢这个方法,因为它给了父进程一个清理的机会,而且父进程应该能够在没有awk的情况下找到子进程的PID。处理这个问题最简单的方法是使用某种监督进程,Docker现在方便地提供了一个名为“tini”的进程。只需运行add参数--init to docker run,Docker就会将tini设置为容器中的PID 1。完整的描述在这里:https://docs.docker.com/engine/reference/run/#specify-an-init-process
kill -s SIGKILL 1
trap "exit" SIGINT SIGTERM
kill -s SIGINT 1
--init
docker run
nafvub8i2#
我遇到了同样的问题,我通过使用docker的healthcheck功能解决了它。您可以在heahthcheck.sh这样的文件中添加检查以验证您的服务。然后在Dockerfile中添加如下内容:
heahthcheck.sh
Dockerfile
# HealthcheckCOPY healthcheck.sh /RUN chmod +x /healthcheck.shHEALTHCHECK --interval=10s --retries=5 CMD /healthcheck.sh
# 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
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autoheal
型这将在每次容器状态变得不健康时重新启动容器。
2ul0zpep3#
我最近不得不弄清楚这一点。在经历了很多挫折之后,我最终想到了这个:在dockerfile中,指定一个ENTRYPOINT:
ENTRYPOINT ["/entrypoint.sh"]
字符串然后,提供这样的脚本。除了调用应用程序之外,它不需要做任何事情。您可以随意向脚本添加其他设置,但要注意,如果脚本在调用应用程序后执行了任何操作,它可能会屏蔽应用程序的返回代码。如果这与您相关,请确保让脚本捕获返回代码并将其作为自己的返回代码传播出去。
exec
结果将是PID 1属于entrypoint.sh,而您的应用程序将具有其他PID。我的倾向于落在PID 9或10上。然后,当需要终止应用程序时,只需确定其PID并调用kill -SIGKILL $PID或pkill -SIGKILL yourapp。你的进程,不是PID 1,将收到信号并立即退出。您的entrypoint.sh将立即退出,因为这是您设计的在流程退出后执行的操作。
kill -SIGKILL $PID
pkill -SIGKILL yourapp
entrypoint.sh
mlnl4t2r4#
来自@JakeRobb的灵感:你可以使用以下命令执行docker:
/bin/bash -c "while true; do sleep infinity || exit 0; done"
字符串这将在低于1的PID上执行休眠。一旦你杀了它,循环就会退出。为此,在docker中用途:
pkill -f sleep
型
uajslkp65#
/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 yourselfTHE_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....
#!/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
exit $?
fi
(sleep 300; echo "Killing process: $THE_PID"; kill -9 $THE_PID) &
YOUR_SCRIPT_TEXT....
字符串
owfi6suc6#
我杀死了“阻塞过程”,即。docker正在运行的主进程;像这样(在这种情况下,docker正在运行一个sleep infinity命令,用于演示目的)。ps-afx| grep睡眠|awk '{print $1}'| xargs kill-9
qgelzfjb7#
我试图杀死进程1,但没有成功。给予用shutdown -h now评论@zero323。它工作正常(对不起,我不能直接投票给它,因为它不在答案列表中)。
shutdown -h now
7条答案
按热度按时间l7wslrjt1#
基本上,您需要PID 1退出以停止容器。
执行
kill -s SIGKILL 1
将不起作用,因为PID 1受到保护。正如@Thomasleveil所建议的那样,您可以将
trap "exit" SIGINT SIGTERM
这样的代码添加到PID 1脚本中,这意味着当发送kill -s SIGINT 1
时,进程将退出。比起你提出的方法(直接杀死子进程),我更喜欢这个方法,因为它给了父进程一个清理的机会,而且父进程应该能够在没有awk的情况下找到子进程的PID。处理这个问题最简单的方法是使用某种监督进程,Docker现在方便地提供了一个名为“tini”的进程。只需运行add参数
--init
todocker run
,Docker就会将tini设置为容器中的PID 1。完整的描述在这里:https://docs.docker.com/engine/reference/run/#specify-an-init-processnafvub8i2#
我遇到了同样的问题,我通过使用docker的healthcheck功能解决了它。
您可以在
heahthcheck.sh
这样的文件中添加检查以验证您的服务。然后在Dockerfile
中添加如下内容:字符串
这可以确保docker通过在指定的时间间隔内运行脚本来检查容器的健康状况,如果它连续失败5次,它会标记状态不健康。
现在,为了在状态不正常时重启容器,可以像这样使用autoheal:
型
这将在每次容器状态变得不健康时重新启动容器。
2ul0zpep3#
我最近不得不弄清楚这一点。在经历了很多挫折之后,我最终想到了这个:
在dockerfile中,指定一个ENTRYPOINT:
字符串
然后,提供这样的脚本。除了调用应用程序之外,它不需要做任何事情。您可以随意向脚本添加其他设置,但要注意,如果脚本在调用应用程序后执行了任何操作,它可能会屏蔽应用程序的返回代码。如果这与您相关,请确保让脚本捕获返回代码并将其作为自己的返回代码传播出去。
exec
来调用你的应用程序!*结果将是PID 1属于entrypoint.sh,而您的应用程序将具有其他PID。我的倾向于落在PID 9或10上。
然后,当需要终止应用程序时,只需确定其PID并调用
kill -SIGKILL $PID
或pkill -SIGKILL yourapp
。你的进程,不是PID 1,将收到信号并立即退出。您的entrypoint.sh
将立即退出,因为这是您设计的在流程退出后执行的操作。mlnl4t2r4#
来自@JakeRobb的灵感:你可以使用以下命令执行docker:
字符串
这将在低于1的PID上执行休眠。一旦你杀了它,循环就会退出。为此,在docker中用途:
型
uajslkp65#
/usr/local/bin/docker-entrypoint.sh
字符串
owfi6suc6#
我杀死了“阻塞过程”,即。docker正在运行的主进程;像这样(在这种情况下,docker正在运行一个sleep infinity命令,用于演示目的)。
ps-afx| grep睡眠|awk '{print $1}'| xargs kill-9
qgelzfjb7#
我试图杀死进程1,但没有成功。
给予用
shutdown -h now
评论@zero323。它工作正常(对不起,我不能直接投票给它,因为它不在答案列表中)。