kubernetes_scheduler
kube-scheduler
简介
kube-scheduler
是 Kubernetes 的核心组件之一,负责 Pod 的调度(Scheduling)。其主要职责是为尚未绑定节点的 Pod 选择合适的节点进行运行。调度器在 Kubernetes 中扮演“任务分派员”的角色,核心目标是满足工作负载的资源需求(如 CPU、内存等),同时遵循用户定义的调度策略和约束(如 Pod 的 nodeSelector
、affinity
等)。
工作流程
一、Pod 监听
初始化 Informer
kube-scheduler
启动时,会创建一个 Pod Informer,用于监听和缓存 Pod 的变化(包括新增、修改、删除事件)。仅监听那些尚未绑定节点(即
spec.nodeName
为空)的 Pod。1
2
3
4
5
6
7
8
9
10
11
12
13
14func NewScheduler(...) (*Scheduler, error) {
// ...existing code...
// 创建 Pod Informer
podInformer := informerFactory.Core().V1().Pods()
// 初始化调度器
sched := &Scheduler{
podQueue: queue, // 调度队列
podInformer: podInformer, // Pod Informer
podLister: podInformer.Lister() // 用于从缓存中获取 Pod 列表
// ...existing code...
}
// ...existing code...
}
通过 List 和 Watch 获取数据
- List:调度器启动时,通过 API Server 全量获取当前所有未绑定节点的 Pod。
- Watch:随后通过 Watch API 订阅 Pod 的增量更新事件(新增、修改、删除)。
二、接收调度请求
当用户创建 Pod 时,若 Pod 未绑定到特定节点(即
.spec.nodeName
为空),kube-scheduler 会将其视为待调度对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 在 Informer 初始化过程中,设置过滤器
podInformer := informerFactory.Core().V1().Pods().Informer()
// 仅监听未绑定节点的 Pod
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
if pod.Spec.NodeName == "" {
// Pod 未被绑定,加入调度队列
sched.AddPodToQueue(pod)
}
},
UpdateFunc: func(oldObj, newObj interface{}) {
oldPod := oldObj.(*v1.Pod)
newPod := newObj.(*v1.Pod)
if oldPod.Spec.NodeName == "" && newPod.Spec.NodeName == "" {
// Pod 更新但仍未绑定
sched.AddPodToQueue(newPod)
}
},
DeleteFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
if pod.Spec.NodeName == "" {
// Pod 被删除
sched.DeletePodFromQueue(pod)
}
},
})
三、可调度节点筛选(Filter 阶段)
kube-scheduler 会根据一系列过滤规则(Filter Plugins,原称 Predicates),筛选出所有满足 Pod 调度需求的候选节点。例如:

常见的 Filter 插件包括:
- PodFitsHostPorts:检查目标节点上是否有 Pod 使用了相同的
hostPort
,避免端口冲突。 - PodFitsResources:检查节点资源(CPU、内存、GPU 等)是否满足 Pod 的
requests
。 - HostName:若 Pod 指定了
spec.nodeName
,则只匹配该节点。 - MatchNodeSelector:节点需满足 Pod 的
nodeSelector
条件。 - NoVolumeZoneConflict:检查 Pod 所需的 Volume 是否可在目标节点所在的可用区挂载。
- MatchInterPodAffinity:检查 Pod 的亲和性或反亲和性规则。
- NoDiskConflict:验证节点上是否存在 Volume 冲突。
- PodToleratesNodeTaints:检查 Pod 是否能容忍节点的 Taint。
- CheckNodeMemoryPressure:节点是否处于内存压力状态。
- CheckNodeDiskPressure:节点是否处于磁盘压力状态。
- NoVolumeNodeConflict:检查节点是否满足 Pod 所需 Volume 的挂载条件。
四、候选节点评分(Score 阶段)
- 对通过过滤的候选节点,调度器会根据一系列优先级规则(Scoring Plugins,原称 Priorities)为每个节点打分。
- 评分目标是从所有可用节点中选择最优节点。例如:
- 优先将 Pod 调度到负载较低的节点。
- 优先调度到与数据存储位置更近的节点。
- 避免过多 Pod 调度到同一节点,防止资源热点。
常见的 Scoring 插件包括:
- SelectorSpreadPriority:将同一类型的 Pod 尽量分布到不同节点,实现负载均衡和高可用。
- InterPodAffinityPriority:优先调度到与目标 Pod 拓扑接近的节点。
- LeastRequestedPriority:优先调度到资源请求最少的节点。
- BalancedResourceAllocation:优先选择 CPU 和内存使用率均衡的节点。
- NodePreferAvoidPodsPriority:优先避开有
preferAvoidPods
标记的节点。 - NodeAffinityPriority:优先调度到匹配 NodeAffinity 的节点。
- TaintTolerationPriority:优先调度到能容忍特定 Taint 的节点。
- ImageLocalityPriority:优先调度到已缓存所需镜像的节点。
- MostRequestedPriority:优先调度到已使用较多资源的节点,提高资源利用率。
- EqualPriority:所有节点分配相同优先级(用于测试或无特殊需求场景)。
以 BalancedResourceAllocation
插件为例,其实现如下:
1 |
|
五、决策与绑定(Bind 阶段)
- 从评分最高的节点中选择一个节点,作为该 Pod 的最终调度目标。
- 调度器将调度结果写入 etcd,将 Pod 绑定到目标节点。
调度流程可概括为:过滤(Filter) → 评分(Score) → 绑定(Bind)。
Kubernetes 的 QoS 类(Quality of Service)
Kubernetes 根据 Pod 的资源请求和限制自动确定其 QoS 类,QoS 类影响调度、资源管理和优先级。主要分为三类:
1. Guaranteed
所有容器的
requests
和limits
必须完全相等。特点:最高优先级,资源保障最强,适用于关键性应用。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "500Mi"
cpu: "0.5"
limits:
memory: "500Mi"
cpu: "0.5"
2. Burstable
至少有一个容器设置了
requests
,但requests
和limits
不完全相等。特点:可获得至少
requests
的资源,超出部分可被回收。示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "200Mi"
cpu: "0.2"
limits:
memory: "500Mi"
cpu: "0.5"
3. BestEffort
所有容器都未设置
requests
或limits
。特点:最低优先级,仅在资源充足时调度。
示例:
1
2
3
4
5
6
7
8apiVersion: v1
kind: Pod
metadata:
name: besteffort-pod
spec:
containers:
- name: app
image: nginx
QoS 类与调度行为
- 资源分配优先级:
Guaranteed > Burstable > BestEffort
- 节点驱逐优先级:BestEffort 最先被驱逐,Guaranteed 最后被驱逐。
- 调度优先级:调度器优先分配高 QoS 的 Pod。
调度阶段 QoS 决策举例
调度器会依次检查:
- 节点是否满足 Pod 的
requests
(按 QoS 优先顺序)。 - 节点剩余容量能否满足 Pod 的
limits
。 - 结合 Taints、Tolerations、亲和性等规则综合评估。
QoS 调度优化建议
- 关键应用使用 Guaranteed,明确资源上下界。
- 配合 Taints 和 Tolerations,将高 QoS 应用调度到专用节点。
- 通过
kube-reserved
、system-reserved
预留关键资源。 - 使用 ResourceQuota 限制低 QoS 资源消耗。
requests 与 limits
1. 概念
- requests:容器运行的最低资源需求,调度器据此判断节点是否有足够资源。
- limits:容器运行的资源上限,Kubelet 和容器运行时据此限制资源使用。
示例
1 |
|
2. 调度器如何使用 requests
- 节点可用资源 = 节点总资源 - 所有已分配 Pod 的 requests
- 调度器过滤掉可用资源不足的节点,仅在满足 requests 的节点中选择。
3. Kubelet 如何使用 limits
limits.cpu
通过 Cgroup 的 CPU Shares 和 CPU Quota 实现。limits.memory
是硬限制,超出会被 OOM 杀死。
4. 最佳实践
- requests 设为容器最低需求,limits 设为最大允许值。
- 避免 requests 和 limits 差距过大,防止资源超分配或浪费。
- 配合 ResourceQuota 和 LimitRange 管理资源。
Pod 调度到指定 Node
1. NodeSelector
- 通过为节点打标签,并在 Pod 的
spec.nodeSelector
字段指定标签,实现将 Pod 调度到特定节点。
示例
1 |
|
1 |
|
- 支持多个键值对,所有条件需同时满足(AND 逻辑)。
2. NodeSelector 局限性
- 仅支持简单 AND 逻辑,无法表达复杂调度规则。
- 节点标签变更不会自动触发 Pod 重新调度。
- 推荐使用 NodeAffinity、Taints/Tolerations 或自定义调度器实现更复杂需求。
NodeAffinity
1. 概念
- NodeAffinity 是基于节点标签的调度约束,分为硬约束(
requiredDuringSchedulingIgnoredDuringExecution
)和软约束(preferredDuringSchedulingIgnoredDuringExecution
)。
2. 语法示例
1 |
|
matchExpressions
支持 In、NotIn、Exists、DoesNotExist、Gt、Lt 等操作符。- 多个
nodeSelectorTerms
之间为 OR 关系,matchExpressions
内为 AND 关系。
PodAffinity 与 PodAntiAffinity
1. 概念
- PodAffinity:指定 Pod 应调度到与特定 Pod 接近的节点。
- PodAntiAffinity:指定 Pod 应避免与特定 Pod 同节点。
2. 应用场景
- 优化服务间局部性、降低延迟、提升高可用性。
3. 配置示例
Pod Affinity:
1 |
|
Pod Anti-Affinity:
1 |
|
topologyKey
可指定亲和性作用域,如节点、可用区、区域等。
Taints 与 Tolerations
1. 概念
- Taints(污点):为节点设置特殊标记,限制哪些 Pod 可调度到该节点。
- Tolerations(容忍):Pod 声明可容忍哪些污点,从而允许被调度到带有对应污点的节点。
Taint 结构:Key、Value、Effect(NoSchedule、PreferNoSchedule、NoExecute)
1 |
|
Toleration 结构:
1 |
|
2. 工作机制
- 节点有 Taint 时,只有带有匹配 Toleration 的 Pod 才能调度到该节点。
- Taints 主动限制,Tolerations 被动声明。
3. 应用场景
- 专用节点调度、节点维护、负载隔离等。
故障转移(Failover)
Kubernetes 通过 Taints 和 Tolerations 实现节点故障时的 Pod 驱逐与重新调度。
1. 节点不可用检测
- 节点心跳超时(默认 40 秒),Node Controller 会为节点添加
node.kubernetes.io/unreachable:NoExecute
Taint。
2. Pod 行为
- 无 Toleration:Pod 立即被驱逐并重新调度。
- 有 Toleration 且无
tolerationSeconds
:Pod 无限期保留。 - 有 Toleration 且有
tolerationSeconds
:Pod 在宽限期后被驱逐。
3. 故障转移流程
- 节点失联,自动添加
NoExecute
Taint。 - Pod 检查 Toleration,决定是否驱逐。
- 被驱逐的 Pod 重新调度到健康节点。
- 节点恢复后,Taint 自动移除。
4. 调优建议
- 合理设置心跳间隔和
tolerationSeconds
。 - 无状态应用可设置较短容忍时间,有状态应用可适当延长。
- 配合 Liveness/Readiness Probe 区分节点与 Pod 健康。
优先级调度(PriorityClass)与多调度器
1. PriorityClass
- 通过 PriorityClass 对象为 Pod 设置调度优先级,
value
越大优先级越高。 - 支持抢占机制,高优先级 Pod 可驱逐低优先级 Pod。
示例:
1 |
|
1 |
|
2. 多调度器(Multiple Schedulers)
- 支持部署多个调度器,Pod 通过
spec.schedulerName
指定使用哪个调度器。
示例:
1 |
|
3. 生产经验总结
- 小集群高并发场景可通过多调度器分摊压力。
- 使用 PriorityClass 控制任务优先级,结合资源配额和自定义调度器隔离高风险工作负载。
- 持续监控调度器性能,优化缓存刷新机制,避免调度延迟和资源倾斜。