做者:Ron Sobol
翻譯:Bach(才雲)
校對:星空下的文仔(才雲)、bot(才雲)
Kubernetes Scheduler 是 Kubernetes 控制平面的核心組件之一。它在控制平面上運行,將 Pod 分配給節點,同時平衡節點之間的資源利用率。將 Pod 分配給新節點後,在該節點上運行的 kubelet 會在 Kubernetes API 中檢索 Pod 定義,根據節點上的 Pod 規範建立資源和容器。換句話說,Scheduler 在控制平面內運行,並將工做負載分配給 Kubernetes 集羣。node
本文將對 Kubernetes Scheduler 進行深刻研究,首先概述通常的調度以及具備親和力(affinity)和 taint 的驅逐調度,而後討論調度程序的瓶頸以及生產中可能遇到的問題,最後研究如何微調調度程序的參數以適合集羣。nginx
Kubernetes 調度是將 Pod 分配給集羣中匹配節點的過程。Scheduler 監控新建立的 Pod,併爲其分配最佳節點。它會根據 Kubernetes 的調度原則和咱們的配置選項選擇最佳節點。最簡單的配置選項是直接在 PodSpec
設置 nodeName:api
上面的 nginx pod 默認狀況下將在 node-01 上運行,可是 nodeName 有許多限制致使沒法正常運行 Pod,例如雲中節點名稱未知、資源節點不足以及節點網絡間歇性問題等。所以,除了測試或開發期間,咱們最好不使用 nodeName。網絡
若是要在一組特定的節點上運行 Pod,可使用 nodeSelector。咱們在 PodSpec
中將 nodeSelector 定義爲一組鍵值對:架構
對於上面的 nginx pod,Kubernetes Scheduler 將找到一個磁盤類型爲 ssd 的節點。固然,該節點能夠具備其餘標籤。咱們能夠在 Kubernetes 參考文檔中查看標籤的完整列表。框架
地址:https://kubernetes.io/docs/re...性能
使用 nodeSelector
有約束 Pod 能夠在有特定標籤的節點上運行。但它的使用僅受標籤及其值限制。Kubernetes 中有兩個更全面的功能來表達更復雜的調度需求:節點親和力(node affinity),標記容器以將其吸引到一組節點上;taint 和 toleration,標記節點以排斥 Pod。這些功能將在下面討論。學習
節點親和力(Node Affinity)是在 Pod 上定義的一組約束,用於肯定哪些節點適合進行調度,即便用親和性規則爲 Pod 的節點分配定義硬性要求和軟性要求。例如能夠將 Pod 配置爲僅運行帶有 GPU 的節點,而且最好使用 NVIDIA_TESLA_V100 運行深度學習工做負載。Scheduler 會評估規則,並在定義的約束內找到合適的節點。與 nodeSelectors
類似,節點親和性規則可與節點標籤一塊兒使用,但它比 nodeSelectors
更強大。測試
咱們能夠爲 podspec 添加四個類似性規則:ui
這四個規則由兩個條件組成:必需或首選條件,以及兩個階段:計劃和執行。以 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 文檔)
工做流中的如下幾點對插件擴展開放:
插件擴展實現了 Plugin API,是 Kubernetes Scheduler 的一部分。咱們能夠在 Kubernetes 存儲庫中檢查。插件應使用如下名稱進行註冊:
插件還實現了相關的擴展點,以下所示:
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 設置相當重要。