原生
概念
K8s 默认调度器(kube-scheduler)是 Pod-by-Pod 的通用调度器,从 1.19 起 Scheduler Framework + Plugin API 让用户可以 in-tree / out-of-tree 写插件,扩展能力。
- 项目:kubernetes/kubernetes/cmd/kube-scheduler
- 架构:Scheduler Framework,调度分阶段,每阶段可插拔
- 替代关系:跟 Volcano / YuniKorn 是 共存,不是取代
Scheduler Framework 阶段
调度一个 Pod 走两阶段(每个阶段都有 Plugin Point):
Scheduling Cycle(选节点)
- PreEnqueue:Queue 入口过滤
- EnqueueExtensionPoints:自定义 enqueue
- PreFilter:调度前预处理
- Filter:节点过滤(不满足资源 / 亲和性的剔除)
- PostFilter:过滤后处理(抢占前的最后机会)
- PreScore:评分前预处理
- Score:节点打分(最优节点)
- Reserve:资源预留(避免并发调度同一资源)
- Permit:批准 / 拒绝 / 等待
Binding Cycle(绑节点)
- PreBind:绑前预处理(如挂载卷)
- Bind:实际写 spec.nodeName
- PostBind:绑后清理
自定义插件
Out-of-tree Plugin(推荐)
写一个 binary,注册到 kube-scheduler 配置:
# scheduler-config.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
plugins:
multiPoint:
enabled:
- name: MyCustomPlugin
disabled:
- name: DefaultPodTopologySpread
pluginConfig:
- name: MyCustomPlugin
args: |
{"myConfigKey": "myValue"}
自定义调度器二进制(独立 scheduler)
跟默认 scheduler 并存,指定 schedulerName:
cmd := scheduler.NewOptions()
cmd.ConfigFile = "my-scheduler.yaml"
cmd.SecureServing.ServingOptions.BindPort = 10260
// 注册自定义 plugin
registry := runtime.Registry{}
registry.Add("MyPlugin", func(_ context.Context, _ runtime.Object, _ framework.Handle) (framework.Plugin, error) {
return &MyPlugin{}, nil
})
sched, _ := scheduler.New(cmd, registry)
// cmd.Execute()
Pod 指定:
spec:
schedulerName: my-scheduler
...
内置插件(1.30+)
| 插件 | 功能 |
|---|---|
| NodeResourcesFit | 资源(CPU / 内存 / GPU)满足 |
| NodeAffinity / NodeName | nodeSelector / 亲和性 |
| PodAffinity / AntiAffinity | Pod 间亲和 / 反亲和 |
| TaintToleration | 污点容忍 |
| TopologySpread | Pod 跨拓扑分布 |
| VolumeBinding | PV 绑定 |
| DefaultBinder | 绑节点(默认) |
| ImageLocality | 镜像本地优先 |
| InterPodAffinity | Pod 亲和优先级 |
| PodSchedulingReadiness | Pod 调度就绪条件(schedulingGates) |
| DRA | Dynamic Resource Allocation |
Scheduler Extender(旧方案,1.32+ 不推荐)
HTTP 调用外部服务:
extenders:
- urlPrefix: "http://my-extender:8080"
filterVerb: filter
scoreVerb: score
managedResources:
- name: "example.com/foo"
ignorable: false
性能差(每次 HTTP 调用),新项目直接用 Plugin API。
优缺点
- ✅ K8s 原生,默认就是它
- ✅ 调度框架灵活,插件机制完整
- ✅ 内置插件覆盖大多数场景
- ✅ 性能优秀(in-process,无 HTTP)
- ❌ 不懂 Gang / Queue / 抢占批处理语义
- ❌ 不懂 GPU 拓扑(要靠 node label)
- ❌ 大集群(>5k 节点)有性能压力
适用场景
- 大多数常规 workload(Deployment / StatefulSet / DaemonSet)
- 服务型应用(web / API / 中间件)
- 通用 K8s 集群默认
- 写自定义调度逻辑(用 Plugin API)
跟 Volcano / YuniKorn 共存
# 普通 Pod 用默认
spec:
containers: ...
# Volcano Job
spec:
schedulerName: volcano
...
# YuniKorn 通过 label 自动识别
spec:
labels:
applicationId: "my-app"
queue: "production.ads"
监控 / 排查
# scheduler 日志
kubectl -n kube-system logs kube-scheduler-<master>
# 调度延迟 metrics
scheduler_pending_pods
scheduler_e2e_scheduling_duration_seconds
scheduler_binding_duration_seconds
scheduler_queue_incoming_pods_total
# Pod 调度失败原因
kubectl describe pod <pending-pod> | grep -A 5 Events
一句话
K8s 默认调度器,Scheduler Framework + Plugin API 让自定义成为可能。