本文发布时间已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已不准确。

Kubernetes 1.26:Pod 调度就绪

Kubernetes 1.26 引入了一个新的 Pod 特性:调度门控 (scheduling gates)。在 Kubernetes 中,调度门控是告诉调度器何时可以考虑调度一个 Pod 的关键。

它解决了什么问题?

创建 Pod 后,调度器会不断尝试为其找到合适的节点。这个无限循环会一直持续,直到调度器为 Pod 找到节点,或者 Pod 被删除。

长期处于不可调度状态的 Pod(例如,被某些外部事件阻塞的 Pod)会浪费调度周期。一个调度周期可能需要约 20 毫秒或更长时间,具体取决于 Pod 调度约束的复杂性。因此,在大规模环境下,这些浪费的周期会显著影响调度器的性能。请参阅下方“调度器”框中的箭头。

graph LR; pod((新 Pod))-->queue subgraph 调度器 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 调度器 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;

它是如何工作的?

调度门控的工作原理与 Finalizers 非常相似。spec.schedulingGates 字段非空的 Pod 将显示状态为 SchedulingGated,并被阻止调度。请注意,可以添加多个门控,但它们都应在创建 Pod 时添加(例如,你可以将它们作为 spec 的一部分添加,或通过 mutating webhook 添加)。

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

要清除门控,你需要更新 Pod,移除 Pod 的 schedulingGates 字段中的所有项。门控不需要一次性全部移除,只有当所有门控都被移除时,调度器才会开始考虑调度该 Pod。

在底层,调度门控被实现为一个 PreEnqueue 调度器插件,这是一个新的调度器框架扩展点,在每个调度周期开始时被调用。

使用场景

此特性实现的一个重要使用场景是动态配额管理。Kubernetes 支持ResourceQuota,但 API Server 会在你尝试创建 Pod 时强制执行配额。例如,如果一个新 Pod 超出了 CPU 配额,它将被拒绝。API Server 不会将该 Pod 排队;因此,创建该 Pod 的人需要不断地尝试重新创建它。这要么意味着资源可用与 Pod 实际运行之间存在延迟,要么意味着由于持续尝试而增加了 API Server 和调度器的负载。

调度门控允许外部配额管理器解决上述 ResourceQuota 的限制。具体而言,管理器可以为集群中创建的所有 Pod 添加一个 example.com/quota-check 调度门控(使用 mutating webhook)。当有配额可供启动 Pod 时,管理器就会移除该门控。

后续计划?

要使用此特性,必须在 API Server 和调度器中启用 PodSchedulingReadiness 特性门控。非常欢迎你进行测试并告诉我们(SIG Scheduling)你的想法!

更多资源