Wiki LogoWiki - The Power of Many

Kubernetes 调度器: 放置 Pod 的艺术

深入解析 kube-scheduler 的工作流程, 调度框架插件机制, 亲和性策略及抢占机制.

kube-scheduler 是 Kubernetes 的核心决策者. 它的任务是根据一系列规则, 在庞大的节点资源池中为待调度的 Pod 找到最合适的 "家".


1. 调度器架构

1.1 调度上下文

对象描述
Pod待调度的工作负载
Node候选节点列表
PodInfoPod 的调度相关信息缓存
NodeInfo节点资源快照

2. 调度的两个阶段

当一个 Pod 进入调度队列时, 调度器会经历两个核心阶段:

2.1 过滤阶段 (Filtering/Predicates)

排除不符合条件的节点:

过滤器检查内容
PodFitsResourcesCPU/内存资源是否充足
PodFitsHostPortsHostPort 是否被占用
PodMatchNodeSelectornodeSelector 是否匹配
PodToleratesNodeTaintsPod 是否容忍节点 Taints
CheckNodeUnschedulable节点是否可调度
CheckVolumeBindingPV 是否可绑定
InterPodAffinityPod 亲和性规则检查

2.2 打分阶段 (Scoring/Priorities)

在候选节点中打分排序:

打分器策略
LeastRequestedPriority倾向资源占用少的节点 (负载均衡)
BalancedResourceAllocationCPU/内存使用比例均衡
ImageLocality倾向已有所需镜像的节点
NodeAffinityPriority满足 preferredNodeAffinity
InterPodAffinityPriority满足 podAffinity/antiAffinity
TaintTolerationPriority容忍更多 Taints 的节点得分更高

3. 调度框架 (Scheduling Framework)

Kubernetes 1.19+ 引入了插件化的调度框架, 将调度过程分为多个扩展点:

3.1 扩展点说明

扩展点阶段作用
QueueSort入队决定 Pod 在队列中的顺序
PreFilter预处理检查 Pod 先决条件
Filter过滤排除不合格节点
PostFilter后处理处理无可用节点的情况 (抢占)
PreScore打分前准备打分所需信息
Score打分为节点评分
Reserve预留预留节点资源
Permit许可批准/拒绝/等待绑定
PreBind绑定前执行绑定前置操作
Bind绑定将 Pod 绑定到节点
PostBind绑定后清理或通知操作

3.2 自定义调度插件

type Plugin interface {
    Name() string
}

type FilterPlugin interface {
    Plugin
    Filter(ctx context.Context, state *CycleState, pod *v1.Pod, nodeInfo *NodeInfo) *Status
}

type ScorePlugin interface {
    Plugin
    Score(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) (int64, *Status)
}

4. 亲和性与反亲和性

4.1 Node Affinity

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬性要求
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values: ["ssd"]
      preferredDuringSchedulingIgnoredDuringExecution:  # 软性偏好
      - weight: 100
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values: ["zone-a"]

4.2 Pod Affinity / Anti-Affinity

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: cache
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: web
          topologyKey: topology.kubernetes.io/zone
字段含义
topologyKey定义 "同一位置" 的标准 (主机名, 机架, 可用区)
labelSelector匹配目标 Pod 的标签
namespaceSelector跨 Namespace 匹配

5. Taints 与 Tolerations

5.1 Taint 效果

Effect行为
NoSchedule不调度新 Pod
PreferNoSchedule尽量不调度
NoExecute驱逐已有 Pod
# 添加 Taint
kubectl taint nodes node1 key=value:NoSchedule

# 移除 Taint
kubectl taint nodes node1 key=value:NoSchedule-

5.2 Toleration

spec:
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
  - key: "key"
    operator: "Exists"
    effect: "NoExecute"
    tolerationSeconds: 3600  # 容忍 1 小时后驱逐

6. 优先级与抢占

6.1 PriorityClass

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: "用于关键业务"

6.2 抢占机制

当高优先级 Pod 无法调度时:

  1. 调度器尝试寻找可抢占的低优先级 Pod
  2. 选择 "牺牲者" 使高优先级 Pod 可调度
  3. 优雅终止被抢占的 Pod
  4. 调度高优先级 Pod

7. Descheduler (反调度器)

调度器只负责 Pod 的初始放置. Descheduler 可以重新平衡已运行的 Pod:

7.1 使用场景

  • 节点资源利用率不均衡
  • 新节点加入集群
  • 节点 Taint 变更
  • Pod 亲和性规则违反

7.2 常用策略

策略作用
RemoveDuplicates移除同节点上的重复 Pod
LowNodeUtilization从高负载节点迁移到低负载节点
RemovePodsViolatingInterPodAntiAffinity移除违反反亲和性的 Pod
RemovePodsViolatingNodeAffinity移除违反节点亲和性的 Pod
RemovePodsViolatingTopologySpreadConstraint重新平衡拓扑分布

8. Topology Spread Constraints

控制 Pod 在拓扑域间的分布:

spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: web
  - maxSkew: 2
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway
字段含义
maxSkew允许的最大差异
topologyKey拓扑域标签
whenUnsatisfiable不满足时的行为

默认调度器能满足 90% 的场景. 剩下的 10% 需要通过 Affinity, Taints, PriorityClass 以及合理的 Resource Quota 来进行精细化微调.

On this page