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 与调度器的联动实现了弹性扩缩容的自动化。深入理解调度器原理和管理策略,是构建高效稳定云原生基础设施的关键一步。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部