调度框架

功能状态: 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 或 Permit 的插件应实现此接口。

QueueingHint

功能状态: Kubernetes v1.28 [beta]

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阶段之后,调度程序将根据配置的插件权重组合所有插件的节点分数。

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 的调度周期结束时调用,以防止或延迟绑定到候选节点。Permit 插件可以执行以下三种操作之一

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

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

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

PreBind

这些插件用于执行 Pod 绑定之前的任何必要工作。例如,一个 PreBind 插件可以在允许 Pod 在目标节点上运行之前预配网络卷并将网络卷装载到目标节点上。

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

Bind

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

PostBind

这是一个信息性接口。PostBind 插件在 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 或更高版本,您可以将一组插件配置为调度程序配置文件,然后定义多个配置文件以适合各种工作负载。了解更多信息,请访问 multiple profiles.

上次修改时间:2024 年 2 月 19 日下午 1:54 PST:Fix trailing whitespace in scheduler section (2f298d2077)