🧭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 调度器架构

调度器以持续循环的方式运行,监听尚未分配
nodeName 的新创建 Pod。对于每个 Pod,调度器遵循以下两个阶段的流程:2.1 调度周期(串行)
此阶段是同步且串行执行的,以确保资源统计的一致性。
排队(Queueing)
新创建的未绑定 Pod(spec.nodeName 为空)被调度器监听到后,进入优先级队列。
主要作用:
- 对所有待调度 Pod 进行排序
- 控制调度时机
核心扩展点:QueueSort 插件
默认排序规则(优先级最高 → 最低):
- Pod Priority(越高越靠前)
- 创建时间(越新越靠前)
其他重要机制:
- 反亲和性预检查与规避
- 调度失败重试降级(多次失败后降低调度优先级)
- 支持调度暂停/恢复(运维需求)
过滤(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)
调度流程的终点。
执行流程:
- 调度器构造 Bind 请求,向 API Server 发送(Pod + 目标节点)
- API Server 执行全局二次强校验(弥补本地缓存局限)
- 校验通过 → 更新 etcd 中 Pod.spec.nodeName,同步给 kubelet
- 校验失败 → 返回错误,调度器回滚预留,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 特有需求
- 成组调度(Gang Scheduling / All-or-Nothing):分布式训练(如 PyTorch DDP)要求所有参与者同时启动。如果 8 个 Worker 中只有 7 个启动而第 8 个处于挂起状态,前 7 个将空转,造成昂贵 GPU 资源的极大浪费。
- GPU 共享与装箱(Binpacking):AI 推理通常不需要占用整块 GPU。调度器必须支持 GPU 分片共享或“装箱”策略(优先填满一个节点再使用下一个),以最大化资源利用率。
- 拓扑感知(Topology Awareness):对于大模型(LLM)训练,GPU 之间(NVLink)以及节点之间(InfiniBand)的通信延迟是性能瓶颈。调度器必须具备“拓扑感知”能力。
- 异构资源管理:管理 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...