1. 程式人生 > >Kubernetes之POD

Kubernetes之POD

repl 共享網絡 內容 light ons cat period 之前 target

什麽是Pod

Pod是可以創建和管理Kubernetes計算的最小可部署單元。一個Pod代表著集群中運行的一個進程。

Pod就像是豌豆莢一樣,它由一個或者多個容器組成(例如Docker容器),它們共享容器存儲、網絡和容器運行配置項。Pod中的容器總是被同時調度,有共同的運行環境。你可以把單個Pod想象成是運行獨立應用的“邏輯主機”——其中運行著一個或者多個緊密耦合的應用容器——在有容器之前,這些應用都是運行在幾個相同的物理機或者虛擬機上。

盡管kubernetes支持多種容器運行時,但是Docker依然是最常用的運行時環境,我們可以使用Docker的術語和規則來定義Pod。

Pod中共享的環境包括Linux的namespace,cgroup和其他可能的隔絕環境,這一點跟Docker容器一致。在Pod的環境中,每個容器中可能還有更小的子隔離環境。

Pod中的容器共享IP地址和端口號,它們之間可以通過localhost互相發現。它們之間可以通過進程間通信,例如SystemV信號或者POSIX共享內存。不同Pod之間的容器具有不同的IP地址,不能直接通過IPC通信。

Pod中的容器也有訪問共享volume的權限,這些volume會被定義成pod的一部分並掛載到應用容器的文件系統中。

就像每個應用容器,pod被認為是臨時實體。在Pod的生命周期中,pod被創建後,被分配一個唯一的ID(UID),調度到節點上,並一致維持期望的狀態直到被終結(根據重啟策略)或者被刪除。如果node死掉了,分配到了這個node上的pod,在經過一個超時時間後會被重新調度到其他node節點上。一個給定的pod(如UID定義的)不會被“重新調度”到新的節點上,而是被一個同樣的pod取代,如果期望的話甚至可以是相同的名字,但是會有一個新的UID(查看replication controller獲取詳情)。

Pod中如何管理多個容器

Pod中可以同時運行多個進程(作為容器運行)協同工作。同一個Pod中的容器會自動的分配到同一個 node 上。同一個Pod中的容器共享資源、網絡環境和依賴,它們總是被同時調度。

註意在一個Pod中同時運行多個容器是一種比較高級的用法。只有當你的容器需要緊密配合協作的時候才考慮用這種模式。例如,你有一個容器作為web服務器運行,需要用到共享的volume,有另一個“sidecar”容器來從遠端獲取資源更新這些文件。如圖

技術分享圖片

Pod中可以共享兩種資源

  • 網絡 每個Pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網絡空間,包括IP地址和端口。Pod內部的容器可以使用localhost
    互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)。
  • 存儲 可以Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟後文件丟失。

使用Pod

我通常把pod分為兩類:

  • 自主式Pod 這種Pod本身是不能自我修復的,當Pod被創建後(不論是由你直接創建還是被其他Controller),都會被Kuberentes調度到集群的Node上。直到Pod的進程終止、被刪掉、因為缺少資源而被驅逐、或者Node故障之前這個Pod都會一直保持在那個Node上。Pod不會自愈。如果Pod運行的Node故障,或者是調度器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。
  • 控制器管理的Pod Kubernetes使用更高級的稱為Controller的抽象層,來管理Pod實例。Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod調度到其他健康的Node上。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。

技術分享圖片

上圖所示是Pod的組成示意圖,我們看到每個Pod都有一個特殊的被稱為“根容器”的Pause 容器。 Pause容器對應的鏡像屬於Kubernetes平臺的一部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的用戶業務容器。

Pod的終止

因為Pod作為在集群的節點上運行的進程,所以在不再需要的時候能夠優雅的終止掉是十分必要的(比起使用發送KILL信號這種暴力的方式)。用戶需要能夠放松刪除請求,並且知道它們何時會被終止,是否被正確的刪除。用戶想終止程序時發送刪除pod的請求,在pod可以被強制刪除前會有一個寬限期,會發送一個TERM請求到每個容器的主進程。一旦超時,將向主進程發送KILL信號並從API server中刪除。如果kubelet或者container manager在等待進程終止的過程中重啟,在重啟後仍然會重試完整的寬限期。

示例流程如下:

  1. 用戶發送刪除pod的命令,默認寬限期是30秒;
  2. 在Pod超過該寬限期後API server就會更新Pod的狀態為“dead”;
  3. 在客戶端命令行上顯示的Pod狀態為“terminating”;
  4. 跟第三步同時,當kubelet發現pod被標記為“terminating”狀態時,開始停止pod進程:1 如果在pod中定義了preStop hook,在停止pod前會被調用。如果在寬限期過後,preStop hook依然在運行,第二步會再增加2秒的寬限期;2 向Pod中的進程發送TERM信號;
  5. 跟第三步同時,該Pod將從該service的端點列表中刪除,不再是replication controller的一部分。關閉的慢的pod將繼續處理load balancer轉發的流量;
  6. 過了寬限期後,將向Pod中依然運行的進程發送SIGKILL信號而殺掉進程。
  7. Kublete會在API server中完成Pod的的刪除,通過將優雅周期設置為0(立即刪除)。Pod在API中消失,並且在客戶端也不可見。

刪除寬限期默認是30秒。 kubectl delete命令支持 --grace-period=<seconds> 選項,允許用戶設置自己的寬限期。如果設置為0將強制刪除pod。在kubectl>=1.5版本的命令中,你必須同時使用 --force 和 --grace-period=0 來強制刪除pod。

Pause 容器

在接觸Kubernetes的初期,便知道集群搭建需要下載一個gcr.io/google_containers/pause-amd64:3.0鏡像,然後每次啟動一個容器,都會伴隨一個pause容器的啟動。

但這個pause容器的功能是什麽,它是如何做出來的,以及為何都伴隨容器啟動等等。這些問題一直在我心裏,如今有緣學習相關內容。

189fbd12e903        rancher/rancher-agent:v2.0.6                                                                                           "run.sh -- share-r..."   10 days ago         Exited (0) 10 days ago                              share-mnt
[root@k8s-master ~]# docker ps -a | grep pause-amd64
f30cc4df0eff        rancher/pause-amd64:3.1                                                                                                "/pause"                 4 days ago          Up 4 days                                      k8s_POD_confserver-bdf79c8cb-xxf82_confserver_f92c3ecc-a11b-11e8-a1c4-005056936694_0
af651c01f1e4        rancher/pause-amd64:3.1                                                                                                "/pause"                 5 days ago          Up 5 days                                      k8s_POD_jenkins-5cf89c84f6-h4hs6_jenkins_954201e0-a057-11e8-a1c4-005056936694_0
7ab1920551ca        rancher/pause-amd64:3.1                                                                                                "/pause"                 10 days ago         Up 10 days                                     k8s_POD_nfs-provisioner-2cjpp_nfs-provisioner_a24395b7-9c42-11e8-a1c4-005056936694_0
4f89f1c2e83b        rancher/pause-amd64:3.1                                                                                                "/pause"                 10 days ago         Up 10 days                                     k8s_POD_cattle-node-agent-s8s75_cattle-system_a2443a27-9c42-11e8-a1c4-005056936694_0
74ff9a7eb776        rancher/pause-amd64:3.1                                                                                                "/pause"                 10 days ago         Up 10 days                                     k8s_POD_nginx-ingress-controller-gl7k6_ingress-nginx_a239056d-9c42-11e8-a1c4-005056936694_0
76a3177f05ec        rancher/pause-amd64:3.1                                                                                                "/pause"                 10 days ago         Up 10 days                                     k8s_POD_calico-node-7vzlj_kube-system_a2391472-9c42-11e8-a1c4-005056936694_0

kubernetes中的pause容器主要為每個業務容器提供以下功能:

  • 在pod中擔任Linux命名空間共享的基礎;
  • 啟用pid命名空間,開啟init進程。

Pod 的生命周期

Pod phase

Pod 的 status 在信息保存在 Podstatus 中定義,其中有一個 phase 字段。

Pod 的相位(phase)是 Pod 在其生命周期中的簡單宏觀概述。該階段並不是對容器或 Pod 的綜合匯總,也不是為了做為綜合狀態機。

Pod 相位的數量和含義是嚴格指定的。除了本文檔中列舉的狀態外,不應該再假定 Pod 有其他的 phase 值。

下面是 phase 可能的值:

描述
Pending Pod已被Kubernetes系統接受,但尚未創建一個或多個Container圖像。這包括計劃之前的時間以及通過網絡下載圖像所花費的時間,這可能需要一段時間
Running Pod已綁定到節點,並且已創建所有Container。至少有一個Container仍在運行,或者正在啟動或重新啟動
Succeeded Pod中的所有容器都已成功終止,並且不會重新啟動
Failed Pod中的所有容器都已終止,並且至少有一個Container已終止失敗。也就是說,Container要麽退出非零狀態,要麽被系統終止
Unknown 由於某種原因,無法獲得Pod的狀態,這通常是由於與Pod的主機通信時出錯

下圖是Pod的生命周期示意圖,從圖中可以看到Pod狀態的變化。

技術分享圖片

Pod條件

Pod有一個PodStatus,它有一個PodConditions 數組, Pod已經或沒有通過它。PodCondition數組的每個元素都有六個可能的字段:

  • lastProbeTime字段提供上次探測Pod條件的時間戳。

  • lastTransitionTime字段提供Pod最後從一個狀態轉換到另一個狀態的時間戳
  • message字段是人類可讀的消息,指示有關轉換的詳細信息
  • reason字段是該條件最後一次轉換的唯一,單字,CamelCase原因
  • status字段是一個字符串,可能的值為“ True”,“ False”和“ Unknown
  • type字段是一個包含以下可能值的字符串:
    • PodScheduled:Pod已被安排到一個節點;
    • Read: Pod能夠提供請求,應該添加到所有匹配服務的負載平衡池中;
    • Initialized:所有init容器都已成功啟動;
    • Unschedulable:調度程序現在無法調度Pod,例如由於缺少資源或其他限制
    • ContainersReady:Pod中的所有容器都已準備就緒

容器探針

探針是由 Kubelet 對容器執行的定期診斷。要執行診斷,kubelet 調用由容器實現的 Handler。有三種類型的處理程序:

  • ExecAction:在Container內執行指定的命令。如果命令以狀態代碼0退出,則認為診斷成功
  • TCPSocketAction:對指定端口上的Container的IP地址執行TCP檢查。如果端口打開,則診斷被認為是成功的
  • HTTPGetAction:對指定端口和路徑上的Container的IP地址執行HTTP Get請求。如果響應的狀態代碼大於或等於200且小於400,則認為診斷成功。

每個探針都有三個結果之一:

  • 成功:Container通過了診斷。
  • 失敗:容器未通過診斷。
  • 未知:診斷失敗,因此不應采取任何措施。

kubelet可以選擇在運行容器上執行兩種探測並對其做出反應:

  • livenessProbe:指示Container是否正在運行。如果存活探測失敗,則kubelet會殺死Container,並且Container將受其重啟策略的約束如果Container未提供存活探測,則默認狀態為Success。
  • readinessProbe:指示Container是否已準備好為服務請求。如果就緒探測失敗,則端點控制器會從與Pod匹配的所有服務的端點中刪除Pod的IP地址。初始延遲之前的默認就緒狀態是Failure如果Container未提供就緒狀態探測,則默認狀態為Success

什麽時候應該使用活力或準備探針?

如果您的Container中的進程在遇到問題或變得不健康時自行崩潰,則不一定需要存活探測器; kubelet將根據Pod的restartPolicy自動執行正確的操作

如果您希望在容器探測失敗時殺死並重新啟動,則指定存活探測,並指定restartPolicy為Always或OnFailure。

如果您只想在探測成功時開始向Pod發送流量,請指定就緒探測。在這種情況下,就緒探針可能與存活探測相同,但spec中就緒探針的存在意味著Pod將在不接收任何流量的情況下啟動,並且僅在探針探測成功後才開始接收流量。

如果Container需要在啟動期間處理大型數據,配置文件或遷移,請指定就緒探針。

如果您希望Container能夠自行維護,您可以指定一個就緒探針,該探針檢查特定於就緒的端點,該端點與活動探針不同。

請註意,如果您只想在Pod被刪除時排除請求,則不一定需要就緒探測; 在刪除Pod時,無論是否存在就緒探針,Pod都會自動將其置於未完成狀態。當等待 Pod 中的容器停止時,Pod 仍處於未完成狀態。

Kubernetes之POD