Kubernetes 之淺析 Pod

一. 爲什麼需要 Pod

在一個 Linux 操作系統中,進程是以進程組的方式組織在一起的,即一個或多個進程的集合,一方面是一些進程之前存在密切的關係,更重要的一點是方便管理。

而容器的本質實際上就是進程,經過了隔離,限制等一系列操作之後形成了一個獨立的容器,那麼 K8s 則類似於操作系統。因此同樣地,K8s 也採用了 Linux 中進程組的思想,去組織其中的進程——即容器。Pod 的出現就是爲了處理那些存在着密切協作關係的,需要部署在同一臺機器上的應用的運維問題。

Pod 是 K8s 中的原子調度單位,所有 K8s 在對容器進行節點調度的時候,看的其實是一整個 Pod 而非單個容器。這也就理所當然地解決了調度的時候的資源問題,因爲 K8s 會保證同屬一個 Pod 的容器必定會在同一個節點當中,保證了應用直接的協作關係。

二. Pod 實現原理

很多地方把容器與虛擬機作對比,但其實對於容器進程和 K8s 來說,Pod 更像是運行在節點機器上的虛擬機,因爲它纔是管控其中進程的關鍵。但實際上,K8s 並沒有真正地創建一個 Pod 實體出來,Pod 一直都只是一個邏輯的概念。對於 K8s 來說,Pod 其實就是一組容器,只不過這組容器之間存在着資源共享的關係。

實際上,Pod 裏面所有的容器都共享了同一個 Network Namespace,同時也可以共享同一個數據卷。爲了達到這樣的目的,K8s 會首先創建一個 pause 容器,又叫 infra 容器,既然是首先創建的,那麼很顯然,它會作爲一個先導的作用,引導其他容器的加入,在 pause 容器被創建以後,其他容器則可以通過 Join Network Namespace 的方式,與它關聯在一起。 數據卷的話,只需要把所有的數據卷定義在 Pod 層級即可。

因爲 pause 容器的作用特殊,所以它佔用的資源非常少,使用的鏡像是 k8s.gcr.io/pause,解壓後的大小隻有 100~200 KB。而且從名字可以看出來,它是一個永遠處於暫停狀態的容器。值得注意的是,Pod 生命週期只與 pause 容器有關。

因此我們可以得知,一個 Pod 只會有一個 IP 地址,即 Network Namespace 對應的 IP 地址,裏面的容器看到的網絡設備,網絡資源也都是相同的。也因爲有 pause 容器的存在,容器的網絡配置只能跟隨 pause 容器的腳步,即是跟隨 Pod 的腳步,而不能讓容器網絡自定義爲我們自己想要的網絡配置,因爲必須保證 Pod 裏面所有容器的網絡的統一性。

三. Pod 屬性

由上述可知,我們可以把 Pod 看做一臺機器,而容器就是運行在這個機器裏面的程序。所以理所當然地,與機器相關的屬性,網絡,存儲,安全等屬性都是基於 Pod 級別的。而這些屬性,我們都可以通過編寫 YAML 文件進行自定義。

調度

調度是 K8s 中至關重要的一環,調度器會經過調度策略將 Pod 調度到理想的節點中。在 YAML 文件中,有 NodeSelector 和 NodeName 等屬性與調度息息相關。

NodeSelector 顧名思義是一種節點選擇器,經過設置可以指定該 Pod 必須調度到攜帶了規定的 Label 的節點當中。

NodeName 即節點名,當調度器設置了 NodeName,則表示該 Pod 已經完成了調度。而我們使用者也可以通過設置該屬性來讓調度器誤以爲其已經被調度過,適用於測試和調試的場景。

配置

在 YAML 文件中我們可以完成 Pod 層級的配置工作,比如我們通常會使用 HostAliases 屬性來設置 host,而不是直接去修改 hosts 文件,因爲這樣不利於 host 的持久化,當 Pod 刪除重建以後,K8s 會覆蓋掉之前直接在文件中修改的內容。

Namespace

Namespace 是與隔離密不可分的屬性,Namespace 包含了很多方面,包括網絡相關的 Network Namespace,進程相關的 PID Namespace,文件系統相關的 Mount Namespace 等。

在 K8s 中,凡是跟容器的 Linux Namespace 相關的屬性,也一定是 Pod 級別的。以便在保留必要的隔離和限制能力的同時,讓裏面的容器儘可能多地共享 Linux Namespace。例如 shareProcessNamespace 屬性可以設置該 Pod 是否共享 PID Namespace,除此之外還有 hostNetwork,hostIPC 等也是同理。

容器

Pod 裏面最重要的屬性固然是容器了,在 YAML 中,我們可以對 Pod 中的容器進行全方位的配置,包括Image(鏡像)、Command(啓動命令)、workingDir(容器的工作目錄)、Ports(容器要開發的端口)、volumeMounts(數據卷)等等。除此以外,還有諸如如 Init Containers 可以設置爲 init 容器,它的創建會先於其他所有的容器,ImagePullPolicy 定義了每次創建是否都需要重新拉取一次鏡像等字段

四. Pod 生命週期

Pod 的生命週期,即 status 屬性,包含以下:

  • Pending:代表 Pod API 對象已創建完成,但其中的容器還未被順利創建。
  • Running:表示調度完成且其中的容器至少有一個在運行中
  • Succeeded:所有容器正常運行完畢且已經退出,如一次性任務
  • Failed:其中的容器至少有一個以不正常狀態退出
  • Unknown:異常狀態,意味着 Pod 的狀態不能持續地被 kubelet 彙報給 kube-apiserver,這很有可能是主從節點間的通信出現了問題

五. 配置管理

在 K8s 中,有專門的 Projected Volume 用於配置的工作,這些 Volume 是爲容器預先定義好的數據,可以理解爲用於配置的數據卷,通過在容器中進行掛載,來訪問其中的信息。這些信息都存放於 K8s 的 Etcd 之中,因此一旦其對應的 Etcd 裏的數據被更新,這些 Volume 裏的內容,同樣也會被更新。

分爲以下兩種:

Secret

以鍵值對形式存放加密數據,如數據庫的 Credential 信息,數據需要經過 Base64 轉碼,而在真正的生產環境中,通常還需要開啓 Secret 的加密插件,以增強數據的安全性。除此之外還可以指定可用的命名空間。

ConfigMap

存放鍵值對形式的配置信息,無需加密

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章