调度框架

特性状态: Kubernetes v1.19 [稳定]

调度框架是 Kubernetes 调度器的可插拔架构。它由一组直接编译到调度器中的“插件”API 组成。这些 API 允许大多数调度功能以插件形式实现,同时保持调度“核心”轻量级和可维护性。有关框架设计的更多技术信息,请参阅调度框架的设计提案

框架工作流程

调度框架定义了一些扩展点。调度器插件注册以在其中一个或多个扩展点被调用。其中一些插件可以更改调度决策,而另一些插件仅提供信息。

尝试调度单个 Pod 会分为两个阶段:调度周期绑定周期

调度周期和绑定周期

调度周期为 Pod 选择一个节点,而绑定周期将该决策应用于集群。 调度周期和绑定周期合起来称为“调度上下文”。

调度周期按顺序运行,而绑定周期可以并发运行。

如果确定 Pod 无法调度或发生内部错误,则可以中止调度或绑定周期。Pod 将返回队列并重试。

接口

下图显示了 Pod 的调度上下文以及调度框架公开的接口。

一个插件可以实现多个接口以执行更复杂或有状态的任务。

某些接口与可以通过 调度器配置 配置的调度器扩展点匹配。

调度框架扩展点

PreEnqueue

这些插件在将 Pod 添加到内部活动队列之前被调用,在活动队列中,Pod 被标记为已准备好进行调度。

只有当所有 PreEnqueue 插件都返回 Success 时,Pod 才能进入活动队列。 否则,它将被放置在内部不可调度 Pod 列表中,并且不会获得 Unschedulable 条件。

有关内部调度器队列如何工作的更多详细信息,请阅读 kube-scheduler 中的调度队列

EnqueueExtension

EnqueueExtension 是插件控制是否基于集群中的更改来重试调度被此插件拒绝的 Pod 的接口。 实现 PreEnqueue、PreFilter、Filter 或 Reserve 的插件应实现此接口。

QueueingHint

特性状态: Kubernetes v1.34 [稳定](默认启用)

QueueingHint 是一个回调函数,用于确定 Pod 是否可以重新排队到活动队列或回退队列。 每当集群中发生某种类型的事件或更改时,它都会执行。 当 QueueingHint 发现事件可能会使 Pod 可调度时,Pod 将被放入活动队列或回退队列,以便调度器将重试 Pod 的调度。

QueueSort

这些插件用于对调度队列中的 Pod 进行排序。 队列排序插件本质上提供了一个 Less(Pod1, Pod2) 函数。 一次只能启用一个队列排序插件。

PreFilter

这些插件用于预处理有关 Pod 的信息,或检查集群或 Pod 必须满足的某些条件。 如果 PreFilter 插件返回错误,则调度周期将被中止。

Filter

这些插件用于过滤掉无法运行 Pod 的节点。 对于每个节点,调度器将按配置的顺序调用筛选器插件。 如果任何筛选器插件将节点标记为不可行,则对于该节点将不会调用剩余的插件。 节点可以并发评估。

PostFilter

这些插件在 Filter 阶段之后被调用,但仅当 Pod 没有找到可行的节点时。 插件按配置的顺序调用。 如果任何 postFilter 插件将节点标记为 Schedulable,则不会调用剩余的插件。 典型的 PostFilter 实现是抢占,它试图通过抢占其他 Pod 来使 Pod 可调度。

PreScore

这些插件用于执行“预评分”工作,该工作生成 Score 插件可以使用的共享状态。 如果 PreScore 插件返回错误,则调度周期将被中止。

Score

这些插件用于对通过筛选阶段的节点进行排名。 调度器将为每个节点调用每个评分插件。 将有一个明确定义的整数范围,表示最小和最大分数。 在 NormalizeScore 阶段之后,调度器将根据配置的插件权重组合来自所有插件的节点分数。

容量评分

特性状态: Kubernetes v1.33 [alpha](默认禁用)

v1.32 中的 VolumeCapacityPriority 特性门控用于支持静态配置的存储。 从 v1.33 开始,新的特性门控 StorageCapacityScoring 用添加的支持来动态配置存储取代了旧的 VolumeCapacityPriority 门控。 启用 StorageCapacityScoring 后,kube-scheduler 中的 VolumeBinding 插件将扩展为根据每个存储上的存储容量对节点进行评分。 此特性适用于支持 存储容量 的 CSI 卷,包括由 CSI 驱动程序支持的本地存储。

NormalizeScore

这些插件用于在调度器计算节点的最终排名之前修改分数。 注册此扩展点的插件将使用来自相同插件的 Score 结果进行调用。 这在每个插件每个调度周期调用一次。

例如,假设一个插件 BlinkingLightScorer 根据节点上闪烁灯的数量对节点进行排名。

func ScoreNode(_ *v1.pod, n *v1.Node) (int, error) {
    return getBlinkingLightCount(n)
}

但是,闪烁灯的最大数量可能与 NodeScoreMax 相比很小。 为了解决这个问题,BlinkingLightScorer 也应该注册此扩展点。

func NormalizeScores(scores map[string]int) {
    highest := 0
    for _, score := range scores {
        highest = max(highest, score)
    }
    for node, score := range scores {
        scores[node] = score*NodeScoreMax/highest
    }
}

如果任何 NormalizeScore 插件返回错误,则调度周期将被中止。

Reserve

实现 Reserve 接口的插件有两种方法,即 ReserveUnreserve,分别对应于两个信息调度阶段,称为 Reserve 和 Unreserve。 维护运行时状态(也称为“有状态插件”)的插件应使用这些阶段来在调度器等待绑定成功时收到通知。

Reserve 阶段发生在调度器实际将 Pod 绑定到其指定节点之前。 它旨在防止在调度器等待绑定成功时发生竞争条件。 每个 Reserve 插件的 Reserve 方法可以成功或失败; 如果一个 Reserve 方法调用失败,则不会执行后续插件,并且 Reserve 阶段被认为已失败。 如果所有插件的 Reserve 方法都成功,则 Reserve 阶段被认为成功,并且执行其余的调度周期和绑定周期。

如果 Reserve 阶段或后续阶段失败,则会触发 Unreserve 阶段。 发生这种情况时,将执行 所有 Reserve 插件的 Unreserve 方法,顺序与 Reserve 方法调用的相反顺序。 此阶段旨在清理与保留的 Pod 关联的状态。

Permit

Permit 插件在调度周期的末尾为每个 Pod 调用,以防止或延迟绑定到候选节点。 Permit 插件可以执行以下三种操作之一

  1. 批准
    一旦所有 Permit 插件批准了 Pod,它将被发送进行绑定。

  2. 拒绝
    如果任何 Permit 插件拒绝 Pod,它将被返回到调度队列。 这将触发 Reserve 插件 中的 Unreserve 阶段。

  3. 等待(带有超时)
    如果 Permit 插件返回 "wait",则 Pod 将被保存在内部的 "waiting" Pods 列表中,并且该 Pod 的绑定周期开始,但直接阻塞,直到获得批准。如果发生超时,wait 将变为 deny,Pod 将返回到调度队列,触发 Reserve 插件 中的 Unreserve 阶段。

PreBind

这些插件用于在 Pod 被绑定之前执行任何必要的工作。例如,PreBind 插件可以在目标节点上预置网络卷并挂载它,然后才能允许 Pod 在那里运行。

如果任何 PreBind 插件返回错误,Pod 将被 拒绝 并返回到调度队列。

Bind

这些插件用于将 Pod 绑定到 Node。Bind 插件只有在所有 PreBind 插件都完成后才会被调用。每个 Bind 插件都按照配置的顺序调用。Bind 插件可以选择是否处理给定的 Pod。如果 Bind 插件选择处理 Pod,其余的 Bind 插件将被跳过

PostBind

这是一个信息性接口。Post-bind 插件在 Pod 成功绑定后被调用。这是绑定周期的结束,可用于清理相关的资源。

Plugin API

Plugin API 有两个步骤。首先,插件必须注册并配置,然后它们使用扩展点接口。扩展点接口具有以下形式。

type Plugin interface {
    Name() string
}

type QueueSortPlugin interface {
    Plugin
    Less(*v1.pod, *v1.pod) bool
}

type PreFilterPlugin interface {
    Plugin
    PreFilter(context.Context, *framework.CycleState, *v1.pod) error
}

// ...

Plugin 配置

您可以在调度器配置中启用或禁用插件。如果您使用的是 Kubernetes v1.18 或更高版本,大多数调度 插件 默认情况下正在使用并启用。

除了默认插件之外,您还可以实现自己的调度插件,并将其与默认插件一起配置。您可以访问 scheduler-plugins 以获取更多详细信息。

如果您使用的是 Kubernetes v1.18 或更高版本,您可以将一组插件配置为调度器配置文件,然后定义多个配置文件以适应各种类型的工作负载。请参阅 multiple profiles 了解更多信息。

最后修改时间 2025 年 7 月 04 日 上午 6:50 PST:KEP-4247:将 SchedulerQueueingHints 功能升级到 GA (e2c0fe17d6)