詳解如何在 docker 容器中捕獲訊號

2021-08-14 11:50:39 字數 3205 閱讀 3897

訊號(linux)

訊號是一種程序間通訊的形式。乙個訊號就是核心傳送給程序的乙個訊息,告訴程序發生了某種事件。當乙個訊號被傳送給乙個程序後,程序會立即中斷當前的執行流並開始執行訊號的處理程式。如果沒有為這個訊號指定處理程式,就執行預設的處理程式。

程序需要為自己感興趣的訊號註冊處理程式,比如為了能讓程式優雅的退出(接到退出的請求後能夠對資源進行清理)一般程式都會處理 sigterm 訊號。與 sigterm 訊號不同,sigkill 訊號會粗暴的結束乙個程序。因此我們的應用應該實現這樣的目錄:捕獲並處理 sigterm 訊號,從而優雅的退出程式。如果我們失敗了,使用者就只能通過 sigkill 訊號這一終極手段了。除了 sigterm 和 sigkill ,還有像 sigusr1 這樣的專門支援使用者自定義行為的訊號。下面的**簡單的說明在 nodejs 中如何為乙個訊號註冊處理程式:

process.on('sigterm', function() );
關於訊號的更多資訊,筆者在《linux kill 命令》一文中有所提及,這裡不再贅述。

容器中的訊號

docker 的 stop 和 kill 命令都是用來向容器傳送訊號的。注意,只有容器中的 1 號程序能夠收到訊號,這一點非常關鍵!

stop 命令會首先傳送 sigterm 訊號,並等待應用優雅的結束。如果發現應用沒有結束(使用者可以指定等待的時間),就再傳送乙個 sigkill 訊號強行結束程式。

kill 命令預設傳送的是 sigkill 訊號,當然你可以通過 -s 選項指定任何訊號。

});這個應用是乙個 http 伺服器,監聽埠 3000,為 sigint 和 sigterm 訊號註冊了處理程式。接下來我們將介紹以不同的方式在容器中執行程式時訊號的處理情況。

應用程式作為容器中的 1 號程序

建立 dockerfile 檔案,把上面的應用打包到映象中:

from iojs:onbuild

copy ./package.json ./package.json

expose 3000

請注意 entrypoint 指令的寫法,這種寫法會讓 node 在容器中以 1 號程序的身份執行。

接下來建立映象:

然後啟動容器執行應用程式:

此時 node 應用在容器中的程序號為 1:

現在我們讓程式退出,執行命令:

此時應用會以我們期望的方式退出:

應用程式不是容器中的 1 號程序

#!/usr/bin/env bash

然後建立 dockerfile1 檔案,內容如下:

from iojs:onbuild

copy ./package.json ./package.json

expose 3000

接下來建立映象:

然後啟動容器執行應用程式:

此時 node 應用在容器中的程序號不再是 1:

我們可以通過:

# or

退出應用,它們最終都是向容器中的 1 號程序傳送了 sigkill 訊號。很顯然這不是我們期望的,我們希望程式能夠收到 sigterm  訊號優雅的退出。

在指令碼中捕獲訊號

#!/usr/bin/env bash

set -x

pid=0

# sigusr1-handler

my_handler()

# sigterm-handler

term_handler()

# setup handlers

# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler

trap 'kill $; my_handler' sigusr1

trap 'kill $; term_handler' sigterm

pid="$!"

# wait forever

while true

do tail -f /dev/null & wait $

done

這個指令碼檔案在啟動應用程式的同時可以捕獲傳送給它的 sigterm 和 sigusr1 訊號,並為它們新增了處理程式。其中 sigterm 訊號的處理程式就是向我們的 node 應用程式傳送 sigterm 訊號。

然後建立 dockerfile2 檔案,內容如下:

from iojs:onbuild

copy ./package.json ./package.json

expose 3000

接下來建立映象:

然後啟動容器執行應用程式:

此時 node 應用在容器中的程序號也不是 1,但是它卻可以接收到 sigterm 訊號並優雅的退出了:

結論

容器中的 1 號程序是非常重要的,如果它不能正確的處理相關的訊號,那麼應用程式退出的方式幾乎總是被強制殺死而不是優雅的退出。究竟誰是 1 號程序則主要由 entrypoint, cmd, run 等指令的寫法決定,所以這些指令的使用是很有講究的。

如何在docker容器中啟jupyter

docker h 0.0.0.0 run it rm p 18888 8888 v pwd dump data root dump data harbor.atompai.com nitrogen xdock v1 bin bash設定密碼 pip install jupyter啟動容器 docke...

如何在Docker容器中執行GUI程式

各位,今天我們將學習如何在docker之中執行gui程式。我們可以輕易地在docker容器中執行大多數gui程式且不出錯。docker是乙個開源專案,提供了乙個打包 分發和執行任意程式的輕量級容器的開放平台。它沒有語言支援 框架或者打包系統的限制,並可以執行在任何地方 任何時候,從小型的家用電腦到高...

如何在Docker容器中執行GUI程式

各位,今天我們將學習如何在docker 之中執行gui程式。我們可以輕易地在 docker容器中執行大多數gui程式且不出錯。docker是乙個開源專案,提供了乙個打包 分發和執行任意程式的輕量級容器的開放平台。它沒有語言 支援 框架或者打包系統的限制,並可以執行在任何地方 任何時候,從小型的家用電...