概述
三个副本落在同一个节点上,可用性就等同于一个节点。调度器主要依据资源匹配与打分放置 Pod,因此一台资源充足的空节点可能接收某个 Deployment 的全部副本。拓扑分布约束增加了分布规则:带有相同标签的 Pod 会在 zone 或 host 等拓扑域之间平衡。硬约束(DoNotSchedule)拒绝放置会破坏偏斜上限的 Pod,软约束(ScheduleAnyway)优先平衡但在无法满足时仍然调度。
步骤
- 同时设置硬性的可用区约束与软性的节点偏好:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: payments
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: payments
- 确认所有可调度节点都带有可用区标签:
kubectl get nodes -L topology.kubernetes.io/zone
- 发布后检查 Pod 的实际落点:
kubectl get pods -n prod -l app=payments -o wide
kubectl get nodes -L topology.kubernetes.io/zone
- 缩容再扩容,验证约束仍会重新平衡:
kubectl scale deployment/payments --replicas=1 -n prod
kubectl scale deployment/payments --replicas=3 -n prod
验证
Pod 应分布在不同节点,且这些节点属于不同可用区;缩容到 1 再扩回 3 后,空出的可用区应被重新填充,而不是全部堆在第一个节点。若 Pod 处于 Pending,说明当前可用区数量或容量无法满足偏斜上限,应先确认容量,必要时设置 minDomains 或改用软约束。
注意事项
- 硬约束在可用区满载或缺失时会导致 Pod Pending。
- 分布只控制放置位置,不提供容量,每个可用区仍需足够 CPU 与内存。
- 标签选择器应使用稳定的 app 标签,而不是带版本号的标签。
maxSkew设为 1 适合小副本数,过大的值会容忍你本想避免的失衡。- 滚动更新期间放置会变化,发布后需要重新检查实际分布。