最近看了一下 k8s 的 pause 容器,讓我重新梳理了一下 pid namespace。

pid namespace 用於隔離進程,意思就是可以用 pid namespace 對進程進行分組管理,那麼不同的進程就可以被放入不同的 namespace 分組中去。linux 系統啟動後,默認創建了第一個 namespace,此時的所有進程都位於在這個 namespace 中,所以 ps 命令才能夠查看到所有的進程。

pid namespace 是有父子嵌套關係的,當我們創建一個新的子進程的時候,完全可以同時為這個子進程分配一個新的 namespace,這個時候就會出現父子進程在不同的 namespace 中,但兩個 namespace 也是父子的嵌套關係。大概是如下這樣的一個關係:

目前,真實的容器環境一般來說只有兩層 namespace,第一層就是系統初始化默認的,第二層就是每個容器所創建的 namespace,很少有2層以上的實際場景,目前我好像還沒遇到。上圖展示的最深是 3 層。

pid namespace 隔離的是進程,是對進程進行的分組管理,這個分組隔離的具體內容其實是進程間的可見性,簡單的說就是屬於同一個 pid namespace 中的進程相互是可見的,注意這裡可見的意思是『進程之間相互可以看到對方,也可以使用 syscall 操作對方,比如發送信號等』。進程除了對相同 pid namespace 中的其他進程可見以外,其實對它的祖先 pid namespace 中的進程也是可見的,這就是為什麼我們在 linux 宿主機上 ps 可以看到所有的進程,包括每個 docker 容器中的進程,在宿主機上也可以使用 kill 命令殺死每個 docker 容器中的進程。

pid namespace 除了有進程分組隔離的作用外,還有一個大家都知道的特性,就是一個 pid namespace 中的第一個被創建的進程 pid 是 1,通常也稱這個進程為 init 進程。這個特性不難理解,一個 pid namespace 就是一個全新的、獨立的 pid 分配環境,那麼 pid 的分配自然是從 1 開始了。在 linux 系統上,1 號進程是特殊的,它不會被同 pid namespace 內的其他進程殺死,即使是 kill -9 也不行,這樣的設計是為了防止誤操作殺掉 1 號進程;但是容器內的 1 號進程是可以被父 pid namespace 中的進程殺死的,這樣一來內核將會同時殺掉整個 namespace 內的其他進程,也就說 1 號進程掛掉後,其整個 namespace 內的進程都會被內核 kill 掉。

1 號進程還有一個能力,就是能夠接管孤兒進程,成為孤兒進程的父進程。這一點很重要,否則系統里就會出現非常多的僵死進程了。

不難發現,一個進程有唯一的一個 pid 這種說法是不正確的,必須加上 pid namespace 這個維度才正確。也就是說,在一個固定的 pid namespace 內,一個進程有唯一的一個 pid,在多個 pid namespace 中,同一個進程就可能有不同的 pid 了。

基於上面的總結,再談一下 k8s pod 中的 pause 容器。設計這個 pause 容器的核心是解決 pod 中多個容器相互共享 namespace 的問題,也就是 k8s 創建 pod 的時候會先創建一個 pause 容器,然後再創建其他應用容器並將相關的 namespace 和 pause 共享。那麼,k8s 為什麼不設計成去掉 pause 容器,然後按某個順序啟動應用容器,把第一個應用容器作為標準,後面的應用容器和第一個應用容器共享 namespace 呢?這樣也是可以達到共享 namespace,實現 pod 本地通信等功能。

我認為至少有以下幾點:

1. 引入 pause 容器的設計更加優雅一點,至少遵循了一個模塊、一個組件干一件事情的原則,角色上劃分比較清晰明了。

2. k8s pod 採用多容器設計,也就是多進程設計,因此 namespace 中的第一個進程就必須足夠穩定,不會輕易退出。上文提到,1 號進程掛掉,會導致整個 namespace 的進程被內核殺死的。所以,pause 進程的源碼非常的簡單。

3. 應用容器內的進程完全有可能出現孤兒進程,這些孤兒進程最終會被 1 號進程接管,也就是成為 1 號進程的子進程,那麼最終 1 號進程就需要負責回收孤兒進程的退出狀態。如果這個 1 號進程不是 pause,而是一個應用容器內的應用進程的話,就有可能不能正常的處理退出信號回收子進程。因為,應用進程有可能並沒有處理 SIGCHLD 信號;也可能採用了特殊的邏輯去處理,而不是單純的 wait or wait_pid,比如:nginx master。

所以,k8s pod 要設計一個獨立的 pause 容器。


個人文章優先發表在『專治好奇』知識星球。

推薦閱讀:

相关文章