3. 调度亲和性基础:Kubernetes 节点亲和性 (NodeAffinity) 与 Pod 亲和性 (PodAffinity) 的核心概念

在 Multus 多网卡场景中,Pod 不仅需要被调度到满足常规资源需求的节点上,还要求目标节点具备特定的网络接口(如 SR-IOV VF、DPDK 就绪状态或辅助网卡 VLAN 配置)。Kubernetes 调度亲和性机制正是实现这种“网络拓扑感知调度”的基石。本节将深入解析节点亲和性与 Pod 亲和性的核心概念、语法规则及在 Multus 环境下的典型应用。

3.1 节点亲和性 (NodeAffinity):将 Pod 绑定到特定网络能力的节点

节点亲和性允许你根据节点上的标签(Labels)来约束 Pod 可以被调度到哪些节点上。它取代了早期的 nodeSelector,提供了更灵活、表达能力更强的匹配规则。

3.1.1 节点亲和性类型

类型 语义 调度阶段 Multus 典型用途
requiredDuringSchedulingIgnoredDuringExecution 硬性要求:Pod 必须调度到满足规则的节点上,否则无法调度。 调度时 强制 Pod 运行在具备特定物理网卡(如 nic-type=mlx5)的节点上。
preferredDuringSchedulingIgnoredDuringExecution 软性偏好:调度器会优先选择满足规则的节点,但不强制。 调度时 优先将 Pod 调度到网络负载较低的节点(如 network-zone=low-latency)。
关键理解: 两种类型的后半部分 IgnoredDuringExecution 表示:如果节点在 Pod 运行后标签发生变化,导致规则不再满足,已运行的 Pod 不会被驱逐。这与 Pod 反亲和性的 RequiredDuringExecution 行为不同。

3.1.2 节点亲和性语法与匹配器

节点亲和性通过 nodeSelectorTerms 和 matchExpressions 定义匹配逻辑。支持以下操作符:

  • In:标签值在给定集合中。
  • NotIn:标签值不在给定集合中。
  • Exists:节点上存在该标签键(不关心值)。
  • DoesNotExist:节点上不存在该标签键。
  • Gt / Lt:标签值大于/小于给定数值(标签值需为数值字符串)。
apiVersion: v1
kind: Pod
metadata:
  name: multus-pod-nodeaffinity
  annotations:
    k8s.v1.cni.cncf.io/networks: '[
      {"name": "sriov-net",
       "interface": "net1"}
    ]'
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: "network.nic.type"
            operator: In
            values:
            - "mlx5"
            - "ice"
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 50
        preference:
          matchExpressions:
          - key: "network.bandwidth"
            operator: Gt
            values:
            - "10000"   # 单位 Mbps
  containers:
  - name: app
    image: busybox
    command: ["sleep", "3600"]
Multus 实践要点: 建议在集群节点上使用统一的标签体系来标记网络能力,例如 network.nic.vendor=intel、network.sriov.enabled=true、network.dpdk.supported=true。这能显著简化调度策略的维护。

3.2 Pod 亲和性 (PodAffinity) 与反亲和性 (PodAntiAffinity):控制 Pod 间的网络拓扑关系

Pod 亲和性/反亲和性根据节点上已运行 Pod 的标签来决定调度位置。这在 Multus 场景中至关重要,例如:将需要高速通信的两个 Pod 调度到同一台机器(亲和性),或将高网络负载的 Pod 分散到不同节点(反亲和性)。

3.2.1 核心概念与类型

概念 作用 Multus 应用场景
PodAffinity 将 Pod 调度到与某些 Pod 相同的拓扑域(如节点、机架)。 将数据生产者 Pod 与消费者 Pod 调度到同一节点,利用本地内存或本地网络加速。
PodAntiAffinity 将 Pod 调度到与某些 Pod 不同的拓扑域。 将多个使用 SR-IOV VF 的 Pod 分散到不同节点,避免单节点 VF 资源耗尽。

与节点亲和性类似,Pod 亲和性也分为 requiredDuringSchedulingIgnoredDuringExecution(硬性)和 preferredDuringSchedulingIgnoredDuringExecution(软性)。

3.2.2 topologyKey:定义拓扑域

topologyKey 是 Pod 亲和性/反亲和性的核心参数,它指定了用于划分拓扑域的节点标签键。常见的 topologyKey 包括:

  • kubernetes.io/hostname:节点级别(最严格)。
  • topology.kubernetes.io/zone:可用区级别。
  • topology.kubernetes.io/region:地域级别。
  • 自定义标签,如 network.rack.id:机架级别。
调度性能警告: 使用 requiredDuringScheduling 的 Pod 反亲和性且 topologyKey=kubernetes.io/hostname 时,如果集群中 Pod 副本数接近节点数,调度器可能陷入“死锁”,导致大量 Pod 处于 Pending 状态。建议对大规模集群使用软性反亲和性或更粗粒度的 topologyKey。

3.2.3 Pod 反亲和性示例:分散 SR-IOV Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sriov-workload
spec:
  replicas: 4
  selector:
    matchLabels:
      app: sriov-app
  template:
    metadata:
      labels:
        app: sriov-app
      annotations:
        k8s.v1.cni.cncf.io/networks: sriov-net
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: "app"
                operator: In
                values:
                - "sriov-app"
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: dpdk-worker
        image: dpdk-app:latest

上述配置确保每个节点上最多运行一个 sriov-workload Pod,从而避免单节点 SR-IOV VF 数量不足或 PCIe 带宽争抢。

3.3 节点亲和性与 Pod 亲和性的协同:构建网络拓扑感知调度

在 Multus 环境中,通常需要组合使用两种亲和性来满足复杂的网络需求。下面的 SVG 图展示了这种协同调度策略。

Multus 场景下节点亲和性与 Pod 亲和性协同调度策略 阶段 1:节点亲和性过滤 (NodeAffinity) required: network.nic.type In (mlx5, ice) preferred: network.bandwidth Gt 10000 候选节点列表 阶段 2:Pod 亲和性/反亲和性 (PodAffinity / PodAntiAffinity) podAntiAffinity: app=sriov-app topologyKey: kubernetes.io/hostname 最终调度结果 节点 A (mlx5, 25Gbps) Pod-1 (sriov-app) ✅ 节点 B (mlx5, 25Gbps) Pod-2 (sriov-app) ✅ 节点 C (ice, 10Gbps) Pod-3 (sriov-app) ❌ 带宽不足 调度决策

3.4 调度亲和性在 Multus 故障排查中的价值

当 Multus 网络出现异常时,调度亲和性配置往往是排查的起点:

  • Pod 一直 Pending:检查 requiredDuringScheduling 的节点亲和性是否过于严格,导致没有节点满足网络标签条件。
  • Pod 启动后网络不通:确认 Pod 是否被调度到了不具备对应 Multus 网络附加定义(NAD)所需底层网卡的节点上。
  • SR-IOV VF 分配失败:检查 Pod 反亲和性是否有效,避免多个 Pod 争抢同一节点的 VF 资源。
  • 网络性能不达标:验证 preferredDuringScheduling 的权重设置是否合理,确保高带宽 Pod 优先调度到高速网卡节点。
排查命令速查:
kubectl describe pod <pod-name> — 查看 Events 字段中的调度失败原因。
kubectl get nodes --show-labels — 检查节点标签是否符合亲和性规则。
kubectl get pods -o wide --selector=app=sriov-app — 查看 Pod 分布是否符合反亲和性预期。