本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.26:Pod 排程就緒性

Kubernetes 1.26 引入了一個新的 Pod 特性:排程門控(scheduling gates)。在 Kubernetes 中,排程門控是一些鍵(key),用來告訴排程器一個 Pod 何時準備好被排程。

它解決了什麼問題?

當 Pod 被建立時,排程器將不斷嘗試為它尋找一個合適的節點。這個無限迴圈會一直持續,直到排程器為 Pod 找到一個節點,或者 Pod 被刪除。

長時間處於不可排程狀態的 Pod(例如,那些被某些外部事件阻塞的 Pod)會浪費排程週期。一個排程週期可能需要 ≅20 毫秒或更長時間,具體取決於 Pod 排程約束的複雜性。因此,在大規模場景下,這些被浪費的週期會顯著影響排程器的效能。請參見下面“排程器”框中的箭頭。

graph LR; pod((新 Pod))-->queue subgraph Scheduler queue(排程器佇列) sched_cycle[/排程週期/] schedulable{可排程?} queue==>|彈出|sched_cycle sched_cycle==>schedulable schedulable==>|否|queue subgraph note [因不斷重新排程“未就緒”的 Pod 而浪費週期] end end classDef plain fill:#ddd,stroke:#fff,stroke-width:1px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:1px,color:#fff; classDef Scheduler fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; classDef note fill:#edf2ae,stroke:#fff,stroke-width:1px; class queue,sched_cycle,schedulable k8s; class pod plain; class note note; class Scheduler Scheduler;

排程門控有助於解決這個問題。它允許宣告新建立的 Pod 尚未準備好進行排程。當 Pod 上存在排程門控時,排程器會忽略該 Pod,從而節省不必要的排程嘗試。如果你在叢集中安裝了 Cluster Autoscaler,這些 Pod 也會被其忽略。

清除門控是外部控制器的責任,這些控制器知道 Pod 何時應被考慮進行排程(例如,配額管理器)。

graph LR; pod((新 Pod))-->queue subgraph Scheduler queue(排程器佇列) sched_cycle[/排程週期/] schedulable{可排程?} popout{彈出?} queue==>|入隊前檢查|popout popout-->|是|sched_cycle popout==>|否|queue sched_cycle-->schedulable schedulable-->|否|queue subgraph note [一個控制 Pod 排程的開關] end end classDef plain fill:#ddd,stroke:#fff,stroke-width:1px,color:#000; classDef k8s fill:#326ce5,stroke:#fff,stroke-width:1px,color:#fff; classDef Scheduler fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; classDef note fill:#edf2ae,stroke:#fff,stroke-width:1px; classDef popout fill:#f96,stroke:#fff,stroke-width:1px; class queue,sched_cycle,schedulable k8s; class pod plain; class note note; class popout popout; class Scheduler Scheduler;

它是如何工作的?

排程門控的工作方式通常與 Finalizer 非常相似。spec.schedulingGates 欄位非空的 Pod 將顯示為 SchedulingGated 狀態,並且其排程將被阻止。請注意,可以新增多個門控,但它們都應在 Pod 建立時新增(例如,你可以將它們作為規約的一部分或透過一個變更性質的 Webhook 來新增)。

NAME       READY   STATUS            RESTARTS   AGE
test-pod   0/1     SchedulingGated   0          10s

要清除門控,你需要更新 Pod,從其 schedulingGates 欄位中移除所有項。門控不必一次性全部移除,但只有當所有門控都被移除後,排程器才會開始考慮排程該 Pod。

在底層,排程門控是作為 PreEnqueue 排程器外掛實現的,這是一個新的排程器框架擴充套件點,在每個排程週期的開始時被呼叫。

使用場景

此功能實現的一個重要使用場景是動態配額管理。Kubernetes 支援ResourceQuota,但 API 伺服器在你嘗試建立 Pod 時強制執行配額。例如,如果一個新的 Pod 超過了 CPU 配額,它將被拒絕。API 伺服器不會將 Pod 排隊;因此,建立 Pod 的一方需要不斷地嘗試重新建立它。這要麼意味著資源可用和 Pod 實際執行之間存在延遲,要麼意味著由於不斷的嘗試而給 API 伺服器和排程器帶來負載。

排程門控允許外部配額管理器解決 ResourceQuota 的上述限制。具體來說,該管理器可以(使用一個變更性質的 Webhook)向叢集中建立的所有 Pod 新增一個 example.com/quota-check 排程門控。當有配額啟動 Pod 時,該管理器再移除該門控。

下一步是什麼?

要使用此功能,必須在 API 伺服器和排程器中啟用 PodSchedulingReadiness 特性門控。我們非常歡迎你進行測試並告訴我們(SIG Scheduling)你的想法!

其他資源