Skip to content

10 — 调度策略深度教材

调度策略决定 Pod 在哪里运行。本章覆盖调度框架、亲和性、污点容忍、优先级抢占、拓扑感知,配有生产 YAML 示例。


1. 调度器框架

调度器核心流程(简化):
  Pending Pod → PreFilter → Filter(排除不合格 Node)
  → Score(打分排序)→ Reserve → Bind → Running

Filter 阶段插件:
  NodeResourcesFit     → 资源是否足够
  NodeSelector         → nodeSelector 匹配
  TaintToleration      → 污点容忍
  NodeAffinity         → 节点亲和性
  PodTopologySpread    → 拓扑分布约束
  NodeUnschedulable    → 节点是否 cordoned

Score 阶段插件:
  LeastRequestedPriority → 资源使用率低的节点得分高
  BalancedResourceAllocation → CPU/内存均衡的节点得分高
  InterPodAffinity     → Pod 亲和性得分

2. 节点亲和性(Node Affinity)

yaml
# 硬性亲和性(必须满足)
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values: ["zone-a", "zone-b"]
          - key: node-type
            operator: In
            values: ["high-memory"]

# 软性亲和性(尽量满足,不满足也可调度)
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: gpu
            operator: In
            values: ["true"]
      - weight: 20
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values: ["ssd"]

3. Pod 亲和性与反亲和性

yaml
# Pod 反亲和性:避免 Pod 调度在同一节点(高可用)
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: web
        topologyKey: kubernetes.io/hostname  # 同一节点不能有两个 web Pod

# Pod 亲和性:尽量与缓存 Pod 调度在同一节点(减少网络延迟)
      podAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchLabels:
                app: redis
            topologyKey: topology.kubernetes.io/zone

4. 污点与容忍(Taint & Toleration)

bash
# 常见污点
kubectl taint nodes node1 key=value:NoSchedule    # 新 Pod 不调度
kubectl taint nodes node1 key=value:NoExecute     # 驱逐已有 Pod
kubectl taint nodes node1 key=value:PreferNoSchedule  # 尽量不调度

# 移除污点
kubectl taint nodes node1 key:NoSchedule-   # 注意末尾的 -

# 系统污点(节点问题时自动添加)
# node.kubernetes.io/not-ready:NoExecute    # 节点 NotReady
# node.kubernetes.io/unreachable:NoExecute  # 节点不可达
# node.kubernetes.io/disk-pressure:NoSchedule
# node.kubernetes.io/memory-pressure:NoSchedule
yaml
# Pod 容忍污点
spec:
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "ml-workload"
    effect: "NoSchedule"
  - key: "node.kubernetes.io/not-ready"
    operator: "Exists"
    effect: "NoExecute"
    tolerationSeconds: 300   # 容忍 300 秒后驱逐

5. 拓扑分布约束(Topology Spread)

yaml
# 跨可用区均匀分布 Pod
spec:
  topologySpreadConstraints:
  - maxSkew: 1               # 各区 Pod 数量差最多 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule  # 不满足则不调度
    labelSelector:
      matchLabels:
        app: web
  - maxSkew: 1               # 跨节点也均匀分布
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway  # 不满足则尽量调度
    labelSelector:
      matchLabels:
        app: web

6. 优先级与抢占(Priority & Preemption)

yaml
# 创建优先级类
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000        # 数值越大优先级越高
globalDefault: false
preemptionPolicy: PreemptLowerPriority  # 可抢占低优先级 Pod
---
# Pod 使用优先级
spec:
  priorityClassName: high-priority

7. 面试高频问题

Q: 如何实现跨可用区高可用?

1. topologySpreadConstraints: maxSkew=1, topologyKey=zone
2. podAntiAffinity: 不同节点
3. nodeAffinity: 限制可用区
4. PDB: 保护最低可用副本
5. Cluster Autoscaler: 按需扩容节点

Q: 如何把特定 Pod 调度到特定节点?

方案 A(推荐):nodeSelector + 节点标签
方案 B(更灵活):nodeAffinity required
方案 C(专用节点):节点加污点 + Pod 加容忍
方案 D(软性):nodeAffinity preferred + weight