
sleep
當然,它是最複雜流程的替代品。
這個 Dockerfile(如您所看到的,使用 exec 形式,因此只有一個進程正在運行,並且沒有子進程bash
):
FROM busybox
CMD ["/bin/sleep", "100000"]
創造一個不間斷的容器:
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
當我試圖阻止它時:
time docker stop kill-sleep
kill-sleep
real 0m10.449s
user 0m0.021s
sys 0m0.027s
該命令在容器被終止前 10 秒逾時。
問題不在於sleep
不處理訊號,因為如果我在主機上運行它:
sleep 100000
# in another shell
ps faxww | grep sleep
kill -TERM 31333 # the PID
該過程立即停止。
這個問題可能與它在容器中作為 PID 1 運行這一事實有關,但我還沒有看到這方面的參考文件。
答案1
當你跑步時docker stop ...
,有些事情將會發生:
docker
發送 aSIGTERM
到容器的主程序。該進程能夠屏蔽/忽略 aSIGTERM
,如果它這樣做(或在不終止的情況下處理它)”沒有什麼「將會發生。- 逾時(預設 10 秒)後,向主進程
docker
發送 a 。SIGKILL
該訊號不能被進程屏蔽,因此它會立即終止,沒有機會執行關閉程序。
理想情況下,其中運行的進程將及時docker
回應,在終止之前處理所有內務處理工作。SIGTERM
如果您知道該進程沒有執行任何內務處理(例如:sleep
),或者不會正確回應SIGTERM
,您可以使用以下標誌指定更短(或更長)的逾時-t
:
-t, --time=10 Seconds to wait for stop before killing it
例如,在您的情況下,您可能想運行docker stop -t 0 ${CONTAINER}
.
此訊號行為不同的原因是由於sleep
PID = 1 的運作。
通常(例如:使用 PID != 1 運行),任何在進程未明確處理的訊號都會導致進程被終止 - 嘗試發送sleep
a SIGUSR1
。
但是,當以 PID = 1 運行時,未處理的訊號將被忽略,否則最終會出現核心恐慌:
Kernel panic - not syncing: Attempted to kill init!
您可以使用 docker 工具向 docker 容器發送訊號,例如:
docker kill -s TERM kill-sleep
正如我們所看到的,這並沒有達到預期的效果,而這樣可以:
docker kill -s KILL kill-sleep
一個實驗
Dockerfile
FROM busybox
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD "/run.sh"
運行sh
#!/bin/sh
echo "sleeping"
sleep 100000
現在,運行
docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep
這是在不同的終端機中:
docker stop kill-sleep
我們觀察到同樣的 10 秒延遲/逾時。
一個辦法
現在讓我們來處理SIGTERM
.後台處理和wait
ing forsleep
是由 POSIX shell 處理訊號的方式決定的(請參閱這了解更多)。
運行sh
#!/bin/sh
die_func() {
echo "oh no"
sleep 2
exit 1
}
trap die_func TERM
echo "sleeping"
sleep 100000 &
wait
再次運行命令,我們就可以看到我們想要的結果了!
$ time docker stop kill-sleep
kill-sleep
real 0m2.515s
user 0m0.008s
sys 0m0.044s
答案2
更多選項:
- 將開關加入
--init
容器運行命令中。這樣,sleep 就不是 PID 1,而且 init 在 TERM 上執行正確的操作。 - 新增
--stop-signal=KILL
到容器運行命令。然而,通常不鼓勵將 KILL 作為某種正常操作使用。