kubernetes調度器
在kubernetes中,調度指的是將新生成的pod調度到合適的Node節點上,然后Node上對應的kubelet才能運行pod。
1.調度概述
調度器通過kubernetes的watch機制來發現新生成的且未調度到Node上的pod。調度器會將發現的每一個未調度的pod調度到合適的Node上運行,調度器會使用以下所述的調度原則來做出調度選擇。
2.kube-scheduler
kube-sceduler時kubernetes集群中默認調度器,並且是集群控制面的一部分,kube-scheduler在設計上允許你寫一個自己的調度組件並替換原有的kube-scheduler。
對每一個新創建或未被調度的的pod,kube-scheduler都會選擇一個最優的Node去運行這個pod。然而,pod內的每一個容器對資源都有不同的需求,而且pod本身也有不同的資源需求。因此,pod被調度到Node之前,會根據這些特定的資源調度需求,對集群中的Node進行一次過濾。
在一個集群中,滿足一個pod調度請求的所有node稱之為可調度節點。如果沒有任何一個Node滿足pod的調度請求,那個這個pod會一直處於未調度狀態直到調度器能夠找到合適的Node。
調度器先在集群中找到pod的所有可調度節點,然后根據一系列函數對這些可調度節點打分,然后選出得分最高的Node來運行pod。之后,調度器將這個調度決定通知給kube-apiserver,這個過程叫做綁定。
在做調度決定時需要考慮的因素包括:單獨和整體的資源需求,硬件/軟件/策略限制,親和以及反親和要求,數據局域性,負載間的干擾等。
3.kube-scheduler調度流程
kube-scheduler給一個pod做調度選擇包含兩個步驟:
(1)過濾
(2)打分
過濾階段會將所有滿足調度需求的node選擇出來。例如,PodFitsResources 過濾函數會檢查候選 Node 的可用資源能否滿足 Pod 的資源請求。在過濾之后,得出一個Node列表,里面包含了所有可調度節點;通常情況下,這個Node列表不止一個Node。如果這個列表是空的,說明這個pod不可調度。
在打分階段,調度器會為pod在所有可調度節點中選擇最合適的Node。根據當前的打分規則,調度器會給每一個可調度節點進行打分。
最后,kube-scheduler會將pod調度到得分最高的Node上。如果存在多個得分最高的Node,kube-scheduler會從中隨機選擇一個。
默認策略
kube-scheduler 有一系列的默認調度策略。
過濾策略
PodFitsHostPorts:如果 Pod 中定義了 hostPort 屬性,那么需要先檢查這個指定端口是否 已經被 Node 上其他服務占用了。
PodFitsHost:若 pod 對象擁有 hostname 屬性,則檢查 Node 名稱字符串與此屬性是否匹配。
PodFitsResources:檢查 Node 上是否有足夠的資源(如,cpu 和內存)來滿足 pod 的資源請求。
PodMatchNodeSelector:檢查 Node 的 標簽 是否能匹配 Pod 屬性上 Node 的 標簽 值。
NoVolumeZoneConflict:檢測 pod 請求的 Volumes 在 Node 上是否可用,因為某些存儲卷存在區域調度約束。
NoDiskConflict:檢查 Pod 對象請求的存儲卷在 Node 上是否可用,若不存在沖突則通過檢查。
MaxCSIVolumeCount:檢查 Node 上已經掛載的 CSI 存儲卷數量是否超過了指定的最大值。
CheckNodeMemoryPressure:如果 Node 上報了內存資源壓力過大,而且沒有配置異常,那么 Pod 將不會被調度到這個 Node 上。
CheckNodePIDPressure:如果 Node 上報了 PID 資源壓力過大,而且沒有配置異常,那么 Pod 將不會被調度到這個 Node 上。
CheckNodeDiskPressure:如果 Node 上報了磁盤資源壓力過大(文件系統滿了或者將近滿了), 而且配置沒有異常,那么 Pod 將不會被調度到這個 Node 上。
CheckNodeCondition:Node 可以上報其自身的狀態,如磁盤、網絡不可用,表明 kubelet 未准備好運行 pod。 如果 Node 被設置成這種狀態,那么 pod 將不會被調度到這個 Node 上。
PodToleratesNodeTaints:檢查 pod 屬性上的 tolerations 能否容忍 Node 的 taints。
CheckVolumeBinding:檢查 Node 上已經綁定的和未綁定的 PVCs 能否滿足 Pod 對象的存儲卷需求。
打分策略
SelectorSpreadPriority:盡量將歸屬於同一個 Service、StatefulSet 或 ReplicaSet 的 Pod 資源分散到不同的 Node 上。
InterPodAffinityPriority:遍歷 Pod 對象的親和性條目,並將那些能夠匹配到給定 Node 的條目的權重相加,結果值越大的 Node 得分越高。
LeastRequestedPriority:空閑資源比例越高的 Node 得分越高。換句話說,Node 上的 Pod 越多,並且資源被占用的越多,那么這個 Node 的得分就會越少。
MostRequestedPriority:空閑資源比例越低的 Node 得分越高。這個調度策略將會把你所有的工作負載(Pod)調度到盡量少的 Node 上。
RequestedToCapacityRatioPriority:為 Node 上每個資源占用比例設定得分值,給資源打分函數在打分時使用。
BalancedResourceAllocation:優選那些使得資源利用率更為均衡的節點。
NodePreferAvoidPodsPriority:這個策略將根據 Node 的注解信息中是否含有 scheduler.alpha.kubernetes.io/preferAvoidPods 來 計算其優先級。使用這個策略可以將兩個不同 Pod 運行在不同的 Node 上。
NodeAffinityPriority:基於 Pod 屬性中 PreferredDuringSchedulingIgnoredDuringExecution 來進行 Node 親和性調度。你可以通過這篇文章 Pods 到 Nodes 的分派 來了解到更詳細的內容。
TaintTolerationPriority:基於 Pod 中對每個 Node 上污點容忍程度進行優先級評估,這個策略能夠調整待選 Node 的排名。
ImageLocalityPriority:Node 上已經擁有 Pod 需要的 容器鏡像 的 Node 會有較高的優先級。
ServiceSpreadingPriority:這個調度策略的主要目的是確保將歸屬於同一個 Service 的 Pod 調度到不同的 Node 上。如果 Node 上 沒有歸屬於同一個 Service 的 Pod,這個策略更傾向於將 Pod 調度到這類 Node 上。最終的目的:即使在一個 Node 宕機之后 Service 也具有很強容災能力。
CalculateAntiAffinityPriorityMap:這個策略主要是用來實現pod反親和。
EqualPriorityMap:將所有的 Node 設置成相同的權重為 1。
4.調度器性能調優
在大規模 Kubernetes 集群下調度器性能優化的方式。
設置打分階段 Node 數量占集群總規模的百分比
在Kubernetes1.12版本之前,kube-scheduler會檢查集群中所有節點的可調度性,並且給可調度節點打分。Kubernetes1.12版本添加了一個新的功能,允許調度器在找到一定數量的可調度節點之后就停止繼續尋找可調度節點。該功能能提高調度器在大規模集群下的調度性能。這個數值是集群規模
的百分比。這個百分比通過 percentageOfNodesToScore 參數來進行配置。其值的范圍在1到100之間,最大值就是100%。如果設置為0就代表沒有提供這個參數配置。Kubernetes1.14版本又加入了一個特性,在該參數沒有被用戶配置的情況下,調度器會根據集群的規模自動設置一個集群比例,然后
通過這個比例篩選一定數量的可調度節點進入打分階段。該特性使用線性公式計算出集群比例,如在100-node 的集群下取 50%。在 5000-node 的集群下取 10%。這個自動設置的參數的最低值是5%。換句話說,調度器至少會對集群中 5% 的節點進行打分,除非用戶將該參數設置的低於5。
注意: 當集群中的可調度節點少於 50 個時,調度器仍然會去檢查所有的 Node,因為可調度節點太少,不足以停止調度器最初的過濾選擇。
如果想要關閉這個功能,你可以將 percentageOfNodesToScore 值設置成 100。
調節 percentageOfNodesToScore 參數
percentageOfNodesToScore 的值必須在 1 到 100 之間,而且其默認值是通過集群的規模計算得來的。另外,還有一個 50 個 Node 的數值是硬編碼在程序里面的。設置這個值的作用在於:當集群的規模是數百個 Node 並且percentageOfNodesToScore 參數設置的過低的時候,調度器篩選到的可調度節點數目基本不會受到該參數影響。當集群規模較小時,這個設置將導致調度器性能提升並不明顯。然而在一個超過 1000 個 Node 的集群中,將調優參數設置為一個較低的值可以很明顯的提升調度器性能。
值得注意的是,該參數設置后可能會導致只有集群中少數節點被選為可調度節點,很多 node 都沒有進入到打分階段。這樣就會造成一種后果,一個本來可以在打分階段得分很高的 Node 甚至都不能進入打分階段。由於這個原因,這個參數不應該被設置成一個很低的值。通常的做法是不會將這個參數的值設置的低於 10。很低的參數值一般在調度器的吞吐量很高且對 node 的打分不重要的情況下才使用。換句話說,只有當你更傾向於在可調度節點中任意選擇一個 Node 來運行這個 Pod 時,才使用很低的參數設置。
如果你的集群規模只有數百個節點或者更少,我們並不推薦你將這個參數設置得比默認值更低。因為這種情況下不太可能有效的提高調度器性能。
調度器做調度選擇的時候如何覆蓋所有的 Node
在將 Pod 調度到 Node 上時,為了讓集群中所有 Node 都有公平的機會去運行這些 Pod,調度器將會以輪詢的方式覆蓋全部的 Node。你可以將 Node 列表想象成一個數組。調度器從數組的頭部開始篩選可調度節點,依次向后直到可調度節點的數量達到 percentageOfNodesToScore 參數的要求。
在對下一個 Pod 進行調度的時候,前一個 Pod 調度篩選停止的 Node 列表的位置,將會來作為這次調度篩選 Node 開始的位置。
如果集群中的 Node 在多個區域,那么調度器將從不同的區域中輪詢 Node,來確保不同區域的 Node 接受可調度性檢查。如下例,考慮兩個區域中的六個節點:
Zone 1: Node 1, Node 2, Node 3, Node 4 Zone 2: Node 5, Node 6
調度器將會按照如下的順序去評估 Node 的可調度性:
Node 1, Node 5, Node 2, Node 6, Node 3, Node 4
在評估完所有 Node 后,將會返回到 Node 1,從頭開始。