當一個 Pod 被調度時,Kubernetes 內部發生了什麼?
- 2021 年 10 月 8 日
- 筆記
- kube-scheduler, Kubernetes
在 Kubernetes 中,調度是指將 Pod 放置到合適的 Node 上,然後對應 Node 上的 Kubelet 才能夠運行這些 Pod 。
kube-scheduler 是集群控制平面的主要組件之一。Kubernetes 通過它來決定如何調度集群中的 Pod。它會使用基於預選(斷言 predicate)和基於優選(優先順序 priority)的評分演算法,根據集群中的約束以及用戶指定的約束來優化資源。
預選(過濾)
kube-scheduler 首先使用預選函數來制定調度策略,決定 Pod 可以在哪些節點上進行調度。它意味著一個硬性約束條件,因此函數的返回值為布爾值。例如,一個 Pod 請求 10GB 的記憶體,而節點 A 的配置為 8 GB,那麼節點 A 將返回 false
並從 Pod 的候選調度節點中剔除。另一個例子是節點 B 被集群管理員執行了 kubectl cordon node-b
,被標記節點為不可調度,它也將會被調度決策直接剔除。
調度程式會根據限制條件和複雜性依次進行以下預選檢查,檢查順序存儲在一個名為 predicatesOrdering (順序斷言)的切片中:
var predicateOrdering = []string{
CheckNodeUnschedulablePred,
GeneralPred, HostNamePred, PodFitsHostPortsPred,
MatchNodeSelectorPred, PodFitsResourcesPred, NoDiskConflictPred,
PodToleratesNodeTaintsPred, CheckNodeLabelPresencePred,
CheckServiceAffinityPred, MaxEBSVolumeCountPred, MaxGCEPDVolumeCountPred, MaxCSIVolumeCountPred,
MaxAzureDiskVolumeCountPred, MaxCinderVolumeCountPred, CheckVolumeBindingPred, NoVolumeZoneConflictPred,
EvenPodsSpreadPred, MatchInterPodAffinityPred,
}
- CheckNodeUnschedulablePred:檢查節點是否可調度;
- GeneralPred:一般性檢測,如檢測資源是否充足,Pod 的 Host、Port、Selector 是否匹配;
- HostNamePred:檢測 Pod 指定的 Node 名稱是否和 Node 名稱相同;
- PodFitsHostPortsPred:檢查 Pod 請求的埠(網路協議類型)在節點上是否可用;
- MatchNodeSelectorPred:檢測是否匹配 NodeSelector 節點選擇器的設置;
- PodFitsResourcesPred:檢查節點的空閑資源(例如,CPU 和記憶體)是否滿足 Pod 的要求;
- NoDiskConflictPred:根據 Pod 請求的卷是否在節點上已經掛載,評估 Pod 和節點是否匹配;
- PodToleratesNodeTaintsPred:檢查 Pod 的容忍是否能容忍節點的污點;
- CheckNodeLabelPresencePred:檢測 NodeLabel 是否存在;
- CheckServiceAffinityPred:檢測服務的親和;
MaxEBSVolumeCountPred:已廢棄,檢測 Volume 數量是否超過雲服務商 AWS 的存儲服務的配置限制;MaxGCEPDVolumeCountPred:已廢棄,檢測 Volume 數量是否是否超過雲服務商 Google Cloud 的存儲服務的配置限制;- MaxCSIVolumeCountPred:Pod 附加 CSI 卷的數量,判斷是否超過配置的限制;
MaxAzureDiskVolumeCountPred:已廢棄,檢測 Volume 數量是否超過雲服務商 Azure 的存儲服務的配置限制;MaxCinderVolumeCountPred:已廢棄,檢測 Volume 數量是否超過雲服務商 OpenStack 的存儲服務的配置限制;- CheckVolumeBindingPred,:基於 Pod 的卷請求,評估 Pod 是否適合節點,這裡的卷包括綁定的和未綁定的 PVC 都適用;
- NoVolumeZoneConflictPred:給定該存儲的故障區域限制, 評估 Pod 請求的卷在節點上是否可用;
- EvenPodsSpreadPred:檢測 Node 是否滿足拓撲傳播限制;
- MatchInterPodAffinityPred:檢測是否匹配 Pod 的親和與反親和的設置;
可以看出,Kubernetes 正在逐步移除某個具體雲服務商的服務的相關程式碼,而使用介面(Interface)來擴展功能。
優選(打分)
預選通過返回 true 或者 false 來表示節點是否參與調度,而優選則是根據優先順序的相對值對所有可調度節點進行排名,以下是為節點評分的優先順序列表:
- EqualPriority:給予所有節點相等的權重;
- MostRequestedPriority:支援最多請求資源的節點。 該策略將 Pod 調度到整體工作負載所需的最少的一組節點上;
- RequestedToCapacityRatioPriority:使用默認的打分方法模型,創建基於 ResourceAllocationPriority 的 requestedToCapacity;
- SelectorSpreadPriority:屬於同一 Service、 StatefulSet 或 ReplicaSet 的 Pod,儘可能地跨 Node 部署(雞蛋不要只放在一個籃子里,分散風險,提高可用性);
- ServiceSpreadingPriority:對於給定的 Service,此策略旨在確保該 Service 關聯的 Pod 在不同的節點上運行。 它偏向把 Pod 調度到沒有該服務的節點。 整體來看,Service 對於單個節點故障變得更具彈性;
- InterPodAffinityPriority:實現了 Pod 間親和性與反親和性的優先順序;
- LeastRequestedPriority:偏向最少請求資源的節點。 換句話說,節點上的 Pod 越多,使用的資源就越多,此策略給出的排名就越低;
- BalancedResourceAllocation:偏向平衡資源使用的節點;
- NodePreferAvoidPodsPriority:根據節點的註解 scheduler.alpha.kubernetes.io/preferAvoidPods 對節點進行優先順序排序。 你可以使用它來暗示兩個不同的 Pod 不應在同一節點上運行;
- NodeAffinityPriority:根據節點親和中 PreferredDuringSchedulingIgnoredDuringExecution 欄位對節點進行優先順序排序;
- TaintTolerationPriority:根據節點上無法忍受的污點數量,給所有節點進行優先順序排序。 此策略會根據排序結果調整節點的等級;
- ImageLocalityPriority:偏向已在本地快取 Pod 所需容器鏡像的節點;
- EvenPodsSpreadPriority:實現了 Pod 拓撲擴展約束的優先順序排序;
這些分值將會累計為節點的總分,用來表明其優先順序。例如,如果一個 Pod 需要 1 個 cpu 核心的資源,而有兩個候選節點滿足這一要求,其中節點 A 有 2 個 CPU 核心可供分配,節點 B 有 4 個核心可供分配,則節點 B 將具有更高的優先順序。 如果多個節點返回相同的優先順序,調度程式將會使用輪循的方式來選擇節點。
最優解
kube-scheduler 使用基於預選和基於優選的評分演算法,理論上需要遍歷所有 Node(實際上有快取邏輯),而當集群中的 Node 數量超過一定數量後,調度演算法的開銷將變得很大。所以 kube-scheduler 為了解決性能問題,引入了”全局最優解”和”局部最優解”兩種最優解。
- 全局最優解:遍歷集群中的所有節點,找出全局最優的節點;
- 局部最優解:只遍歷集群中的部分節點,找出局部最有的節點;
在小型集群中(例如 100 個節點),使用全局最優解。而在超大型集群中(例如 5000 個節點)使用局部最優解。
搶佔機制
Pod 可以設置優先順序(PriorityClass,注意:此處的 Pod 優先順序與優選演算法的優先順序評分不是一個概念)。 Pod 優先順序表示一個 Pod 相對於其他 Pod 的重要性。 如果一個 Pod 無法被調度,調度程式會嘗試搶佔(驅逐)較低優先順序的 Pod。
要使用優先順序和搶佔,需要:
- 新增 PriorityClass 對象,並設置 value 值;
- 將 Pod 的 Spec.priorityClassName 設置為上述新增的 PriorityClass;
上述設置了高優先順序的 Pod(暫稱為 pod-h
) ,如果 kube-scheduler 沒有找到滿足其指定要求的節點,則觸發搶佔邏輯。搶佔邏輯試圖找到某個節點,在該節點中刪除/驅逐一個或多個優先順序低於 pod-h
的 Pod。被驅逐的 Pod 消失後,pod-h
可以被調度到該節點上。
更多
更多經典示例請參考://github.com/jxlwqq/kubernetes-examples