Kubernetes學習記錄(四):深入理解Pod
1. 什麼是Pod
1.1 Pod的基本概念
Pod就是一組共享了某些資源的容器
Pod的設計是為了親密性應用可以共享儲存和網路而設計
什麼是親密性應用場景:
- 兩個應用之間發生檔案互動
- 兩個應用需要通過127.0.0.1或者socket通訊
- 兩個應用需要發生頻繁呼叫
1.2 pod的實現機制和設計模式
共享網路
容器實現了namesapce隔離,那麼pod是怎麼打破這種隔離的?
實際上,在k8s中,pod的實現需要一箇中間容器,這個容器叫做Infra容器
在一個pod中,Infra容器永遠都是第一個被建立的容器,使用者定義的其它容器則通過JoinNetworkNamespace的方式與Infra關聯在一起
我們可以在node節點中找到這個容器,就是pause容器
在一個pod中共享網路,這意味著對於pod中的兩個容器來說:
- 它們可以使用localhost進行通訊
- 它們看到的網路裝置和Infra容器看到的完全一樣
- 一個pod只有一個IP地址,也就是這個pod的Network Namespace對應的地址
- Pod的生命週期和Infra容器一致,而與其他業務容器無關
共享儲存
pod使用資料卷的方式實現資料共享,k8s只需要把所有的volume定義在pod層級即可
這樣,一個volume對應的宿主機目錄對於pod來說就只有一個,pod內容器只需要宣告掛載這個volume,就可以實現資料共享
我們可以在一個具體的YAML檔案中觀察到這一點
在這個例子中,debian和nginx都宣告掛載了shared-data這個資料卷,而shared-data是hostPath型別,所以它在宿主機上對應的目錄就是 /data
從而nginx可以在它的/usr/share/nginx/html目錄中讀取到debian生成的index.html檔案
1.3 Pod的狀態
Pod的生命週期主要體現在Pod API物件的Status部分,這是它除了Metadata和Spec外的第三個重要欄位
其中pod.status.phase就是Pod當前的狀態,它有下面五種可能的情況:
- Pending
這個狀態意味著Pod的YAML檔案已經提交給了k8s,API物件已經被建立並儲存到etcd中
但是,這個Pod裡有些容器可能因為某種原因不能夠被順序建立,比如無法排程
- Running
這個狀態下,Pod已經被排程成功,跟一個具體節點繫結
它包含的容器都已經被建立,並且至少有一個在正在執行
- Succeeded
Pod裡所有的容器都執行完畢,並且成功退出,常見於一次性任務
- Failed
Pod裡至少有一個容器以不正常的狀態退出,遇到這個狀態需要檢視events
- Unknown
異常狀態,意味著kubelet不能上報情況,可能是master和node之間的通訊出問題
2. Pod的排程策略
k8s的排程策略分為兩個部分:predicates預選策略和priorites優選策略
- 預選策略:predicates是強制性規則,遍歷所有的node節點,按照具體的預選策略篩選出所有符合要求的node,如果沒有node符合要求,pod將會被掛起
- 優選擇略:在預選的基礎之上,按照優選策略為待選的node打分,獲取更優者部署pod
預選策略必須全部滿足
(1)CheckNodeCondition:檢測node是否正常
(2)GeneralPredicates:普通判斷策略
HostName: 檢測pod物件是否定義了pod.spec.hostname
PodFitsHostPorts:檢測pods.spec.containets.ports.hostPort是否定義
MatchNodeSelector:檢測pod是否設定了pods.spec.nodeSelector
PodFitsResources:檢測pod的資源需求是否能被節點所滿足
(3)NoDiskConflict:檢測pod依賴的儲存卷是否能滿足需求
(4)PodToleratesNodeTaints: 檢測pod上的spec.tolerations可容忍的汙點是否完全包含節點上的汙點
(5)PodToleratesNodeNoExecuteTaints: 檢測pod上是否啟用了NoExecute級別的汙點
(6)CheckNodeLabelPresence: 檢測node上的標籤的存在與否
(7)CheckServiceAffinity:將相同service pod的物件放到一起
(8)CheckVolumeBinding:檢測節點上已繫結和未繫結的volume
(9)NoVolumeZoneConflict:檢測區域,是否有pod volume的衝突
(10)CheckNodeMemoryPressure:檢測記憶體節點是否存在壓力
(11)CheckNodePIDPressure:檢測pid資源的情況
(12)CheckNodeDiskPressure:檢測disk資源壓力
(13)MatchInterPodAffity:檢測pod的親和性
優選擇略
優選函式的評估:如果一個pod過來,會根據啟用的全部函式的得分相加得到評估
(1)LeastRequested:最少請求,與節點的總容量的比值
(2)BalancedResourceAllocation:cpu和記憶體資源被佔用的比率相近程度,越接近,比分越高,平衡節點的資源使用情況
(3)NodePreferAvoidPods:在這個優先順序中,優先順序最高,得分非常高
(4)TaintToleration:將pod物件的spec.tolertions與節點的taints列表項進行匹配度檢測,匹配的條目越多,得分越低
(5)SeletorSpreading:儘可能的把pod分散開,也就是沒有啟動這個pod的node,得分會越高
(6)InterPodAffinity:遍歷pod的親和性,匹配項越多,得分就越多
(7)NodeAffinity:節點親和性,親和性高,得分高
(8)MostRequested:空閒量越少的,得分越高,與LeastRequested不能同時使用,集中一個機器上面跑pod
(9)NodeLabel:根據node上面的標籤來評估得分,有標籤就有分,沒有標籤就沒有分
(10)ImageLocality:一個node的得分高低,是根據node上面是否有映象,有映象就有得分,反之沒有。根據node上已有滿足需求的image的size的大小之和來計算
2.1 映象拉取策略
在建立pod時,有三種不同的映象拉取策略
- IfNotPresent:預設值,映象在宿主機上不存在時才會拉取
- Always:每次建立pod時都會重新拉取映象
- Never:Pod永遠不會主動拉取這個映象
關於拉取策略的使用,可以在YAML檔案中看到其使用的位置
上面也同樣展示了關於一些需要認證的私有倉庫,應該怎麼加認證去訪問,這個和secret有關
2.2 資源限制
Pod和Container的資源請求和限制:
- spec.containers[].resources.limits.cpu:實際使用最大CPU配額
- spec.containers[].resources.limits.memory:實際使用最大記憶體配額
- spec.containers[].resources.requests.cpu:排程時請求的CPU配額參考
- spec.containers[].resources.requests.memory:排程時請求的記憶體配額參考
資源限制有什麼用處?
最重要的一點就是避免某個容器資源利用率異常突發影響其它容器,從而造成雪崩
2.3 重啟策略
pod中的容器有三種重啟策略:
- Always:預設策略,當容器終止退出後,總是重啟
- OnFailure:當容器異常退出(退出狀態碼非0)時,才會重啟容器
- Never:當容器終止退出時,從不重啟容器
2.4 健康檢查
Probe有以下兩種型別:
- livenessProbe(存活檢查):如果檢查失敗,將殺死容器,根據重啟策略來決定是否重啟
- readinessProbe(就緒檢查):如果檢查失敗,k8s會將Pod從service endpoints中刪除
Probe支援以下三種檢查方法:
- httpGet:傳送HTTP請求,返回200-400範圍狀態碼為成功
- exec:執行shell命令返回狀態碼是0為成功
- tcpSocket:發起TCP Socket建立成功
比如在下面這個Pod中,健康檢查的機制就是通過在Pod內建立一個healthy檔案的方式來進行健康檢查
因為sleep了30s後刪除了檔案,所以會執行重啟Pod
同樣可以通過生成一個PID或者UUID來檢查
我們可以觀察到liveness測試Pod已經重啟了一次,說明其因為沒有通過健康檢查而重啟
通過 kubectl describe pod liveness-exec 檢視這個容器的Events
可以發現其就是因為沒有通過健康檢查而重啟的,因為healthy檔案被刪除了,cat時返回非0狀態碼
2.5 標籤選擇器
為node設定標籤,讓pod排程到指定標籤的node上
為節點打標籤
kubectl label nodes [node] key=value
為節點刪除標籤
kubectl label nodes [node] key-
在YAML中使用節點選擇器選擇對應標籤的節點即可
2.7 節點親和性
節點親和性用於替換節點標籤選擇器,有兩種親和性表達:
- RequiredDuringSchedulingIgnoredDuringExecution:硬限制,必須滿足條件
- PreferrefDuringSchedulingIgnoredDuringExecution:軟限制,可以按權重優先
2.8 汙點和汙點容忍
首先區分一下汙點是node的汙點,汙點容忍是pod對node上汙點的容忍程度
關於汙點,常見的汙點應用場景為節點獨佔或者有特殊硬體的節點
給一個node設定汙點:
kubectl taint node [node] key=valie[effect]
刪除汙點:
kubectl taint node [node] key:[effect]-
其中[effect]可取值:
- NoSchedule:不可能被排程,比如master節點在初始化時已經被打上不可排程標籤
- PreferNoSchedule:儘量不要被排程
- NoExecute:不僅不會被排程,還會驅逐Node上已有的Pod
汙點容忍是在構建Pod時,YAML檔案中的一個欄位
比如下面這個Pod,它可以忍受NoSchedule汙點的node
3. Pod的建立
- 使用者建立pod的資訊通過API Server儲存到etcd中,etcd記錄pod的元資訊並將結果返回給API Server
- API Server告知排程器請求資源排程,排程器通過排程演算法計算,將優先順序高的node與pod繫結並告知API Server
- API Server將此資訊寫入etcd,得到etcd回覆後呼叫kubelet建立pod
- kubelet使用docker run建立pod內容器,得到反饋後將此資訊告知API Server
- API Server將收到的資訊寫入etcd
- kubectl get pods 可以查到pod資訊了
參考:
【Kubernetes】Pod學習(八)Pod排程:定向排程與親和性排程_刺眼的寶石藍的部落格-CSDN部落格
pod排程策略,一篇就夠_Mr-Liuqx的部落格-CSDN部落格_pod排程策略
kube-scheduler :排程 Pod 流程-江哥架構師筆記 (andblog.cn)
乾貨!K8S之pod建立流程+排程約束_時光慢旅的部落格-CSDN部落格_k8s建立pod的詳細過程
這應該是最全的K8s-Pod排程策略了 - 雲+社群 - 騰訊雲 (tencent.com)
k8s之pod排程 - 路過的柚子廚 - 部落格園 (cnblogs.com)