4. Pod间亲和性(podAffinity):拓扑键、拓扑域、跨Pod调度约束
Pod间亲和性(podAffinity)与反亲和性(podAntiAffinity)是Kubernetes调度系统中用于控制Pod与Pod之间相对位置的核心规则。与节点亲和性(nodeAffinity)不同,Pod间亲和性不关心Pod被调度到哪台具体节点,而是关心“与哪些Pod靠在一起”或“远离哪些Pod”。
4.1 核心概念:拓扑键与拓扑域
Pod间亲和性的调度决策依赖于两个关键抽象:拓扑键(topologyKey)和拓扑域(topology domain)。
| 概念 | 定义 | 示例值 | 说明 |
|---|---|---|---|
| 拓扑键 | 节点标签的Key,用于划分拓扑域 | kubernetes.io/hostname |
每个节点拥有唯一值,形成最小拓扑域 |
| 拓扑域 | 共享同一拓扑键值的节点集合 | zone-a(所有topology.kubernetes.io/zone=zone-a的节点) |
域的大小取决于拓扑键的粒度 |
| 调度约束 | Pod必须/尽量与目标Pod位于同一拓扑域 | requiredDuringScheduling |
硬约束或软约束 |
关键理解:拓扑键决定了“以什么粒度来分组节点”。使用
kubernetes.io/hostname 意味着“同一台节点”;使用 topology.kubernetes.io/zone 意味着“同一个可用区”。拓扑域是拓扑键值相同的所有节点的集合。
4.2 调度约束类型
Pod间亲和性支持两种调度约束,与节点亲和性一致:
requiredDuringSchedulingIgnoredDuringExecution:硬约束。调度器必须满足该规则,否则Pod无法被调度。preferredDuringSchedulingIgnoredDuringExecution:软约束。调度器尽量满足,但不强制。
注意:“IgnoredDuringExecution”意味着一旦Pod运行后,即使后续Pod的标签发生变化,也不会驱逐已运行的Pod。Kubernetes目前不支持“RequiredDuringExecution”模式。
4.3 Pod间亲和性(podAffinity)工作原理
当使用podAffinity时,调度器会:
- 在集群中查找所有满足
labelSelector匹配条件的Pod。 - 获取这些Pod所在的节点。
- 根据
topologyKey确定这些节点所属的拓扑域。 - 将待调度Pod调度到这些拓扑域内的任意节点上。
4.4 Pod间反亲和性(podAntiAffinity)
podAntiAffinity 与 podAffinity 的配置结构完全相同,但语义相反:它要求待调度Pod不要与目标Pod位于同一拓扑域。常用于将同一应用的多个副本分散到不同节点或可用区,实现高可用。
典型场景:将Nginx的3个副本分散到3个不同的可用区。使用
podAntiAffinity + topologyKey: topology.kubernetes.io/zone + requiredDuringScheduling,确保每个可用区最多运行1个Nginx Pod。
4.5 配置示例与参数解析
以下是一个完整的Pod间亲和性配置示例:
apiVersion: v1
kind: Pod
metadata:
name: web-consumer
labels:
app: consumer
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: consumer
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:1.25
| 字段 | 路径 | 说明 |
|---|---|---|
labelSelector |
podAffinity[].podAffinityTerm |
选择目标Pod的标签匹配规则,支持 matchLabels 和 matchExpressions |
topologyKey |
podAffinity[].podAffinityTerm |
定义拓扑域的节点标签Key |
namespaces |
podAffinity[].podAffinityTerm |
可选,限定目标Pod所在的命名空间,默认与待调度Pod同命名空间 |
weight |
preferredDuringScheduling |
软约束的权重值,范围1-100,越高优先级越大 |
4.6 拓扑键选择策略
拓扑键的选择直接影响调度结果的分布粒度:
| 拓扑键 | 粒度 | 适用场景 | 注意事项 |
|---|---|---|---|
kubernetes.io/hostname |
节点级 | 将Pod调度到同一台节点(亲和)或分散到不同节点(反亲和) | 节点故障会导致所有同节点Pod不可用 |
topology.kubernetes.io/zone |
可用区级 | 将Pod调度到同一可用区(低延迟)或分散到不同可用区(高可用) | 需要集群已配置可用区标签 |
topology.kubernetes.io/region |
区域级 | 跨区域亲和或反亲和 | 区域间网络延迟较高 |
| 自定义标签 | 自定义 | 按机架、GPU池、专用硬件分组 | 需要运维确保标签一致性 |
避坑指南:
podAntiAffinity配合requiredDuringScheduling+topologyKey: kubernetes.io/hostname时,如果集群节点数少于Pod副本数,会导致部分Pod无法调度。- 不要将
topologyKey设置为空字符串,Kubernetes会拒绝该配置。 - 对于大规模集群,大量Pod间反亲和规则会增加调度器的计算开销,建议使用
preferred而非required。
4.7 与节点亲和性的对比
| 维度 | 节点亲和性(nodeAffinity) | Pod间亲和性(podAffinity) |
|---|---|---|
| 匹配对象 | 节点标签 | Pod标签 |
| 调度依据 | 节点自身属性(机型、区域、GPU等) | 集群中已运行的其他Pod的位置 |
| 拓扑域 | 隐式,通过节点标签分组 | 显式,通过 topologyKey 定义 |
| 典型场景 | 将Pod调度到SSD节点或特定区域 | 将Web Pod与Cache Pod部署在同一节点 |
| 配置复杂度 | 较低 | 较高,需考虑拓扑域和标签选择器 |
4.8 实践建议
- 优先使用软约束:在非关键场景下,使用
preferredDuringScheduling避免调度失败。 - 合理选择拓扑键粒度:对于高可用场景,使用
topology.kubernetes.io/zone;对于本地缓存亲和场景,使用kubernetes.io/hostname。 - 组合使用亲和与反亲和:例如,要求Web Pod与Redis Pod在同一节点(亲和),但Web Pod的多个副本分散到不同节点(反亲和)。
- 监控调度失败事件:使用
kubectl describe pod <pod-name>查看调度事件,排查亲和性规则是否导致Pod Pending。