主题
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/zone4. 污点与容忍(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:NoScheduleyaml
# 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: web6. 优先级与抢占(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-priority7. 面试高频问题
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