一個實驗

一個實驗

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 ...有些事情將會發生:

  1. docker發送 aSIGTERM到容器的主程序。該進程能夠屏蔽/忽略 a SIGTERM,如果它這樣做(或在不終止的情況下處理它)”沒有什麼「將會發生。
  2. 逾時(預設 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}.


此訊號行為不同的原因是由於sleepPID = 1 的運作。

通常(例如:使用 PID != 1 運行),任何在進程未明確處理的訊號都會導致進程被終止 - 嘗試發送sleepa 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.後台處理和waiting 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 作為某種正常操作使用。

相關內容