
Kubernetes 调度过程是将 Pod 分配到集群中合适节点的过程。具体流程如下:
spec.nodeName 为空的 Pod,将其标记为待调度ActiveQ)Binding 对象,设置 Pod 的 spec.nodeName完整流程:
用户创建 Pod → API Server 写入 etcd → 调度器监听到 Pod → 加入调度队列 → 调度框架处理(Filter→Score→Reserve→Bind) → Kubelet 启动容器 → Pod 状态更新为 RunningKubernetes 调度器的核心是 两个协同工作的控制循环,分别负责状态同步和调度决策。
实时同步集群状态到调度器缓存,为调度决策提供最新数据。
Informer 监听 API Server 的资源变更事件(Pod、Node、PV/PVC 等)。PodAdded、NodeUpdated),实时更新缓存状态。Pod 的 spec.nodeName 为空且 status.phase 为 Pending 时,将其加入调度队列(如 ActiveQ)。UnschedulableQ)。从队列中取出待调度 Pod,通过多阶段流水线完成调度决策。
核心机制:自 Kubernetes 1.19 引入的 调度框架(Scheduling Framework),将调度过程拆解为多个扩展点(Extension Points)。
阶段 | 功能 | 关键插件示例 |
|---|---|---|
1. QueueSort | 决定调度队列中 Pod 的排序顺序(如按优先级排序) |
|
2. PreFilter | 预处理 Pod 信息或检查前置条件(如校验资源请求合法性) |
|
3. Filter | 过滤不符合条件的节点(如资源不足、亲和性冲突) |
|
4. PostFilter | 当没有可用节点时,执行备选逻辑(如抢占低优先级 Pod) |
|
5. PreScore | 为 Score 阶段预处理数据(如计算拓扑分布权重) |
|
6. Score | 为通过 Filter 的节点打分(0-100 分),确定最优节点 |
|
7. Reserve | 预留节点资源(防止其他 Pod 占用),此阶段后资源被视为“已分配” |
|
8. Permit | 批准或拒绝调度决策(可阻塞等待外部条件满足) |
|
9. PreBind | 绑定前的准备工作(如创建网络配置、挂载存储卷) |
|
10. Bind | 将 Pod 绑定到节点(通过 API Server 提交 |
|
11. PostBind | 绑定后的清理或通知操作(如更新监控指标) |
|
QueueSort → PreFilter → Filter → PostFilter → PreScore → Score → Reserve → Permit。PreBind → Bind → PostBind。NodeAffinity 和 PodTopologySpread)。Score 插件的权重值决定最终节点得分)。ActiveQ。PreFilter 校验资源请求。Filter 排除资源不足的节点,Score 为剩余节点打分,选择最高分节点。Reserve 预留节点资源,Permit 批准调度。PreBind 挂载存储卷,Bind 向 API Server 提交绑定请求。PostBind 更新监控指标;若失败,Pod 重新入队。Scheduler Cache在创建Pod的工作内容:
当新Pod创建后,整个调度过程是一个流畅的工作流。首先,通过Informer机制,调度器会收到Pod的Add事件,这是整个流程的起点。接着,Scheduler Cache会立即将这个新Pod的信息添加到内存缓存中,为后续的调度决策做好准备。
随后,当调度器从队列中取出这个Pod准备进行调度时,它会创建一个缓存快照。这个快照非常重要,因为它提供了一个一致的集群状态视图,调度器就基于这个快照进行调度决策,包括节点过滤和打分。
经过一系列的计算和比较后,调度器为Pod选择出最佳节点,然后执行Assume操作。这个操作会在内存缓存中预先更新Pod和节点的关联关系,是一种乐观的更新机制。
Assume操作完成后,调度器并不会立即等待API Server的响应,而是会异步执行实际的绑定操作。这种设计减少了关键路径上的延迟。Scheduler Cache 它维护了集群资源状态的内存缓存,以提高调度决策的效率。以下是其工作流程:
Scheduler Cache 在调度器启动时初始化,主要包括:
通过 Informer 机制从 API Server 获取初始数据:
通过 Informer 的事件处理函数实时更新缓存:
调度决策做出后,使用 Assume 机制预先更新缓存:
Assume 后异步执行实际的绑定操作:
调度周期开始时创建缓存快照:
Scheduler Cache 精确跟踪各种资源:
这种内存缓存机制大大提高了调度器的性能,特别是在大规模集群中,避免了频繁访问 API Server 的开销。
在Kubernetes调度系统中,Assume操作是一种非常巧妙的性能优化设计。当调度器为Pod选择好目标节点后,不会立即向API Server发送绑定请求,而是先在内存中的Scheduler Cache里更新Pod和Node的关联信息。这种方式被称为"乐观"更新,因为它假设后续的实际绑定操作大概率会成功。
这种设计的核心优势在于避免了在关键调度路径上对API Server的远程访问。在大规模集群中,API Server可能成为性能瓶颈,尤其是在高并发调度场景下。通过Assume操作,调度器可以快速完成一个Pod的调度决策并立即处理下一个Pod,而不必等待API Server的响应。
从代码实现角度看,Assume操作通常会使用锁机制来保护Scheduler Cache的并发访问。就像编写代码中的 Lock() 一样,在更新共享数据结构时需要加锁保护。在Scheduler Cache中,当执行Assume操作时,也会使用类似的锁机制来确保数据一致性。
完成Assume操作后,调度器会创建一个异步的goroutine来执行实际的Bind操作,向API Server发送请求。如果绑定成功,一切正常;如果失败,下一次缓存同步时会修正这种不一致状态。
这种"乐观"更新策略是Kubernetes调度器性能优化的重要手段之一,它与缓存机制一起,大大提高了调度器的吞吐量和响应速度。
Kubernetes 调度器的“无锁化”设计是其高效处理大规模集群资源调度的核心机制之一。这种设计通过避免传统锁机制(如互斥锁或读写锁)的竞争,显著提升了调度器的并发性能和可扩展性。
调度器的核心职责是将 Pod 与 Node 匹配,但调度过程本身不直接修改集群状态。所有状态变更(如 Pod 绑定到节点)通过 API Server 的原子操作完成,调度器仅负责计算调度结果。这种职责分离避免了调度过程中对共享状态的直接竞争。
Informer 监听集群状态的变化,但调度决策基于当前状态的快照(通过 SharedIndexInformer 的本地缓存),避免了频繁与 API Server 交互。ResourceVersion)。调度器通过多级队列管理待调度的 Pod,不同队列之间通过优先级和调度条件隔离,避免了全局锁的需求:
heap 结构)管理顺序,无需显式加锁。尽管 Kubernetes 支持多调度器实例,但默认情况下:
调度器通过 Watch 机制 监听集群状态变化(如新 Pod 创建、Node 资源变更等),而非主动轮询:
Kubernetes 默认调度器(kube-scheduler)的可扩展性设计是其核心优势之一,它允许用户在不修改核心代码的情况下,通过多种机制扩展调度能力,满足不同场景的定制化需求。
调度器提供了多种扩展机制:
扩展点 | 功能 | 典型应用场景 |
|---|---|---|
QueueSort | 定义调度队列中 Pod 的排序规则(如按优先级排序) | 高优先级 Pod 优先调度 |
PreFilter | 预处理 Pod 信息或校验前置条件(如资源请求合法性) | 校验 Pod 的拓扑分布约束 |
Filter | 过滤不符合条件的节点(资源不足、亲和性冲突等) | 排除资源不足的节点 |
PostFilter | 当无可用节点时触发备选逻辑(如抢占低优先级 Pod) | 实现抢占(Preemption)机制 |
PreScore | 预处理数据(如计算拓扑分布权重) | 为 Score 阶段准备数据 |
Score | 为节点打分(0-100 分),确定最优节点 | 节点资源均衡、亲和性权重 |
Reserve | 预留节点资源(临时锁定资源,防止其他 Pod 抢占) | 避免资源竞争冲突 |
Permit | 批准或延迟调度决策(如等待外部审批或资源就绪) | 人工审批、依赖资源等待 |
PreBind | 绑定前的准备工作(如挂载存储卷、配置网络) | 存储卷绑定(VolumeBinding) |
Bind | 将 Pod 绑定到节点(可自定义绑定逻辑) | 多调度器协作、自定义绑定策略 |
PostBind | 绑定后的清理或通知操作(如记录指标、触发通知) | 监控、日志记录 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。