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"]
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 图展示了这种协同调度策略。
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 分布是否符合反亲和性预期。