Skip to content

原生

概念

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(选节点)

  1. PreEnqueue:Queue 入口过滤
  2. EnqueueExtensionPoints:自定义 enqueue
  3. PreFilter:调度前预处理
  4. Filter:节点过滤(不满足资源 / 亲和性的剔除)
  5. PostFilter:过滤后处理(抢占前的最后机会)
  6. PreScore:评分前预处理
  7. Score:节点打分(最优节点)
  8. Reserve:资源预留(避免并发调度同一资源)
  9. Permit:批准 / 拒绝 / 等待

Binding Cycle(绑节点)

  1. PreBind:绑前预处理(如挂载卷)
  2. Bind:实际写 spec.nodeName
  3. 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 让自定义成为可能