3. 调度亲和性概念:节点亲和性、Pod亲和性、Pod反亲和性

在 Kubernetes 调度系统中,亲和性(Affinity)与反亲和性(Anti-Affinity)是比简单 nodeSelector 更灵活、表达能力更强的调度约束机制。它们允许调度器根据节点或 Pod 的标签(Label)做出精细化决策,是解决资源竞争、高可用部署、故障域隔离等场景的核心工具。

亲和性分为三大类:节点亲和性(nodeAffinity)、Pod 亲和性(podAffinity)和Pod 反亲和性(podAntiAffinity)。理解它们的区别与适用场景,是排查因资源竞争导致 CrashLoop 的前提。

3.1 三类亲和性对比总览

类型 作用对象 匹配依据 典型用途 调度阶段
nodeAffinity Pod → 节点 节点标签(node labels) 将 Pod 调度到特定硬件(如 GPU)、可用区、机型 预选 + 优选
podAffinity Pod → Pod 目标 Pod 的标签 + 拓扑域 将相关 Pod 调度到同一拓扑域(如同一节点、同一可用区) 预选
podAntiAffinity Pod → Pod 目标 Pod 的标签 + 拓扑域 将 Pod 分散到不同拓扑域,避免单点故障或资源争抢 预选
关键区别:nodeAffinity 关注“Pod 应该去哪些节点”;podAffinity 关注“Pod 应该和哪些 Pod 在一起”;podAntiAffinity 关注“Pod 应该远离哪些 Pod”。在资源竞争场景中,podAntiAffinity 是防止多个高负载 Pod 挤在同一节点上的主要手段。

3.2 节点亲和性(nodeAffinity)

节点亲和性允许你使用 In、NotIn、Exists、DoesNotExist、Gt、Lt 等操作符来定义调度规则。它分为两种模式:

  • requiredDuringSchedulingIgnoredDuringExecution:硬约束,调度时必须满足,否则 Pod 无法被调度(Pending)。
  • preferredDuringSchedulingIgnoredDuringExecution:软约束,调度器尽量满足,但不强制;权重越高,优先级越大。
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: accelerator
            operator: In
            values:
            - nvidia-tesla-v100
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - us-east-1a
  containers:
  - name: gpu-container
    image: nvidia/cuda:12.0-base
CrashLoop 关联:当节点资源(CPU、内存、磁盘 IO)被大量占用时,即使 nodeAffinity 硬约束满足,Pod 仍可能因资源竞争导致 OOMKilled 或健康检查失败。此时需要结合 podAntiAffinity 将同类 Pod 分散到不同节点。

3.3 Pod 亲和性(podAffinity)

Pod 亲和性用于将一组 Pod 调度到相同的拓扑域中。拓扑域由 topologyKey 指定,常见取值包括 kubernetes.io/hostname(同一节点)、topology.kubernetes.io/zone(同一可用区)。

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cache
        topologyKey: kubernetes.io/hostname

上述配置要求:当前 Pod 必须被调度到至少运行了一个 app=cache Pod 的节点上。如果没有任何节点满足,Pod 将处于 Pending 状态。

注意:podAffinity 会增加节点上的 Pod 密度。如果目标 Pod 本身是高资源消耗型,盲目使用 podAffinity 可能加剧资源竞争,导致新 Pod 启动后立即 CrashLoop。

3.4 Pod 反亲和性(podAntiAffinity)

Pod 反亲和性是解决资源竞争和高可用的核心工具。它确保同一组 Pod 不会集中部署在同一个拓扑域中。

spec:
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - web-server
          topologyKey: kubernetes.io/hostname

上述配置表示:尽量将 app=web-server 的 Pod 分散到不同节点上(软约束)。如果改为 requiredDuringSchedulingIgnoredDuringExecution,则强制每个节点最多只能运行一个该类型的 Pod。

CrashLoop 排查要点:当集群节点资源紧张时,如果多个高负载 Pod 因缺少反亲和性而挤在同一节点,会导致 CPU 节流、内存 OOM、磁盘 IO 争抢,进而触发健康检查失败和 CrashLoop。此时添加 podAntiAffinity 并配合 topologyKey: kubernetes.io/hostname 是最直接的修复手段。

3.5 亲和性调度决策流程(SVG)

下图展示了调度器在处理亲和性规则时的完整决策路径:

Kubernetes 亲和性调度决策流程 亲和性调度决策流程 Pod 创建请求 节点预选:nodeAffinity 硬约束检查 Pod 亲和性/反亲和性检查 拓扑域匹配(topologyKey 评估) 优选评分(软约束权重累加) 绑定到目标节点 关键说明 • nodeAffinity 硬约束 不满足 → Pending • podAntiAffinity 硬约束 不满足 → Pending • 软约束不满足 仍可调度,但优先级低

3.6 亲和性配置对比速查表

配置项 nodeAffinity podAffinity podAntiAffinity
匹配对象 节点标签 Pod 标签 + topologyKey Pod 标签 + topologyKey
硬约束关键字 requiredDuringScheduling... requiredDuringScheduling... requiredDuringScheduling...
软约束关键字 preferredDuringScheduling... preferredDuringScheduling... preferredDuringScheduling...
常用 topologyKey 不适用 kubernetes.io/hostname
topology.kubernetes.io/zone
kubernetes.io/hostname
topology.kubernetes.io/zone
对资源竞争的影响 间接(选择资源充足的节点) 可能加剧(将 Pod 聚拢) 缓解(将 Pod 分散)
典型 CrashLoop 场景 节点标签变更导致调度失败 目标 Pod 所在节点资源耗尽 缺少反亲和性导致节点过载

3.7 实战建议:资源竞争场景下的亲和性策略

  • 优先使用 podAntiAffinity:对于无状态高负载服务(如 Web 服务器、数据处理 Pod),始终添加 preferredDuringScheduling 级别的反亲和性,避免多个副本挤在同一节点。
  • 谨慎使用 podAffinity:仅当 Pod 间有强通信依赖(如 sidecar 与主容器、缓存与计算)且通信延迟敏感时使用,同时确保目标节点有足够资源余量。
  • nodeAffinity 配合资源预留:使用 nodeAffinity 将特定 Pod 调度到专用节点池,并结合 resources.requests 和 limits 防止资源争抢。
  • 监控拓扑域分布:使用 kubectl get pods -o wide 检查 Pod 的节点分布,若发现多个高负载 Pod 集中在同一节点,立即评估是否缺少反亲和性配置。