3. Pod亲和性与反亲和性:podAffinity、podAntiAffinity、拓扑键与权重
Pod亲和性与反亲和性是Kubernetes调度器将Pod实例按照业务逻辑进行分组或隔离的核心机制。与节点亲和性(nodeAffinity)不同,Pod亲和性基于已经运行在集群中的Pod标签来决定调度目标,而非节点本身的标签。这一特性在微服务就近部署、可用区容灾、缓存局部性等场景中至关重要。
3.1 核心概念与调度语义
Pod亲和性调度规则定义在Pod规约的 spec.affinity.podAffinity 和 spec.affinity.podAntiAffinity 字段中。调度器在执行调度时,会先根据拓扑键(topologyKey)划分候选节点组,再检查该组内是否已存在满足标签选择器(labelSelector)的Pod,最后根据权重(weight)计算得分。
| 字段 | 语义 | 调度行为 | 典型场景 |
|---|---|---|---|
podAffinity |
Pod亲和性 | 将Pod调度到已有目标Pod所在的拓扑域 | Web与缓存同节点部署,减少网络延迟 |
podAntiAffinity |
Pod反亲和性 | 将Pod调度到没有目标Pod的拓扑域 | 多副本跨可用区部署,避免单点故障 |
关键区别:节点亲和性匹配的是节点标签(如
kubernetes.io/hostname),而Pod亲和性匹配的是Pod标签(如 app: redis)。调度器通过拓扑键将Pod标签匹配结果映射到节点分组上。
3.2 拓扑键(topologyKey)—— 分组边界
拓扑键是Pod亲和性规则的分组依据。调度器使用拓扑键对应的节点标签值来划分拓扑域,同一个拓扑域内的节点被视为一个调度单元。常见的拓扑键包括:
kubernetes.io/hostname—— 以节点为粒度(最严格)topology.kubernetes.io/zone—— 以可用区为粒度topology.kubernetes.io/region—— 以地域为粒度- 自定义标签 —— 如
rack、datacenter
避坑提示:对于
requiredDuringScheduling 类型的反亲和性,拓扑键不能为空,且通常建议使用 kubernetes.io/hostname 以确保每个节点最多运行一个目标Pod。如果使用 topology.kubernetes.io/zone,则整个可用区只能运行一个目标Pod,可能导致资源利用率下降。
3.3 调度策略类型:required vs preferred
与节点亲和性一致,Pod亲和性也分为硬约束(required)和软约束(preferred)两种类型。
| 类型 | 字段前缀 | 行为 | 调度失败后果 |
|---|---|---|---|
| 硬约束 | requiredDuringSchedulingIgnoredDuringExecution |
必须满足规则,否则Pod无法调度 | Pod 处于 Pending 状态 |
| 软约束 | preferredDuringSchedulingIgnoredDuringExecution |
尽量满足规则,不满足时仍可调度 | Pod 正常调度,但得分较低 |
3.4 权重(weight)与多规则评分
在 preferredDuringScheduling 中,每条规则可以设置 weight(1~100)。调度器对每个候选节点执行以下评分逻辑:
- 遍历所有软约束规则,检查节点所在拓扑域是否满足该规则。
- 如果满足,则在该规则的权重基础上累加得分。
- 所有规则得分累加后,归一化到 0~100 区间。
权重设计原则:
- 高权重(如 100)用于关键亲和性需求,如缓存与计算同节点。
- 低权重(如 10~30)用于倾向性建议,如尽量分散但允许集中。
- 多个反亲和性规则可以叠加,实现“优先跨可用区,其次跨节点”的分级调度。
3.5 完整配置示例
apiVersion: v1
kind: Pod
metadata:
name: web-server
labels:
app: web
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cache
topologyKey: kubernetes.io/hostname
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: topology.kubernetes.io/zone
containers:
- name: nginx
image: nginx:1.25
上述配置含义:
- 硬亲和:web-server 必须与带有
app=cache标签的 Pod 运行在同一节点上。 - 软反亲和:web-server 尽量不与带有
app=web标签的 Pod 处于同一可用区,权重为 100。
3.6 调度流程与拓扑域匹配
理解拓扑域匹配:调度器首先获取所有节点的拓扑键值,将节点分组。然后检查每个分组内是否至少有一个Pod满足
labelSelector。对于亲和性,调度器会选择包含目标Pod的分组中的节点;对于反亲和性,调度器会排除包含目标Pod的分组。
3.7 实战设计模式与避坑
| 模式 | 配置要点 | 注意事项 |
|---|---|---|
| 缓存与计算同节点 | podAffinity + topologyKey: kubernetes.io/hostname |
确保缓存Pod先于计算Pod创建,否则计算Pod无法调度 |
| 多副本跨可用区 | podAntiAffinity + topologyKey: topology.kubernetes.io/zone |
可用区数量必须 ≥ 副本数,否则硬约束会导致部分副本Pending |
| 分级反亲和(先zone后host) | 两条 preferred 规则,不同权重 |
权重差值不宜过小(建议 ≥ 30),否则评分区分度不足 |
| StatefulSet 严格分散 | required 反亲和 + topologyKey: kubernetes.io/hostname |
集群节点数必须 ≥ StatefulSet 副本数 |
性能考量:Pod亲和性调度会增加调度器的计算开销,因为调度器需要为每个候选节点查询该拓扑域内所有Pod的标签。在集群规模较大(节点数 > 500)时,建议优先使用节点亲和性 + 节点标签来替代部分Pod亲和性场景,以减少调度延迟。
3.8 拓扑键选择与调度器参数联动
调度器参数 --failure-domains 和 --soft-pod-affinity-weight 会影响Pod亲和性的评分行为。在调度器配置文件中,可以通过 profiles.pluginConfig 调整 InterPodAffinity 插件的参数:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
pluginConfig:
- name: InterPodAffinity
args:
hardPodAffinityWeight: 1 # 硬亲和性权重系数(默认0)
softPodAffinityWeight: 50 # 软亲和性权重缩放因子(默认0)
hardPodAffinityWeight:设置为非零值时,硬约束也会参与评分,影响多调度器场景下的优先级排序。softPodAffinityWeight:调整软约束评分的整体权重,值越大,软约束对最终调度决策的影响越强。
最佳实践:在大型集群中,建议将
softPodAffinityWeight 设置为 30~50,避免软约束过度影响调度均衡性。同时,拓扑键尽量使用 topology.kubernetes.io/zone 而非 kubernetes.io/hostname,以减少调度器需要检查的拓扑域数量。