0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何優(yōu)雅地關(guān)閉容器

馬哥Linux運(yùn)維 ? 來(lái)源:opskumu.com ? 2023-02-01 09:21 ? 次閱讀

最近把 Docker 官方的 Docker Reference 文檔又讀了一遍,發(fā)現(xiàn)有些細(xì)節(jié)深究起來(lái),還是有很多可挖的。針對(duì)寫(xiě) Dockerfile ,大部分時(shí)候只要照葫蘆畫(huà)瓢,基本也不會(huì)有什么大的問(wèn)題,但是如果再深入理解一下那就更有意思了。

要說(shuō)如何優(yōu)雅的關(guān)閉容器,那就不得不提到信號(hào)(Signal)的理念,以及 Dockerfile 中 ENTRYPOINT 和 CMD 指令了。在具體說(shuō)優(yōu)雅關(guān)閉之前,先了解一下信號(hào)這個(gè) Linux 中的基礎(chǔ)概念。

1 信號(hào)

信號(hào)是事件發(fā)生時(shí)對(duì)進(jìn)程的通知機(jī)制,有時(shí)也稱(chēng)之為軟件中斷。

信號(hào)有不同的類(lèi)型,Linux 對(duì)標(biāo)準(zhǔn)信號(hào)的編號(hào)為 1~31,可以通過(guò) kill -l 獲取信號(hào)名稱(chēng):

#kill-l
1)SIGHUP2)SIGINT3)SIGQUIT
4)SIGILL5)SIGTRAP6)SIGABRT
7)SIGBUS8)SIGFPE9)SIGKILL
10)SIGUSR111)SIGSEGV12)SIGUSR2
13)SIGPIPE14)SIGALRM15)SIGTERM
......

實(shí)際列出的信號(hào)超過(guò)了 31 個(gè),有些是其它名稱(chēng)的同義詞,有些則是定義但未使用的。以下介紹幾個(gè)常用的信號(hào):

SIGHUP 當(dāng)終端斷開(kāi)(掛機(jī))時(shí),將發(fā)送該信號(hào)給終端控制進(jìn)程。SIGHUP 信號(hào)還可用于守護(hù)進(jìn)程(比如,init 等)。許多守護(hù)進(jìn)程會(huì)在收到 SIGHUP 信號(hào)時(shí)重新進(jìn)行初始化并重讀配置文件。

SIGINT 當(dāng)用戶(hù)鍵入終端中斷字符(通常為 Control-C ) 時(shí),終端驅(qū)動(dòng)程序?qū)l(fā)送該信號(hào)給前臺(tái)進(jìn)程組。該信號(hào)的默認(rèn)行為是終止進(jìn)程。

SIGQUIT 當(dāng)用戶(hù)在鍵盤(pán)上鍵入退出字符(通常為 Control- )時(shí),該信號(hào)將發(fā)往前臺(tái)進(jìn)程組。默認(rèn)情況下,該信號(hào)終止進(jìn)程,并生成用于調(diào)試的核心轉(zhuǎn)儲(chǔ)文件。進(jìn)程如果陷入無(wú)限循環(huán),或者不再響應(yīng)時(shí),使用 SIGQUIT 信號(hào)就很合適。

SIGKILL 此信號(hào)為 “必殺(sure kill)” 信號(hào),處理器程序無(wú)法將其阻塞、忽略或者捕獲,故而 “一擊必殺”,總能終止程序。

SIGTERM 這是用來(lái)終止進(jìn)程的標(biāo)準(zhǔn)信號(hào),也是 kill 、 killall 、 pkill 命令所發(fā)送的默認(rèn)信號(hào)。精心設(shè)計(jì)的應(yīng)用程序應(yīng)當(dāng)為 SIGTERM 信號(hào)設(shè)置處理器程序,以便其能夠預(yù)先清除臨時(shí)文件和釋放其它資源,從而全身而退。因此,總是應(yīng)該先嘗試使用 SIGTERM 信號(hào)來(lái)終止進(jìn)程,而把 SIGKILL 作為最后手段,去對(duì)付那些不響應(yīng) SIGTERM 信號(hào)的失控進(jìn)程。

SIGTSTP 這是作業(yè)控制的停止信號(hào),當(dāng)用戶(hù)在鍵盤(pán)上輸入掛起字符(通常為 Control-Z )時(shí),將該信號(hào)給前臺(tái)進(jìn)程組,使其停止運(yùn)行。

值得注意的是, Control-D 不會(huì)發(fā)起信號(hào),它表示 EOF(End-Of-File),關(guān)閉標(biāo)準(zhǔn)輸入(stdin)管道(比如可以通過(guò) Control-D 退出當(dāng)前 shell)。如果程序不讀取當(dāng)前輸入的話(huà),是不受 Control-D 影響的。

程序可以針對(duì)信號(hào)捕捉,然后執(zhí)行相應(yīng)函數(shù):

7234d2c0-a1b2-11ed-bfe3-dac502259ad0.png

以上知識(shí)大部分都來(lái)自 《Linux/UNIX 系統(tǒng)編程手冊(cè)》,想要了解更多的,可以查看該書(shū)上冊(cè)的 20、21、22 章節(jié)。

2 ENTRYPOINT 、 CMD

可能有人會(huì)問(wèn),說(shuō)了半天,那信號(hào)和優(yōu)雅的關(guān)閉容器有半毛錢(qián)的關(guān)系?。吭?huà)說(shuō),這和錢(qián)確實(shí)沒(méi)關(guān)系,但是和如何優(yōu)雅關(guān)閉容器卻關(guān)系密切。

接著說(shuō) Dockerfile 中的 ENTRYPOINT 和 CMD 指令,它們的主要功能是指定容器啟動(dòng)時(shí)執(zhí)行的程序。

CMD 有三種格式:

CMD ["executable","param1","param2"] (exec 格式, 推薦使用這種格式)

CMD ["param1","param2"] (作為 ENTRYPOINT 指令參數(shù)

CMD command param1 param2 (shell 格式,默認(rèn) /bin/sh -c )

ENTRYPOINT 有兩種格式:

ENTRYPOINT ["executable", "param1", "param2"] (exec 格式,推薦優(yōu)先使用這種格式)

ENTRYPOINT command param1 param2 (shell 格式)

其中,不管你 Dockerfile 用其中哪個(gè)指令,兩個(gè)指令都推薦使用 exec 格式,而不是 shell 格式。原因就是因?yàn)槭褂?shell 格式之后,程序會(huì)以 /bin/sh -c 的子命令啟動(dòng),并且 shell 格式下不會(huì)傳遞任何信號(hào)給程序。這也就導(dǎo)致,在 docker stop 容器的時(shí)候,以這種格式運(yùn)行的程序捕捉不到發(fā)送的信號(hào),也就談不上優(yōu)雅的關(guān)閉了。

?~dockerstop--help

Usage:dockerstop[OPTIONS]CONTAINER[CONTAINER...]

Stoponeormorerunningcontainers

Options:
--helpPrintusage
-t,--timeintSecondstowaitforstopbeforekillingit(default10)

docker stop 停掉容器的時(shí)候,默認(rèn)會(huì)發(fā)送一個(gè) SIGTERM 的信號(hào),默認(rèn) 10s 后容器沒(méi)有停止的話(huà),就 SIGKILL 強(qiáng)制停止容器。通過(guò) -t 選項(xiàng)可以設(shè)置等待時(shí)間。

?~dockerkill--help

Usage:dockerkill[OPTIONS]CONTAINER[CONTAINER...]

Killoneormorerunningcontainers

Options:
--helpPrintusage
-s,--signalstringSignaltosendtothecontainer(default"KILL")

通過(guò) docker kill的-s選項(xiàng)還可以指定給容器發(fā)送的信號(hào)。

所以,說(shuō)了那么多,只要 Dockerfile 中通過(guò) exec 格式執(zhí)行容器啟動(dòng)命令就相安無(wú)事了?那當(dāng)然是,沒(méi)有那么簡(jiǎn)單的了,接下來(lái)我們通過(guò)實(shí)例來(lái)看看具體的效果是怎么樣的。

3 實(shí)例

通過(guò) Go 寫(xiě)一個(gè)簡(jiǎn)單的信號(hào)處理器:

?~catsignals.go
packagemain

import(
"fmt"
"os"
"os/signal"
"syscall"
)

funcmain(){
sigs:=make(chanos.Signal,1)
done:=make(chanbool,1)

signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)

gofunc(){
sig:=<-sigs
????????fmt.Println()
????????fmt.Println(sig)
????????done?<-?true
????}()

????fmt.Println("awaiting?signal")
????<-done
????fmt.Println("exiting")
}

3.1 實(shí)例 1

?~GOOS=linuxGOARCH=amd64gobuildsignals.go
?~ls
Dockerfilesignalssignals.go
?~catDockerfile
FROMbusybox

COPYsignals/signals

CMD["/signals"]#exec格式執(zhí)行
?~dockerbuild-tsignals.

通過(guò) tmux 開(kāi)啟兩個(gè)面板,一個(gè)運(yùn)行容器,一個(gè)執(zhí)行 docker stop :

?~dockerrun-it--rm--namesignalssignals
awaitingsignal

terminated
exiting
?~timedockerstopsignals
signals
dockerstopsignals0.01suser0.02ssystem4%cpu0.732total
?~

可以發(fā)現(xiàn),容器停止之前,程序接收到信號(hào)并輸出相應(yīng)信息,并且停止總耗時(shí)為 0.732 s,達(dá)到了優(yōu)雅的效果。

修改 Dockerfile 中 CMD 執(zhí)行格式,執(zhí)行相同操作:

?~catDockerfile
FROMbusybox

COPYsignals/signals

CMD/signals#shell格式執(zhí)行
?~dockerbuild-tsignals.
?~dockerrun-it--rm--namesignalssignals
awaitingsignal
?~
?~timedockerstopsignals
signals
dockerstopsignals0.01suser0.01ssystem0%cpu10.719total

通過(guò) shell 格式之后,可以發(fā)現(xiàn)容器停止之前,程序并未接收到任何信號(hào),并且停止時(shí)間為 10.719s,說(shuō)明該容器是被強(qiáng)制停止的。

結(jié)論很明顯,為了優(yōu)雅的退出容器,我們應(yīng)該采用 exec 這種格式。

3.2 實(shí)例 2

通過(guò)實(shí)例 1 我們都會(huì)在 Dockerfile 中都會(huì)通過(guò) exec 這種格式來(lái)執(zhí)行程序了,那如果執(zhí)行的程序本身也是一個(gè) shell 腳本呢?

?~ls
Dockerfilesignalssignals.gostart.sh
?~catDockerfile
FROMbusybox

COPYsignals/signals
COPYstart.sh/start.sh#引入shell腳本啟動(dòng)

CMD["/start.sh"]
?~catstart.sh
#!/bin/sh

/signals
?~

測(cè)試依然引用實(shí)例 1 中的方法:

?~dockerrun-it--rm--namesignalssignals
awaitingsignal
?~
?~timedockerstopsignals
signals
dockerstopsignals0.01suser0.02ssystem0%cpu10.765total
?~

可以發(fā)現(xiàn),即使 Dockerfile 中的 CMD 指令使用的是 exec 格式,容器中的程序依然沒(méi)有接收到信號(hào),最后被強(qiáng)制關(guān)閉。因?yàn)?shell 腳本中執(zhí)行的原因,導(dǎo)致信號(hào)依然沒(méi)有被傳遞,我們需要針對(duì) shell 腳本做一些改造:

?~catstart.sh
#!/bin/sh

exec/signals#加入exec執(zhí)行
?~dockerbuild-tsignals.
?~dockerrun-it--rm--namesignalssignals
awaitingsignal

terminated
exiting
?~timedockerstopsignals
signals
dockerstopsignals0.02suser0.02ssystem4%cpu0.744total
?~

可以看到,加入 exec 命令之后,程序又可以接收到信號(hào)正常退出了。當(dāng)然,如果你 Dockerfile 中的 CMD 是以 shell 格式運(yùn)行的,即使啟動(dòng)腳本中加入 exec 也是無(wú)效的。再者,如果你的程序本身不能針對(duì)信號(hào)做一些處理,也就談不上優(yōu)雅關(guān)閉了。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11215

    瀏覽量

    208748
  • 信號(hào)
    +關(guān)注

    關(guān)注

    11

    文章

    2773

    瀏覽量

    76548
  • 容器
    +關(guān)注

    關(guān)注

    0

    文章

    492

    瀏覽量

    22028
  • 命令
    +關(guān)注

    關(guān)注

    5

    文章

    678

    瀏覽量

    21966
  • Docker
    +關(guān)注

    關(guān)注

    0

    文章

    454

    瀏覽量

    11798

原文標(biāo)題:如何優(yōu)雅地關(guān)閉容器

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    200.200 尚硅谷 SparkStreaming 優(yōu)雅關(guān)閉 恢復(fù)數(shù)據(jù)

    數(shù)據(jù)庫(kù)
    充八萬(wàn)
    發(fā)布于 :2023年07月18日 09:25:47

    神舟優(yōu)雅U10R上網(wǎng)本 參考價(jià)格:2499元

    推薦產(chǎn)品:神舟優(yōu)雅U10R上網(wǎng)本  參考價(jià)格:2499元神舟 優(yōu)雅U10R神舟 優(yōu)雅U10R僅重1.15kg 輕盈生活隨處可得   優(yōu)雅U10R采用10.1寸超輕薄靚麗LED
    發(fā)表于 07-01 22:30

    熱門(mén)低價(jià)3G上網(wǎng)本推薦 神舟優(yōu)雅U20Y 參考售價(jià):2399元

    獲得了補(bǔ)貼,含上網(wǎng)自費(fèi)套餐的3G上網(wǎng)本價(jià)格上并不比沒(méi)有3G功能的上網(wǎng)本高。因此在有補(bǔ)貼的情況,今年購(gòu)買(mǎi)還是比較劃算的。下面我們就一起看看具體的情況?! ∩裰?b class='flag-5'>優(yōu)雅U20Y  參考售價(jià):2399元(不含
    發(fā)表于 07-02 09:03

    Spark Streaming的offset管理和關(guān)閉策略

    Spark Streaming優(yōu)雅關(guān)閉策略?xún)?yōu)化
    發(fā)表于 04-22 14:59

    如何優(yōu)雅地完成倒計(jì)時(shí)定時(shí)器自適應(yīng)顯示呢

    如何實(shí)現(xiàn)倒計(jì)時(shí)的基本功能呢?如何優(yōu)雅地完成倒計(jì)時(shí)定時(shí)器自適應(yīng)顯示呢?
    發(fā)表于 10-27 07:15

    磁通電容器的資料分享

    更多的絲印藝術(shù)。再次感謝 pcb 方式,一塊板已完全組裝,我編寫(xiě)了代碼讓燈閃爍以模仿通量電容器動(dòng)畫(huà)。該按鈕目前沒(méi)有做任何事情,但我打算用它來(lái)打開(kāi)和關(guān)閉 LED,或者啟用其他類(lèi)型的動(dòng)畫(huà)。 LED 在日光下非常明亮,并具有溫暖的黃色/橙色。PCB
    發(fā)表于 07-13 07:50

    利用golang優(yōu)雅的實(shí)現(xiàn)單實(shí)例分享

    1、利用golang優(yōu)雅的實(shí)現(xiàn)單實(shí)例平時(shí)編寫(xiě)代碼過(guò)程中,經(jīng)常會(huì)遇到對(duì)于全局角度只需運(yùn)行一次的代碼,比如全局初始化操作,設(shè)計(jì)模式中的單例模式。針對(duì)單例模式,java中又出現(xiàn)了餓漢模式、懶漢模式,再配
    發(fā)表于 10-17 16:46

    經(jīng)驗(yàn)分享|BI數(shù)據(jù)可視化報(bào)表布局——容器

    設(shè)置。2、放大容器點(diǎn)擊右側(cè)的【專(zhuān)有】,將看到一個(gè)【允許放大容器】的開(kāi)關(guān)。這是一個(gè)什么功能?關(guān)閉該開(kāi)關(guān),表示可以放大容器以及容器內(nèi)的圖表;開(kāi)啟
    發(fā)表于 03-15 17:10

    如何通過(guò)ESP模塊打開(kāi)/關(guān)閉樹(shù)莓派GPIO電路?

    如何通過(guò)ESP模塊打開(kāi)/關(guān)閉樹(shù)莓派GPIO電路?樹(shù)莓派作為優(yōu)雅的電源開(kāi)/關(guān)功能。您只需關(guān)閉 Pi Pin 5 (BCM 3) GPIO 到 GND。只要您在 Pi OS 中完成了一些軟件配置,這就
    發(fā)表于 05-15 06:13

    華為nfc怎么關(guān)閉

    華為手機(jī)的NFC功能默認(rèn)的是開(kāi)啟,如果不喜歡,可以選擇關(guān)閉。華為nfc關(guān)閉的步驟的如下:
    的頭像 發(fā)表于 02-28 14:02 ?6.6w次閱讀

    容器充電和放電的工作原理

    容器剛接入電路(本來(lái)不帶電),開(kāi)關(guān)閉合,充電,一會(huì)兒后由不帶電量變得帶電。
    發(fā)表于 06-22 09:45 ?1.5w次閱讀

    單片機(jī)優(yōu)雅的開(kāi)發(fā)Clion環(huán)境搭建

    單片機(jī)優(yōu)雅的開(kāi)發(fā)Clion環(huán)境搭建
    發(fā)表于 11-13 12:21 ?20次下載
    單片機(jī)<b class='flag-5'>優(yōu)雅</b>的開(kāi)發(fā)Clion環(huán)境搭建

    Tokio 模塊的優(yōu)雅停機(jī)機(jī)制

    在進(jìn)行高并發(fā)、網(wǎng)絡(luò)編程時(shí),優(yōu)雅停機(jī)是一個(gè)非常重要的問(wèn)題。在 Rust 語(yǔ)言中,Tokio 是一個(gè)非常流行的異步編程框架,它提供了一些優(yōu)雅停機(jī)的機(jī)制,本文將圍繞 Tokio 模塊的優(yōu)雅停機(jī)進(jìn)行詳細(xì)
    的頭像 發(fā)表于 09-19 15:26 ?569次閱讀

    linux關(guān)閉docker的命令

    在 Linux 系統(tǒng)中,關(guān)閉 Docker 的操作可以通過(guò)以下多種方式進(jìn)行。本文將詳細(xì)講解每一種方式,并提供示例代碼和命令,以幫助讀者更好地理解和實(shí)踐。 使用 docker 命令 最常用的方法
    的頭像 發(fā)表于 11-23 09:39 ?2708次閱讀

    優(yōu)雅停機(jī)是什么?SpringBoot+Nacos+k8s實(shí)現(xiàn)優(yōu)雅停機(jī)

    優(yōu)雅停機(jī)是什么?網(wǎng)上說(shuō)的優(yōu)雅下線、無(wú)損下線,都是一個(gè)意思。
    的頭像 發(fā)表于 02-20 10:00 ?1834次閱讀
    <b class='flag-5'>優(yōu)雅</b>停機(jī)是什么?SpringBoot+Nacos+k8s實(shí)現(xiàn)<b class='flag-5'>優(yōu)雅</b>停機(jī)