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)。调度器对每个候选节点执行以下评分逻辑:

  1. 遍历所有软约束规则,检查节点所在拓扑域是否满足该规则。
  2. 如果满足,则在该规则的权重基础上累加得分。
  3. 所有规则得分累加后,归一化到 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的分组。
Pod亲和性调度流程(拓扑域匹配) 待调度 Pod 读取 topologyKey 分组节点 检查分组内 labelSelector 匹配(亲和) 不匹配(反亲和) 选择该拓扑域节点 排除该拓扑域节点 调度到候选节点

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,以减少调度器需要检查的拓扑域数量。