天天看點

當一個 Pod 被排程時,Kubernetes 内部發生了什麼?

在 Kubernetes 中,排程是指将 Pod 放置到合适的 Node 上,然後對應 Node 上的 Kubelet 才能夠運作這些 Pod 。

kube-scheduler 是叢集控制平面的主要元件之一。Kubernetes 通過它來決定如何排程叢集中的 Pod。它會使用基于預選(斷言 predicate)和基于優選(優先級 priority)的評分算法,根據叢集中的限制以及使用者指定的限制來優化資源。

當一個 Pod 被排程時,Kubernetes 内部發生了什麼?

預選(過濾)

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。

要使用優先級和搶占,需要:

  1. 新增 PriorityClass 對象,并設定 value 值;
  2. 将 Pod 的 Spec.priorityClassName 設定為上述新增的 PriorityClass;

上述設定了高優先級的 Pod(暫稱為

pod-h

) ,如果 kube-scheduler 沒有找到滿足其指定要求的節點,則觸發搶占邏輯。搶占邏輯試圖找到某個節點,在該節點中删除/驅逐一個或多個優先級低于

pod-h

的 Pod。被驅逐的 Pod 消失後,

pod-h

可以被排程到該節點上。

更多

更多經典示例請參考:https://github.com/jxlwqq/kubernetes-examples

繼續閱讀