在 Kubernetes 中,排程是指将 Pod 放置到合适的 Node 上,然後對應 Node 上的 Kubelet 才能夠運作這些 Pod 。
kube-scheduler 是叢集控制平面的主要元件之一。Kubernetes 通過它來決定如何排程叢集中的 Pod。它會使用基于預選(斷言 predicate)和基于優選(優先級 priority)的評分算法,根據叢集中的限制以及使用者指定的限制來優化資源。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnaucTN5ETO2ITNtgTM3UzM5ADNxgDMwETMyAjMtMzM1MTM38CXwETMyAjMvw1MzUzMxczLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
預選(過濾)
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
可以被排程到該節點上。
更多
更多經典示例請參考:https://github.com/jxlwqq/kubernetes-examples