作者:Ron Sobol
翻譯:Bach(才云)
校對:星空下的文仔(才云)、bot(才云)
Kubernetes Scheduler 是 Kubernetes 控制平面的核心組件之一,它在控制平面上運行,將 Pod 分配給節點,同時平衡節點之間的資源利用率,將 Pod 分配給新節點后,在該節點上運行的 kubelet 會在 Kubernetes API 中檢索 Pod 定義,根據節點上的 Pod 規范創建資源和容器,換句話說,Scheduler 在控制平面內運行,并將作業負載分配給 Kubernetes 集群,
本文將對 Kubernetes Scheduler 進行深入研究,首先概述一般的調度以及具有親和力(affinity)和 taint 的驅逐調度,然后討論調度程式的瓶頸以及生產中可能遇到的問題,最后研究如何微調調度程式的引數以適合集群,
調度簡介
**Kubernetes 調度是將 Pod 分配給集群中匹配節點的程序,**Scheduler 監控新創建的 Pod,并為其分配最佳節點,它會根據 Kubernetes 的調度原則和我們的配置選項選擇最佳節點,最簡單的配置選項是直接在 PodSpec 設定 nodeName:

上面的 nginx pod 默認情況下將在 node-01 上運行,但是 nodeName 有許多限制導致無法正常運行 Pod,例如云中節點名稱未知、資源節點不足以及節點網路間歇性問題等,因此,除了測驗或開發期間,我們最好不使用 nodeName,
如果要在一組特定的節點上運行 Pod,可以使用 nodeSelector,我們在 PodSpec 中將 nodeSelector 定義為一組鍵值對:

對于上面的 nginx pod,Kubernetes Scheduler 將找到一個磁盤型別為 ssd 的節點,當然,該節點可以具有其他標簽,我們可以在 Kubernetes 參考檔案中查看標簽的完整串列,
地址:https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/
使用 nodeSelector 有約束 Pod 可以在有特定標簽的節點上運行,但它的使用僅受標簽及其值限制,Kubernetes 中有兩個更全面的功能來表達更復雜的調度需求:節點親和力(node affinity),標記容器以將其吸引到一組節點上;taint 和 toleration,標記節點以排斥 Pod,這些功能將在下面討論,
節點親和力
**節點親和力(Node Affinity)是在 Pod 上定義的一組約束,用于確定哪些節點適合進行調度,即使用親和性規則為 Pod 的節點分配定義硬性要求和軟性要求,**例如可以將 Pod 配置為僅運行帶有 GPU 的節點,并且最好使用 NVIDIA_TESLA_V100 運行深度學習作業負載,Scheduler 會評估規則,并在定義的約束內找到合適的節點,與 nodeSelectors 相似,節點親和性規則可與節點標簽一起使用,但它比 nodeSelectors 更強大,
我們可以為 podspec 添加四個相似性規則:
-
requiredDuringSchedulingIgnoredDuringExecution
-
requiredDuringSchedulingRequiredDuringExecution
-
preferredDuringSchedulingIgnoredDuringExecution
-
preferredDuringSchedulingRequiredDuringExecution
**這四個規則由兩個條件組成:必需或首選條件,以及兩個階段:計劃和執行,**以 required 開頭的規則描述了必須滿足的嚴格要求,以 preferred 開頭的規則是軟性要求,將強制執行但不能保證,調度階段是指將 Pod 首次分配給節點,執行階段適用于在調度分配后節點標簽發生更改的情況,
如果規則宣告為 IgnoredDuringExecution,Scheduler 在第一次分配后不會檢查其有效性,但如果使用 RequiredDuringExecution 指定了規則,Scheduler 會通過將容器移至合適的節點來確保規則的有效性,
以下是示例:

上面的 Nginx Pod 具有節點親和性規則,該規則讓 Kubernetes Scheduler 將 Pod 放置在 us-east 的節點上,第二條規則指示優先使用 us-east-1 或 us-east-2,
使用親和性規則,我們可以讓 Kubernetes 調度決策適用于自定義需求,
K8sMeetup
Taint 與 Toleration
集群中并非所有 Kubernetes 節點都相同,某些節點可能具有特殊的硬體,例如 GPU、磁盤或網路功能,同樣,我們可能需要將一些節點專用于測驗、資料保護或用戶組,我們可以將 Taint 添加到節點以排斥 Pod,如以下示例所示:
kubectl taint nodes node1 test-environment=true:NoSchedule
使用 test-environment=true:NoScheduletaint 時,除非在 podspec 具有匹配的 toleration,否則 Kubernetes Scheduler 將不會分配任何 pod :

taint 和 tolerations 共同發揮作用,讓 Kubernetes Scheduler 專用于某些節點并分配特定 Pod,
調度瓶頸
盡管 Kubernetes Scheduler 能選擇最佳節點,但是在 Pod 開始運行之后,“最佳節點”可能會改變,所以從長遠來看,Pod 的資源使用及其節點分配可能存在問題,
資源請求(Request)和限制(Limit):“Noisy Neighbor”
“Noisy Neighbor”并不特定于 Kubernetes,任何多租戶系統都是它們的潛在地,假設有兩個容器 A 和 B,它們在同一節點上運行,如果 Pod B 試圖通過消耗所有 CPU 或記憶體來創造 noise,Pod A 將出現問題,如果我們為容器設定了資源請求和限制就能控制住 neighbor,Kubernetes 將確保為容器安排其請求的資源,并且不會消耗超出其資源限制的資源,如果在生產中運行 Kubernetes,最好設定資源請求和限制以確保系統可靠,
系統行程資源不足
Kubernetes 節點主要是連接到 Kubernetes 控制平面的虛擬機,因此,節點上也有自己的作業系統和相關行程,如果 Kubernetes 作業負載消耗了所有資源,則這些節點將無法運行,并會發生各種問題問題,我們需要在 kubelet 中使用 –system -reserved 設定保留資源,以防止發生這種情況,
搶占或調度 Pod
如果 Kubernetes Scheduler 無法將 Pod 調度到可用節點,則可以從節點搶占(preempt)或驅逐(evict)一些 Pod 以分配資源,如果看到 Pod 在集群中移動而沒有發現特定原因,可以使用優先級類對其進行定義,同樣,如果沒有調度好 Pod,并且正在等待其他 Pod,也需要檢查其優先級,
以下是示例:

可以通過以下方式在 podspec 中為分配優先級:

調度框架
Kubernetes Scheduler 具有可插拔的調度框架架構,可向框架添加一組新的插件,插件實作 Plugin API,并被編譯到調度程式中,下面我們將討論調度框架的作業流、擴展點和 Plugin API,
作業流和擴展點
調度 Pod 包括兩個階段:調度周期(scheduling cycle)和系結周期(binding cycle),在調度周期中,Scheduler 會找到一個可用節點,然后在系結程序中,將決策應用于集群,
下圖說明了階段和擴展點的流程:

調度作業流(來源:Kubernetes 檔案)
作業流中的以下幾點對插件擴展開放:
-
QueueSort:對佇列中的 Pod 進行排序
-
PreFilter:檢查預處理 Pod 的相關資訊以安排調度周期
-
Filter:過濾不適合該 Pod 的節點
-
PostFilter:如果找不到可用于 Pod 的可行節點,呼叫該插件
-
PreScore:運行 PreScore 任務以生成一個可共享狀態供 Score 插件使用
-
Score:通過呼叫每個 Score 插件對過濾的節點進行排名
-
NormalizeScore:合并分數并計算節點的最終排名
-
Reserve:在系結周期之前選擇保留的節點
-
Permit:批準或拒絕調度周期結果
-
PreBind:執行任何先決條件作業,例如配置網路卷
-
Bind:將 Pod 分配給 Kubernetes API 中的節點
-
PostBind:通知系結周期的結果
插件擴展實作了 Plugin API,是 Kubernetes Scheduler 的一部分,我們可以在 Kubernetes 存盤庫中檢查,插件應使用以下名稱進行注冊:

插件還實作了相關的擴展點,如下所示:

Scheduler 性能調整
Kubernetes Scheduler 有一個作業流來查找和系結 Pod 的可行節點,當集群中的節點數量非常多時,Scheduler 的作業量將成倍增加,在大型集群中,可能需要很長時間才能找到最佳節點,因此要微調調度程式的性能,以在延遲和準確性之間找到折中方案,
percentageOfNodesToScore 將限制節點的數量來計算自己的分數,默認情況下,Kubernetes 在 100 節點集群的 50% 和 5000 節點集群的 10% 之間設定線性閾值,默認最小值為 5%,它要確保至少考慮集群中 5% 節點的調度,
下面的示例展示了如何通過性能調整 kube-scheduler 來手動設定閾值:

如果有一個龐大的集群并且 Kubernetes 作業負載不能承受 Kubernetes Scheduler 引起的延遲,那么更改百分比是個好主意,
總結
本文涵蓋了 Kubernetes 調度的大多方面,從 Pod 和節點的配置開始,包括 nodeSelector、親和性規則、taint 和 toleration,然后介紹了 Kubernetes Scheduler 框架、擴展點、API 以及可能發生的與資源相關的瓶頸,最后展示了性能調整設定,盡管 Kubernetes Scheduler 能簡單地將 Pod 分配給節點,但是了解其動態性并對其進行配置以實作可靠的生產級 Kubernetes 設定至關重要,
原文鏈接:hhttps://mp.weixin.qq.com/s/5J0Ojq95d3Yj1u36e3WQfQ
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/232567.html
標籤:java
