调度框架

特性状态: Kubernetes v1.19 [stable]

调度框架是 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 或 Permit 的插件应该实现此接口。

QueueingHint

特性状态: Kubernetes v1.32 [beta]

QueueingHint 是一个回调函数,用于决定 Pod 是否可以重新加入活动队列或回退队列。每当集群中发生特定类型的事件或变化时,都会执行此函数。当 QueueingHint 发现该事件可能使 Pod 可调度时,Pod 将被放入活动队列或回退队列中,以便调度器重新尝试调度该 Pod。

QueueSort

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

PreFilter

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

Filter

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

PostFilter

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

PreScore

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

Score

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

容量评分

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

特性门控 VolumeCapacityPriority 在 v1.32 中用于支持静态配置的存储。从 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。维护运行时状态(即“有状态插件”)的插件应使用这些阶段,以便在为给定 Pod 预留和释放节点上的资源时收到调度器的通知。

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

如果 Reserve 阶段或后续阶段失败,则触发 Unreserve 阶段。此时,将以与调用 Reserve 方法相反的顺序执行所有 Reserve 插件的 Unreserve 方法。此阶段用于清理与预留 Pod 相关的状态。

Permit

_Permit_ 插件在每个 Pod 调度周期结束时被调用,以阻止或延迟绑定到候选节点。许可插件可以执行以下三种操作之一:

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

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

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

PreBind

这些插件用于在 Pod 绑定之前执行所需的任何工作。例如,一个预绑定插件可能会在允许 Pod 在目标节点上运行之前,预置一个网络卷并将其挂载到目标节点上。

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

Bind

这些插件用于将 Pod 绑定到节点。直到所有 PreBind 插件完成,Bind 插件才会被调用。每个 Bind 插件按照配置的顺序被调用。Bind 插件可以选择是否处理给定的 Pod。如果一个 Bind 插件选择处理 Pod,则剩余的 Bind 插件将被跳过

PostBind

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

插件 API

插件 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
}

// ...

插件配置

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

除了默认插件之外,你还可以实现自己的调度插件,并与默认插件一起进行配置。有关详细信息,你可以访问scheduler-plugins

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

上次修改时间:2024 年 10 月 16 日 10:55 AM PST: 增加 StorageCapacityScoring 特性门控文档 (9ef3b68238)