🧭AI 时代下的 Kubernetes 调度器:架构、挑战与演进路径

type
status
date
slug
summary
category
tags
icon
password
AI summary
Blocked by
Blocking
Category

1. 引言:Kubernetes 编排的核心

Kubernetes 调度器(kube-scheduler)是负责将 Pod 分配到节点(Node)的核心控制平面组件。尽管它在微服务时代表现卓越,但随着人工智能(AI)和机器学习(ML)工作负载的爆发式增长,其原始设计已逐渐触及瓶颈。本文将深入探讨调度器的内部架构、扩展机制,以及它如何演进以满足 AI 时代的需求。

2. Kubernetes 调度器架构

notion image
调度器以持续循环的方式运行,监听尚未分配 nodeName 的新创建 Pod。对于每个 Pod,调度器遵循以下两个阶段的流程:

2.1 调度周期(串行)

此阶段是同步且串行执行的,以确保资源统计的一致性。

排队(Queueing)

新创建的未绑定 Pod(spec.nodeName 为空)被调度器监听到后,进入优先级队列
主要作用:
  • 对所有待调度 Pod 进行排序
  • 控制调度时机
核心扩展点:QueueSort 插件 默认排序规则(优先级最高 → 最低):
  1. Pod Priority(越高越靠前)
  1. 创建时间(越新越靠前)
其他重要机制:
  • 反亲和性预检查与规避
  • 调度失败重试降级(多次失败后降低调度优先级)
  • 支持调度暂停/恢复(运维需求)

过滤(Filtering / Predicates)

从队列取出 Pod 后,遍历所有健康节点,执行过滤规则,剔除不可行节点,得到候选节点列表。
  • 若候选列表为空 → 调度失败,Pod 回到 Pending
  • 过滤规则属于硬约束(不满足 = 直接淘汰,无妥协)
常见内置过滤规则(部分):
  • 节点可分配资源(CPU/内存/存储/端口) ≥ Pod 请求量
  • nodeSelector / nodeAffinity 与节点标签匹配
  • 节点污点(Taints)与 Pod 容忍(Tolerations)兼容
  • 节点 Pod 数量未超上限
  • 存储卷(PV/PVC)可在此节点挂载
扩展:通过 Filter 插件添加自定义硬约束(如限定机房、指定 GPU 任务专属节点等)。

打分(Scoring / Priorities)

对过滤后的候选节点逐一打分,选择综合得分最高的节点作为目标节点。 得分相同时随机选择。
  • 目标:从“可行”节点中挑选“最优”节点
  • 打分规则属于软约束(倾向性排序,而非强制)
打分机制
  • 每个 Score 插件独立给节点打 0–100 分
  • 插件配置权重(Weight)
  • 节点最终得分 = Σ (插件基础分 × 权重)
常见内置打分插件(部分):
插件名称
优化目标
得分倾向
LeastRequestedPriority
资源利用率均衡(避免热点)
剩余资源越多得分越高
BalancedResourceAllocation
CPU/内存分配均衡
维度间利用率越均衡得分越高
NodeAffinityPriority
节点亲和性偏好
亲和匹配度越高得分越高
TopologySpreadPriority
拓扑域分散(提升容灾)
分布越均匀得分越高
扩展:通过 Score 插件实现业务偏好(如同机房优先、显存匹配优先等)。

2.2 绑定周期(异步)

调度周期选定目标节点后,进入绑定周期。 核心目标:正式将 Pod 与节点关联,让 Pod 在目标节点上启动。

预留(Reserve)

调度器本地缓存中:
  • 扣减目标节点的可用资源(CPU/内存/端口等)
  • 记录 Pod → 节点 临时绑定关系
核心价值:在等待 API Server 确认的“时间窗口”内防止资源超卖。
特性:
  • 操作极快(纯内存)
  • 所有并行绑定流程共享同一缓存视图
  • 支持回滚(Unreserve):后续失败时立即恢复资源
扩展点:Reserve / Unreserve 插件(预留/释放时的自定义动作)

准入(Permit)——可选策略钩子

在正式 Bind 前执行的最后一道策略关卡
三种可能结果:
结果
含义
后续行为
Allow
校验通过
直接进入 Bind
Wait
条件暂不满足(需等待)
挂起绑定流程,条件满足后自动唤醒,超时失败
Deny
校验拒绝
终止流程 → 回滚预留 → Pod 重新排队
典型场景:
  • PodGroup 全有或全无调度
  • 等待依赖 Pod 就绪
  • 业务规则动态拦截
无 Permit 插件时默认直接 Allow。

绑定(Bind)

调度流程的终点。
执行流程:
  1. 调度器构造 Bind 请求,向 API Server 发送(Pod + 目标节点)
  1. API Server 执行全局二次强校验(弥补本地缓存局限)
  1. 校验通过 → 更新 etcd 中 Pod.spec.nodeName,同步给 kubelet
  1. 校验失败 → 返回错误,调度器回滚预留,Pod 重新入队
kubelet 后续:
  • 监听到 Pod 被分配到本节点
  • 拉取镜像 → 创建容器 → 配置网络/存储 → 启动进程 → Running
扩展能力
  • Bind 插件:修改绑定逻辑
  • Extender:将 Bind 委托给远程调度系统(联邦、云厂商调度器等)

3. 扩展机制:Framework 与 Extender

Kubernetes 提供了两种主要方式来扩展默认调度器,而无需修改其核心源代码。

3.1 调度框架(Scheduler Framework - 现代标准)

在 K8s 1.15 中引入并在 1.19+ 版本正式商用(GA),调度框架是一种基于插件的架构。
  • 工作原理:开发者编写实现特定接口(Hooks)的 Go 代码,并将其编译进 kube-scheduler 二进制文件中。
  • 与默认调度器的关系:它是默认调度器的组成部分。可以通过 KubeSchedulerConfiguration 配置文件启用、禁用或重新排序插件。
  • 部分扩展 vs. 全量替换可以选择保留所有默认插件并仅添加一个自定义 Score 插件,也可以禁用所有默认插件并提供完全自定义的逻辑。
  • 修改影响如果添加了 Score 插件,其结果将与所有其他活跃打分插件的结果累加。除非显式禁用默认插件(如 NodeResourcesLeastAllocated),否则它不会“替换”默认打分。

3.2 调度扩展器(Scheduler Extender - 传统方案)

  • 工作原理:调度器在过滤和打分阶段通过 Webhook 调用的外部 HTTP 服务。
  • 与默认调度器的关系:这是一种“外挂”逻辑。默认调度器完成自身工作后,将过滤后的节点列表发送给 Extender 进行进一步的过滤或打分。
  • 局限性:HTTP 调用导致高延迟,且无法访问调度器的内部缓存,可能引发竞态条件。

方案对比表

特性
调度框架 (Plugin)
调度扩展器 (Webhook)
性能
高(进程内调用)
低(HTTP 开销)
开发语言
仅限 Go
任意语言(支持 HTTP 即可)
钩子点
11 个以上的扩展点
过滤、打分、绑定、抢占
数据访问
可完全访问内部缓存
仅限于 JSON 发送的数据
集成方式
编译进二进制文件
外部独立服务

4. 核心钩子点(Hook Points)解析

调度框架定义了多个关键钩子,理解这些钩子对自定义开发至关重要:
钩子点
阶段
用途
AI 应用场景
QueueSort
队列
定义 Pod 在队列中的优先级。
优先调度大型训练作业,而非小型开发任务。
Filter
调度
硬约束检查(是/否)。
确保节点拥有特定的 GPU 型号(如 A100)。
Score
调度
软约束检查(排名)。
倾向于选择具有 GPU 间 NVLink 连接的节点。
Permit
绑定
延迟或拒绝绑定。
成组调度:等待所有 8 个工作节点全部就绪。
Reserve
绑定
资源统计。
防止两个 Pod 同时“声明”同一个 GPU 资源。

5. AI 时代:新需求与挑战

传统的微服务是“无状态”且“相互独立”的;而 AI 工作负载则是“有状态”、“相互依赖”且“资源密集”的。

5.1 AI 特有需求

  1. 成组调度(Gang Scheduling / All-or-Nothing):分布式训练(如 PyTorch DDP)要求所有参与者同时启动。如果 8 个 Worker 中只有 7 个启动而第 8 个处于挂起状态,前 7 个将空转,造成昂贵 GPU 资源的极大浪费。
  1. GPU 共享与装箱(Binpacking):AI 推理通常不需要占用整块 GPU。调度器必须支持 GPU 分片共享或“装箱”策略(优先填满一个节点再使用下一个),以最大化资源利用率。
  1. 拓扑感知(Topology Awareness):对于大模型(LLM)训练,GPU 之间(NVLink)以及节点之间(InfiniBand)的通信延迟是性能瓶颈。调度器必须具备“拓扑感知”能力。
  1. 异构资源管理:管理 A100、H100 和 T4 等多种型号的混合资源,需要复杂的过滤和打分逻辑。

5.2 默认调度器的局限性

  • 逐个 Pod 调度逻辑:默认调度器一次仅处理一个 Pod,无法感知 Pod A 和 Pod B 属于同一个“作业(Job)”。
  • 资源粒度过粗:它将 GPU 视为“不透明的整数”,原生状态下无法理解 GPU 显存、NVLink 或 NUMA 亲和性。
  • 队列能力有限:缺乏层级队列管理(例如:团队 A 分配 40% GPU,团队 B 分配 60%)。

6. 生态解决方案:Volcano、Koordinator 等

为了弥补上述差距,CNCF 生态系统涌现了专门的调度器:

6.1 Volcano:批处理与 AI 调度事实标准

  • 原生支持 PodGroup
  • 完整的 Gang Scheduling
  • 丰富的调度策略(DRF、Binpack)
适合 分布式训练与 HPC 场景

6.2 Koordinator:面向混部与 QoS 的调度系统

  • 在线与离线负载混合部署
  • 节点侧实时资源画像
  • 强调 SLO 与稳定性
更偏向 生产级资源治理

6.3 Kueue:作业级排队管理器

  • 不替换默认调度器
  • 提供多租户队列与配额
  • 与 Autoscaler 协同工作
适合 云原生原生生态用户

6.4 YuniKorn:通用高性能调度器

  • 层级队列
  • 应用感知调度
  • Spark / 大数据友好

7. 结语

Kubernetes 调度器已不再是“一劳永逸”的通用组件。对于简单的微服务,默认调度器表现完美;而对于复杂的 AI 工作负载,调度框架提供了深度定制的能力,同时像 Volcano 这样的项目提供了 AI 所需的“作业感知”逻辑。在修改 Score 阶段时,请务必记住您是在参与一个加权求和的过程——您的逻辑必须与现有生态良好兼容,才能实现理想的资源编排。
 
Prev
MySQL-存储引擎
Next
Knative Service 多版本管理指南
Loading...
Article List
如果去做,还有一丝希望;但是不去做,就毫无希望
k8s
knative
技术分享
agentic
个人总结
istio
HAMI
Golang
转发
计算机网络
Redis
MySQL
Mysql