Kubernetes 调度器深度实战:从调度框架到自定义调度策略
深入剖析 Kubernetes 调度器核心原理,掌握调度框架扩展机制与自定义调度策略开发实战
一、调度器架构概述
Kubernetes 调度器(kube-scheduler)是集群控制平面的核心组件,负责将新创建的 Pod 分配到合适的节点上运行。其核心职责包括:资源匹配、约束满足、负载均衡和高可用保障。
调度器采用经典的主控-插件架构,通过调度框架(Scheduling Framework)提供高度可扩展性。自 Kubernetes 1.18 起,调度框架成为稳定 API,允许开发者通过插件方式定制调度行为,而无需修改调度器核心代码。
二、调度周期解析
Pod 的调度过程分为以下关键阶段:
1. 调度队列(Scheduling Queue)
调度器维护一个内部调度队列,Pod 在此等待被调度。队列支持优先级排序(Priority and Preemption),高优先级 Pod 可抢占低优先级 Pod 的资源。
2. 过滤阶段(Filter / Predicates)
过滤阶段筛选出能够满足 Pod 资源需求和约束条件的节点。常见过滤插件包括:NodeResourcesFit(资源匹配)、NodeName(节点名称过滤)、NodeUnschedulable(不可调度节点过滤)、TaintToleration(污点容忍检查)等。
3. 评分阶段(Score / Priorities)
对通过过滤的节点进行打分排序。评分插件包括:NodeResourcesFit(基于资源利用率)、ImageLocality(镜像亲和性)、InterPodAffinity(Pod 亲和性)、NodeAffinity(节点亲和性)等。每个插件返回 0-100 的分数,最终加权求和得出总分。
4. 绑定阶段(Bind)
选定最优节点后,调度器将 Pod 与节点的绑定关系写入 etcd,完成调度流程。
调度框架扩展点
调度框架提供了丰富的扩展点(Extension Points),开发者可以在以下阶段注入自定义逻辑:p>
| 扩展点 | 阶段 | 功能说明 |
|---|---|---|
| QueueSort | 队列排序 | 自定义 Pod 在队列中的排序规则 |
| PreFilter | 过滤前预处理 | 预计算 Pod 信息,为过滤阶段准备数据 |
| Filter | 节点过滤 | 筛选可调度节点 |
| PostFilter | 过滤后处理 | 当没有可用节点时执行,可用于触发抢占 |
| PreScore | 评分前预处理 | 预计算节点或 Pod 信息 |
| Score | 节点评分 | 为节点打分 |
| Reserve | 资源预留 | 预留节点资源,防止并发调度冲突 |
| Permit | 调度许可 | 延迟或拒绝 Pod 绑定 |
| PreBind | 绑定前处理 | 执行绑定前的准备工作 |
| Bind | 节点绑定 | 将 Pod 绑定到节点 |
| PostBind | 绑定后处理 | 绑定成功后的清理操作 |
| Unreserve | 释放预留 | 释放已预留的资源 |
三、调度策略深度配置
3.1 节点亲和性与反亲和性
节点亲和性(Node Affinity)允许 Pod 指定调度到特定节点。支持两种模式:requiredDuringSchedulingIgnoredDuringExecution(硬性要求)和 preferredDuringSchedulingIgnoredDuringExecution(软性偏好)。
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- nvme
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zone
operator: In
values:
- east-1a
containers:
- name: nginx
image: nginx:latest
3.2 Pod 亲和性与反亲和性
Pod 亲和性(Pod Affinity)使 Pod 倾向于调度到特定 Pod 所在的节点,适用于需要将关联服务就近部署的场景。反亲和性则确保 Pod 分散在不同节点,保障高可用。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname
containers:
- name: web
image: nginx:alpine
上述配置确保同一 Deployment 的 Pod 不会调度到同一节点,实现节点级高可用。
3.3 污点与容忍度
污点(Taint)为节点打上标记,阻止不相关 Pod 调度到该节点。容忍度(Tolerance)则允许 Pod 忽略特定污点。这种机制常用于专用节点管理。
# 为节点添加污点
kubectl taint nodes node1 dedicated=gpu:NoSchedule
# Pod 配置容忍度
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
tolerations:
- key: dedicated
operator: Equal
value: gpu
effect: NoSchedule
containers:
- name: cuda-container
image: nvidia/cuda:12.0-base
四、资源管理与调度优化
4.1 资源请求与限制
合理的资源请求(Requests)和限制(Limits)配置是调度优化的基础。调度器基于 Requests 计算节点资源可用性,而 Limits 则被传递给容器运行时进行资源隔离。
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
4.2 QoS 等级与调度优先级
Kubernetes 根据资源配置自动划分 Pod 的 QoS 等级:
- Guaranteed:所有容器的 Requests 等于 Limits,资源有保障
- Burstable:至少一个容器设置了 Requests,可弹性使用资源
- BestEffort:未设置任何 Requests 和 Limits,资源使用无保障
当节点资源紧张时,BestEffort Pod 最先被驱逐,Guaranteed Pod 最后被驱逐。
4.3 拓扑感知调度
拓扑感知调度(Topology Aware Routing)确保 Pod 在跨可用区部署时,流量优先路由到本区域的 Pod,降低延迟并节省带宽成本。结合 TopologySpreadConstraints 可实现 Pod 在指定拓扑域中的均匀分布。
apiVersion: apps/v1
kind: Deployment
metadata:
name: zone-spread-app
spec:
replicas: 6
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: myapp
containers:
- name: app
image: myapp:latest
上述配置确保 6 个副本在 3 个可用区间均匀分布(每区 2 个),skew 不超过 1。
五、自定义调度器开发实战
5.1 自定义调度器场景
当内置调度策略无法满足业务需求时,可开发自定义调度器。常见场景包括:GPU 时间片调度、异构硬件亲和调度、能耗感知调度、分布式系统就近调度等。
5.2 基于调度框架的插件开发
最轻量的自定义方式是编写调度框架插件。插件实现 kube-scheduler 定义的接口即可注册到调度器中。
package myscore
import (
"context"
"k8s.io/kubernetes/pkg/scheduler/framework"
)
type CustomScorePlugin struct{}
func (pl *CustomScorePlugin) Name() string {
return "CustomScorePlugin"
}
func (pl *CustomScorePlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
nodeInfo := handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
if nodeInfo == nil {
return 0, framework.NewStatus(framework.Error, "node not found")
}
score := calculateCustomScore(pod, nodeInfo.Node())
return score, nil
}
func (pl *CustomScorePlugin) ScoreExtensions() framework.ScoreExtensions {
return pl
}
func (pl *CustomScorePlugin) NormalizeScore(ctx context.State, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
// 归一化处理
var maxScore int64 = 0
for _, score := range scores {
if score.Score > maxScore {
maxScore = score.Score
}
}
if maxScore == 0 {
return nil
}
for i := range scores {
scores[i].Score = scores[i].Score * framework.MaxNodeScore / maxScore
}
return nil
}
5.3 独立自定义调度器
完全独立的调度器需要实现 List-Watch 机制监听未调度 Pod 事件,自行做出调度决策后创建 Binding 对象。这种方案更灵活但开发维护成本更高。
apiVersion: v1
kind: Pod
metadata:
name: custom-scheduled-pod
spec:
schedulerName: my-custom-scheduler
containers:
- name: app
image: app:latest
六、生产环境最佳实践
6.1 Pod Disruption Budget
PDB 保障应用在节点维护或升级期间的可用性,限制同时不可用的 Pod 数量。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
6.2 优先级与抢占
通过 PriorityClass 定义 Pod 优先级,当资源不足时高优先级 Pod 可抢占低优先级 Pod 的资源。
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "高优先级业务"
6.3 调度器性能调优
大规模集群(节点数 > 5000)需关注调度器吞吐量。关键参数包括:percentageOfNodesToScore(评分节点比例)、bindTimeoutSeconds(绑定超时)、schedulerName(多调度器共存)。
七、总结
Kubernetes 调度器通过灵活的调度框架提供了强大的扩展能力。掌握亲和性、污点容忍、资源管理、拓扑感知等核心策略,可以有效优化集群资源利用率和业务稳定性。对于有定制化需求的场景,基于调度框架的插件开发是轻量高效的解决方案。
随着云原生生态的演进,调度器也在持续进化。Kueue 等批量调度项目为 AI/ML 工作负载提供了专业的队列管理和资源配额机制;Cluster Autoscaler 与调度器的联动实现了弹性扩缩容的自动化。深入理解调度器原理和管理策略,是构建高效稳定云原生基础设施的关键一步。

发表评论 取消回复