Kubernetes之POD
什麽是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指定多個共享的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在等待進程終止的過程中重啟,在重啟後仍然會重試完整的寬限期。
示例流程如下:
- 用戶發送刪除pod的命令,默認寬限期是30秒;
- 在Pod超過該寬限期後API server就會更新Pod的狀態為“dead”;
- 在客戶端命令行上顯示的Pod狀態為“terminating”;
- 跟第三步同時,當kubelet發現pod被標記為“terminating”狀態時,開始停止pod進程:1 如果在pod中定義了preStop hook,在停止pod前會被調用。如果在寬限期過後,preStop hook依然在運行,第二步會再增加2秒的寬限期;2 向Pod中的進程發送TERM信號;
- 跟第三步同時,該Pod將從該service的端點列表中刪除,不再是replication controller的一部分。關閉的慢的pod將繼續處理load balancer轉發的流量;
- 過了寬限期後,將向Pod中依然運行的進程發送SIGKILL信號而殺掉進程。
- 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容器都已成功啟動;- U
nschedulable
:調度程序現在無法調度Pod,例如由於缺少資源或其他限制 - C
ontainersReady
: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