從乙個例項,一窺docker程序管理

2021-09-11 14:57:46 字數 2771 閱讀 1427

在docker中,程序管理的基礎是linux核心的pid命名空間技術。在不同的pid命名空間下,可以有相同的pid。

linux核心為所有的pid命名空間維護了乙個樹狀的資料結構,最頂層是系統初始化時建立的root namespace(根命名空間), 父節點可以看到子節點中的程序,並可以通過訊號等方式對子節點中的程序產生影響。反過來,子節點不能看到父節點名空間中的任何內容,也不可能通過kill或ptrace影響父節點或其他名空間中的程序。

在docker中有乙個很特殊的程序——pid為1的程序,這也是docker的主程序,通過dockerfile中的 entrypoint 和/或 cmd指令指定。當主程序退出的時候,容器所擁有的pig命名空間就會被銷毀,容器的生命週期也會結束docker最佳實踐建議的是乙個container乙個service,並不強制要你乙個container乙個執行緒。有的服務,會催生更多的子程序,比如apache和uwsgi,這是完全ok的。

pid1程序需要對自己建立的子程序負責,當主程序沒有設計好,不能優雅地讓子程序退出,就會照成很多問題,比如資料庫container,如果處理資料的程序沒有優雅地退出,可能會照成資料丟失。如果很不幸,你的主程序就是這種管理不了子程序的那種,docker提供了乙個小工具,幫助你來完成這部分內容。你只需要在run建立container的時候提供乙個—init flag就行,docker就會手動為你處理好這些問題。

在docker中,對於cmd和 entrypoint,支援兩種程序執行方式:exec和shell。

shell的格式是:

cmd "executable param1 param2"

複製**

最終pid1程序將是: /bin/sh -c 」executable param1 param2」

exec的格式是:

cmd ["executable","param1","param2"]

複製**

最終的pid1程序是: executable param1 param2

現在有兩個映象,dockerfile分別如下:

from ubuntu:14.04

runapt-get update && apt-get -y install redis-server && rm -rf /var/lib/apt/lists/*

expose

6379

cmd"/usr/bin/redis-server"

複製**

from ubuntu:14.04

runapt-get update && apt-get -y install redis-server && rm -rf /var/lib/apt/lists/*

expose

6379

cmd["/usr/bin/redis-server"]

複製**

docker run -d --name myredis1 redis:shell

docker run -d --name myredis2 redis:exec

複製**

那個docker映象更好一點呢?

我們前面講過,pid1程序(主程序)需要對自己的子程序負責,對於redis:shell,它產生的pid1程序是

/bin/sh -c "/usr/bin/redis-server"

複製**

也就是說,是/bin/sh這個程序,不是/usr/bin/redis-server!/usr/bin/redis-server只是它建立的乙個子程序!

執行命令

docker exec myredis1 ps -ef

複製**

可以驗證這種猜測

通過exec方式執行的container的主程序則是我們所期望的。

你可能會覺得,這有什麼大不了的呢,問題出現當我們停止container的時候。

docker stop myredis1

docker logs myredis1

複製**

stop的時候,docker明顯停頓了一段時間,而且檢視日誌可以看出,redis沒有做任何儲存資料庫的操作,直接被強制退出了。這期間發生了什麼?首先,執行stop命令會向容器傳送 sigterm訊號,告訴主程序:你該退出了,感覺收拾收拾。但是,這裡的主程序是/bin/sh啊,它怎麼可能會有處理redis程序退出的機制?所以redis程序不會馬上退出。 docker daemon等待一段時間之後(預設是10s),發現容器還沒有完全退出,這時候就會傳送 sigkill,將容器強行殺死。在這過程中,redis程序完全不知道自己該退出了,所以他沒有做任何收尾的工作。

docker stop myredis2

docker logs myredis2

複製**

這一次stop的時候是立即生效了,沒有卡頓延遲現象,從輸出來看,redis進行了shutdown的操作,把該持久化的資料都儲存到磁碟了。因為這時候的pid1程序是

/usr/bin/redis-server

複製**

它是能夠正確處理sigterm訊號的。這才是我們所期望的。

docker的主程序(pid1程序)是乙個很特殊的存在,它的生命週期就是docker container的生命週期,它得對產生的子程序負責,在寫dockerfile的時候,務必明確pid1程序是什麼。

從乙個例項學習 FLASK WTF

本案例通過實現乙個註冊頁面的編寫,來帶你了解flask wtf的運用.主要功能為表單基礎的功能 手機號碼必須為11位數,且通過資料庫查詢不能有已經註冊的了,密碼要求輸入兩遍且必須一樣,且所有內容不能為空的提示等內容.那麼現在就開始把 一.建立表單類.首先運用flask wtf你必須確保你的環境中已經...

從乙個例項中學習DTW演算法

dtw為 dynamic time warping,動態時間歸準 的簡稱。應用很廣,主要是在模板匹配中,比如說用在孤立詞語音識別,計算機視覺中的行為識別,資訊檢索等中。可能大家學過這些類似的課程都看到過這個演算法,公式也有幾個,但是很抽象,當時看懂了但不久就會忘記,因為沒有具體的例項來加深印象。這次...

程序只執行乙個例項

守護程序往往需要設定使其只執行乙個例項,這裡展示檔案鎖的方式實現 1.使用fcntl 函式設定檔案鎖 include include include include include include include int main else pause return 0 2.使用flock 設定鎖 ...