返回首页

K8s Pod 调度策略完全指南 — 六大机制全解析

📅 创建于 2026-05-13 🔄 更新于 2026-05-13 📝 716 字

K8s Pod 调度策略完全指南

Kubernetes 调度器(kube-scheduler)通过预选(Filtering)和优选(Scoring)决定 Pod 落在哪个节点。 默认行为在生产环境往往不够用。本文覆盖六大调度机制,附完整 YAML 配置和生产案例。

调度流程概览

调度策略的生效优先级从高到低:

  1. nodeName(最高优先级,直接指定节点名,跳过调度器)
  2. Taints / Tolerations(节点污点过滤)
  3. nodeSelector(简单标签匹配)
  4. nodeAffinity(灵活的节点亲和性)
  5. podAffinity / podAntiAffinity(Pod 间亲和/反亲和)
  6. topologySpreadConstraints(拓扑分散约束)
  7. 资源请求(节点剩余资源是否满足 requests)

六大调度机制

1. nodeSelector — 最简单的调度约束

通过标签键值对匹配节点,硬约束,无匹配节点则 Pod 永久 Pending。

spec:
  nodeSelector:
    disktype: ssd

适用场景: 简单场景,如"数据库必须跑在 SSD 节点"。复杂场景建议用 nodeAffinity。

2. nodeAffinity — 灵活的节点亲和性

支持多种操作符和软/硬约束结合:

操作符 含义
In 值在列表中
NotIn 值不在列表中
Exists 标签存在(不关心值)
DoesNotExist 标签不存在
Gt / Lt 大于/小于(仅数字值)
  • 硬约束: requiredDuringSchedulingIgnoredDuringExecution — 不满足不调度
  • 软约束: preferredDuringSchedulingIgnoredDuringExecution — 尽量满足,权重 1-100

⚠️ IgnoredDuringExecution 表示 Pod 已运行后,即使节点标签变了也不驱逐。Kubernetes 计划实现 RequiredDuringExecution 但尚未可用。

逻辑关系: 多个 nodeSelectorTerms 之间是 OR,同一 nodeSelectorTerm 中的多个 matchExpressions 是 AND。

3. podAffinity / podAntiAffinity — Pod 间亲和与反亲和

控制 Pod 之间的调度关系:

  • podAffinity: 让 Pod 和指定 Pod 部署在同一拓扑域(降低网络延迟)
  • podAntiAffinity: 让 Pod 远离指定 Pod(分散风险)

topologyKey 定义拓扑域:

  • kubernetes.io/hostname → 以节点为域
  • topology.kubernetes.io/zone → 以可用区为域

⚠️ 性能警告: podAffinity 计算复杂度为 O(N²),N 是集群 Pod 数量。5000+ Pod 的大集群中调度延迟可从 5ms 升至 200ms。优先用 topologySpreadConstraints 替代。

4. Taints & Tolerations — 节点专用化

从节点角度排斥 Pod,实现节点专用化(GPU 节点、数据库节点等):

Effect 对新 Pod 对已有 Pod 适用场景
NoSchedule 不调度 不影响 节点专用化
PreferNoSchedule 尽量不调度 不影响 软限制
NoExecute 不调度 驱逐 节点维护、故障隔离

常用内置污点:

  • node.kubernetes.io/not-ready:NoExecute
  • node.kubernetes.io/unreachable:NoExecute
  • node-role.kubernetes.io/control-plane:NoSchedule

tolerationSeconds: 容忍 NoExecute 污点的最长等待时间(到期后被驱逐)。

5. topologySpreadConstraints — 拓扑分散(推荐)

K8s 1.19 GA,比 podAntiAffinity 更精细地控制 Pod 在拓扑域间的分布:

参数 说明
maxSkew 域间 Pod 数量最大差值,1 = 严格均匀
topologyKey 拓扑域标签 key
whenUnsatisfiable DoNotSchedule(硬)/ ScheduleAnyway(软)
minDomains 最少拓扑域数量(1.25 Beta)

示例: 9 副本 + 3 zone + maxSkew=1 → 每个 zone 恰好 3 个 Pod。

✅ 生产环境跨故障域部署的首选方案。

6. PriorityClass — 优先级与抢占

高优先级 Pod 可抢占低优先级 Pod 的资源:

preemptionPolicy: PreemptLowerPriority  # 可抢占
preemptionPolicy: Never                 # 不抢占(批处理任务推荐)

⚠️ PreemptLowerPriority 会驱逐低优先级 Pod(收到 SIGTERM),确保应用能正确处理优雅关闭。生产环境建议批处理任务设 Never

生产案例

案例一:MySQL 主从集群调度

  • Master:nodeAffinity 锁定 SSD + database 节点,PriorityClass critical-production
  • Slave:podAntiAffinity 硬约束分散到不同节点,topologySpreadConstraints 跨 zone
  • 结果:Master 固定在 SSD 节点,Slave 分布在 zone-a/b/c 的不同节点

案例二:灰度发布调度

  • 灰度节点打标签 canary=true
  • 灰度 Deployment 通过 nodeAffinity 锁定灰度节点
  • 验证通过后更新稳定版镜像 + 缩容灰度 Deployment

最佳实践

性能优化

  1. 能用 topologySpreadConstraints 就不要用 podAntiAffinity(计算复杂度差别巨大)
  2. 合理设置 resource requests — 调度器按 requests 决策。设 P95 实际用量,避免过高(节点利用率低)或过低(OOMKill)
  3. 使用 Descheduler 重平衡 — 节点扩容/Pod 漂移后自动重新调度

安全加固

  1. 限制 nodeName 直接指定 — 通过 OPA/Gatekeeper 策略禁止(跳过所有调度检查)
  2. PriorityClass 权限控制 — RBAC 限制高优先级类的使用
  3. 节点污点防篡改 — 通过准入 webhook 拦截关键节点 taint 修改

高可用配置

  • 核心服务 ≥3 副本 + podAntiAffinity 硬约束 + topologySpreadConstraints 跨 zone
  • 使用 PodDisruptionBudget(PDB)限制同时不可用 Pod 数量
  • 调度策略配置(PriorityClass、节点标签、污点)纳入 GitOps

排障速查

现象 原因 排查命令
Pod Pending,0/N nodes available nodeSelector/Affinity 无匹配节点 kubectl get nodes --show-labels
调度成功但分布不均匀 topologySpreadConstraints labelSelector 写错 确认 labelSelector 与 Pod labels 一致
高优先级 Pod 抢占后,被抢占 Pod 无法恢复 集群资源不足 扩容节点或降低 requests
taint 添加后已有 Pod 没被驱逐 用了 NoSchedule 而非 NoExecute NoSchedule 只影响新 Pod
drain 卡住 PDB 限制 先扩容副本或临时调整 PDB minAvailable

监控告警

指标 正常 告警 含义
调度延迟 P99 <100ms >500ms 调度器过载或策略过于复杂
Pending Pod 数 0 >10(持续 5min) 持续有 Pod 无法调度
调度失败率 <1% >5% 资源不足或策略配置问题
节点 CPU 分配率 40-70% >85% 新 Pod 无法调度
抢占事件数 0 >5次/小时 资源规划不合理

命令速查表

# 节点标签管理
kubectl label node <node> key=value            # 添加标签
kubectl label node <node> key-                 # 删除标签
kubectl get nodes --show-labels                # 查看所有标签

# 污点管理
kubectl taint nodes <node> key=value:NoSchedule    # 添加污点
kubectl taint nodes <node> key=value:NoSchedule-   # 删除污点
kubectl describe node <node> | grep Taints         # 查看污点

# 调度排查
kubectl get events --field-selector reason=FailedScheduling -A
kubectl describe pod <pod> | grep -A 10 Events
kubectl top nodes

# 节点维护
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
kubectl cordon <node>         # 标记不可调度
kubectl uncordon <node>       # 恢复调度

关联页面

页面关联点
resource-rbac-scheduling-troubleshooting调度失败排障(Taint/OOMKill/RBAC)
k8s-resource-limits-configuration资源限制配置(Request/Limit/QoS)
k8s-statefulset-guideStatefulSet 与有状态应用调度
k8s-rolling-update-pitfalls滚动更新与灰度发布
k8s-troubleshooting-principlesK8s 排障基本原则
k8s-capacity-planning-qos-cost-optimizationK8s 容量规划方法论与成本优化 — 从流量到资源预算的完整框架,含 QoS 策略、弹性伸缩协同、落
k8s-pod-pending-troubleshooting-guidePod Pending 排障指南 — 7 个排查方向(资源不足/污点/亲和性/存储/配额/选择器/端
pod-troubleshootingPod 排障完整指南