3. 亲和性调度基础:nodeSelector、nodeAffinity、podAffinity、podAntiAffinity 概念与区别

在 Kubernetes 集群中,默认调度器(kube-scheduler)基于资源请求和可用节点进行 Pod 分配。但在证书轮换等场景中,我们需要更精细的控制:确保新 Pod 与旧 Pod 运行在同一节点(共享本地证书文件),或强制 Pod 分散到不同节点(避免单点故障)。Kubernetes 提供了四种亲和性调度机制,从简单到复杂,覆盖节点选择与 Pod 间关系。

3.1 四种调度机制总览

机制 作用对象 匹配目标 语义 强制/偏好
nodeSelector Pod → 节点 节点标签(简单键值对) 必须匹配所有指定标签 强制(硬约束)
nodeAffinity Pod → 节点 节点标签(支持表达式) 匹配一组规则(In/NotIn/Exists等) 强制 + 偏好
podAffinity Pod → Pod 目标 Pod 的标签 Pod 倾向于与目标 Pod 同拓扑域 强制 + 偏好
podAntiAffinity Pod → Pod 目标 Pod 的标签 Pod 倾向于与目标 Pod 不同拓扑域 强制 + 偏好
核心区别:nodeSelector 和 nodeAffinity 控制 Pod 与节点的关系;podAffinity 和 podAntiAffinity 控制 Pod 与其他 Pod 的关系。证书轮换零停机部署主要依赖 podAffinity(新旧 Pod 同节点)和 podAntiAffinity(避免同一节点上多个副本同时更新)。

3.2 nodeSelector:最简节点选择

nodeSelector 是 Kubernetes 最早提供的节点选择机制,通过在 Pod spec 中添加 nodeSelector 字段,指定一组键值对,调度器只会将 Pod 分配到同时满足所有标签的节点上。

apiVersion: v1
kind: Pod
metadata:
  name: cert-renewer
spec:
  nodeSelector:
    disktype: ssd
    zone: us-east-1a
  containers:
  - name: renewer
    image: cert-renewer:1.0
  • 优点:语法简单,适合快速固定节点类型(如 GPU 节点、SSD 节点)。
  • 缺点:仅支持等值匹配,无法表达“不在某组节点上”或“节点标签值大于某个版本号”等逻辑;所有条件必须同时满足,没有“偏好”模式。
  • 适用场景:证书轮换中,如果所有证书节点都打上统一标签(如 cert-node: true),可用 nodeSelector 快速定位。

3.3 nodeAffinity:增强的节点选择

nodeAffinity 是 nodeSelector 的进化版,支持丰富的匹配表达式和强制(required)与偏好(preferred)两种模式。它定义在 Pod spec 的 affinity.nodeAffinity 字段下。

apiVersion: v1
kind: Pod
metadata:
  name: cert-renewer-advanced
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/arch
            operator: In
            values:
            - amd64
            - arm64
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  containers:
  - name: renewer
    image: cert-renewer:1.0
字段 说明 示例
requiredDuringSchedulingIgnoredDuringExecution 硬约束:调度时必须满足,运行期间忽略节点标签变化 节点必须属于 amd64 或 arm64 架构
preferredDuringSchedulingIgnoredDuringExecution 软约束:调度时尽量满足,不满足仍可调度 优先选择 SSD 节点(权重 80)
operator 匹配操作符:In、NotIn、Exists、DoesNotExist、Gt、Lt In 表示值在列表中
weight 偏好权重(1-100),越高优先级越大 80 表示较高优先级
注意:nodeAffinity 的“运行期间忽略”意味着如果节点标签在 Pod 运行后被修改,已经运行的 Pod 不会重新调度。证书轮换场景中,我们通常依赖 Pod 启动时的节点选择,运行期间标签变化不影响已运行的 Pod。

3.4 podAffinity 与 podAntiAffinity:Pod 间关系控制

podAffinity 和 podAntiAffinity 将调度决策从“Pod 与节点”扩展到“Pod 与其他 Pod”。它们使用 拓扑域(topologyKey) 定义“同位置”的范围,例如同一节点、同一可用区或同一区域。

apiVersion: v1
kind: Pod
metadata:
  name: cert-consumer
  labels:
    app: cert-app
    version: v2
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - cert-app
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - cert-app
          topologyKey: kubernetes.io/hostname
  containers:
  - name: consumer
    image: cert-consumer:2.0
参数 podAffinity podAntiAffinity
语义 Pod 倾向于与匹配的 Pod 位于同一拓扑域 Pod 倾向于与匹配的 Pod 位于不同拓扑域
典型拓扑键 kubernetes.io/hostname(同节点)
topology.kubernetes.io/zone(同可用区)
同上
证书轮换用途 新 Pod 与旧 Pod 同节点,共享本地证书文件 同一应用的多个副本分散到不同节点,避免同时更新
性能影响 调度器需检查所有已调度 Pod 的标签,集群规模大时可能增加调度延迟 同上,且 anti-affinity 通常需要更多计算
证书轮换关键组合:在零停机部署中,我们通常同时使用 podAffinity(强制新 Pod 与旧 Pod 同节点)和 podAntiAffinity(偏好同一应用的不同副本分散到不同节点)。前者保证证书文件本地可用,后者保证更新过程中服务不中断。

3.5 四种机制对比 SVG 图

四种亲和性调度机制对比 nodeSelector Pod → 节点 等值匹配(key=value) 仅强制模式 无表达式支持 适合简单固定选择 nodeAffinity Pod → 节点 表达式匹配(In/NotIn等) 强制 + 偏好模式 支持权重(1-100) 适合复杂节点选择 podAffinity Pod → Pod 同拓扑域调度 强制 + 偏好模式 需指定 topologyKey 证书轮换:新旧同节点 podAntiAffinity Pod → Pod 不同拓扑域调度 强制 + 偏好模式 需指定 topologyKey 证书轮换:副本分散 关键区别总结 1. 作用对象不同 nodeSelector/nodeAffinity → 节点 podAffinity/podAntiAffinity → Pod 2. 表达能力不同 nodeSelector:仅等值匹配 nodeAffinity:表达式 + 权重 Pod 亲和性:标签选择器 + 拓扑域 3. 证书轮换用途 podAffinity → 新旧 Pod 同节点 podAntiAffinity → 副本分散 4. 性能影响 Pod 亲和性需检查所有 Pod 标签 大规模集群建议使用偏好模式

3.6 证书轮换场景中的选择建议

  1. 定位证书节点:使用 nodeSelector 或 nodeAffinity 将证书管理 Pod 调度到打了特定标签的节点组(如 cert-node: true)。
  2. 新旧 Pod 同节点:使用 podAffinity 配合 topologyKey: kubernetes.io/hostname,确保新 Pod 与旧 Pod 运行在同一节点,共享本地证书文件。
  3. 避免同时更新:使用 podAntiAffinity 配合 topologyKey: kubernetes.io/hostname,确保同一应用的多个副本分散到不同节点,更新时逐个替换,服务不中断。
  4. 性能考量:大规模集群中,Pod 亲和性调度会增加调度器负载。建议将关键场景设为 required,非关键场景设为 preferred 以降低调度压力。
最佳实践:在证书轮换部署中,通常将 podAffinity 设为 requiredDuringScheduling(必须同节点),将 podAntiAffinity 设为 preferredDuringScheduling(尽量分散)。这样既保证证书文件本地可用,又尽量提高可用性,同时避免因强制反亲和导致调度失败。