4. 节点亲和性语法详解:matchExpressions、matchFields 与 operator
节点亲和性(Node Affinity)是 Kubernetes 调度器将 Pod 绑定到特定节点池的核心机制。在滚动升级场景中,通过精确的亲和性规则,可以确保新 Pod 只调度到已升级的节点,从而控制流量迁移粒度。本节深入解析 matchExpressions、matchFields 以及六种 operator 的完整语法与实战用法。
4.1 节点亲和性规则结构
节点亲和性定义在 Pod 的 spec.affinity.nodeAffinity 字段下,包含两种规则类型:
| 规则类型 | 字段路径 | 语义 | 典型场景 |
|---|---|---|---|
| requiredDuringSchedulingIgnoredDuringExecution | nodeSelectorTerms[] |
硬性约束,调度时必须满足,否则 Pod 无法调度 | 强制 Pod 运行在特定节点池(如已升级节点) |
| preferredDuringSchedulingIgnoredDuringExecution | preference.matchExpressions |
软性偏好,调度器尽量满足,但不强制 | 优先调度到某节点池,但允许降级到其他节点 |
两种规则内部都使用 matchExpressions 或 matchFields 定义选择条件。每个条件由 key、operator 和 values(部分 operator 不需要)组成。
4.2 matchExpressions:基于节点标签的选择
matchExpressions 是最常用的选择器,它根据节点的 标签(Label) 进行匹配。节点标签是键值对,例如 node-pool: upgraded、zone: us-east-1。
node-pool-version: v2),然后通过 matchExpressions 让新 Pod 只选择这些节点。
4.2.1 operator 详解
Kubernetes 为 matchExpressions 提供了六种 operator,覆盖了从精确匹配到存在性检查的完整需求:
| operator | 是否需要 values | 匹配逻辑 | 典型用途 |
|---|---|---|---|
| In | 是(至少1个) | 节点的 label value 在 values 列表中 | 精确匹配节点池版本、区域 |
| NotIn | 是(至少1个) | 节点的 label value 不在 values 列表中 | 排除特定节点(如旧版本节点) |
| Exists | 否 | 节点存在该 label key(无论 value 是什么) | 检查节点是否属于某类(如 GPU 节点) |
| DoesNotExist | 否 | 节点不存在该 label key | 排除具有特定标签的节点 |
| Gt | 是(1个数值字符串) | 节点的 label value(数值)大于 values 中的值 | 选择资源充足的节点(如剩余 CPU > 4) |
| Lt | 是(1个数值字符串) | 节点的 label value(数值)小于 values 中的值 | 选择负载较低的节点 |
Gt 和 Lt 要求 label value 必须是可以解析为数字的字符串(如 "8"),否则调度器会忽略该表达式。对于非数值标签,请使用 In 或 NotIn。
4.2.2 实战代码示例
以下 YAML 展示了一个完整的节点亲和性配置,使用 matchExpressions 实现滚动升级中的流量控制:
apiVersion: v1
kind: Pod
metadata:
name: app-v2
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-pool-version
operator: In
values:
- "v2"
- key: node-type
operator: NotIn
values:
- "spot"
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: zone
operator: In
values:
- "us-east-1a"
- key: cpu-capacity
operator: Gt
values:
- "8"
containers:
- name: app
image: myapp:2.0
规则解读:
- 硬性规则: Pod 必须调度到
node-pool-version=v2且node-type不是spot的节点。这确保了新版本 Pod 只进入已升级的节点池,并排除竞价实例。 - 软性偏好: 在满足硬性规则的基础上,优先选择
zone=us-east-1a且cpu-capacity大于 8 的节点,权重为 80。
4.3 matchFields:基于节点字段的选择
matchFields 与 matchExpressions 语法完全相同,但匹配的是节点的 字段(Field) 而非标签。字段是节点对象的固定属性,例如 metadata.name、status.nodeInfo.architecture。
| 对比维度 | matchExpressions | matchFields |
|---|---|---|
| 匹配对象 | 节点标签(Label) | 节点字段(Field) |
| 灵活性 | 高,可自定义标签 | 低,字段由 Kubernetes 定义 |
| 常见用途 | 节点池版本、区域、环境 | 节点名称、架构、操作系统 |
| operator 支持 | 全部六种 | 仅 In、NotIn、Exists、DoesNotExist |
matchExpressions 配合自定义标签(如 node-pool-version),因为标签更灵活且易于管理。matchFields 通常用于系统级约束,例如将 Pod 调度到特定名称的节点。
4.3.1 matchFields 示例
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- "node-01"
- "node-02"
上述规则将 Pod 强制调度到名为 node-01 或 node-02 的节点。注意:matchFields 不支持 Gt 和 Lt,因为字段值通常不是数值。
4.4 节点亲和性选择流程 SVG
下图展示了调度器在处理节点亲和性时的完整决策流程,重点突出 matchExpressions 与 matchFields 的协同工作方式:
4.5 多表达式组合与逻辑规则
一个 nodeSelectorTerm 中可以包含多个 matchExpressions,它们之间是 AND 关系——所有表达式必须同时满足。如果需要 OR 关系,则定义多个 nodeSelectorTerms。
| 组合方式 | YAML 结构 | 逻辑关系 | 示例 |
|---|---|---|---|
| 同一 term 内多个表达式 | 一个 nodeSelectorTerms[0].matchExpressions[] 包含多个条目 |
AND(全部满足) | 节点必须同时有 env=prod 和 zone=us-east |
| 多个 term | nodeSelectorTerms 列表中有多个 matchExpressions 块 |
OR(满足任一即可) | 节点可以是 env=prod 或 env=staging |
Term 1:
node-pool-version In [v2](新版本节点)Term 2:
canary In [true](金丝雀节点)这样新 Pod 可以调度到已升级节点或专门的金丝雀节点,实现灰度验证。
4.6 常见错误与避坑指南
- operator 与 values 不匹配:
Exists和DoesNotExist不能带values,否则 API 校验失败;In和NotIn必须至少提供一个values。 - Gt/Lt 值类型错误: 确保 label value 是纯数字字符串(如
"10"),不能包含单位(如"10Gi"会解析失败)。 - matchFields 的 key 必须正确: 字段名必须使用 Kubernetes 内部表示,例如
metadata.name而非name。可以通过kubectl get node <node-name> -o json查看可用字段。 - 硬性规则过于严格导致 Pod 无法调度: 在滚动升级初期,如果只有少量节点满足条件,大量 Pod 会处于 Pending 状态。建议配合
preferred规则或使用 PodDisruptionBudget 控制升级速率。
4.7 节点亲和性与节点选择器对比
Kubernetes 还提供了更简单的 nodeSelector 字段,但功能有限。下表帮助你在两者之间做出选择:
| 特性 | nodeSelector | nodeAffinity(matchExpressions) |
|---|---|---|
| 表达式能力 | 仅支持精确匹配(key=value) | 支持 In、NotIn、Exists 等六种 operator |
| 多条件组合 | 多个条件之间是 AND 关系 | 支持 AND 和 OR(通过多个 term) |
| 软性约束 | 不支持 | 支持 preferredDuringScheduling |
| 字段匹配 | 仅标签 | 支持标签和字段(matchFields) |
| 推荐场景 | 简单、静态的节点选择 | 复杂策略、滚动升级、金丝雀发布 |
nodeSelector,可以无缝迁移到 nodeAffinity。例如 nodeSelector: { env: prod } 等价于 matchExpressions: [{ key: env, operator: In, values: [prod] }]。迁移后可以获得更丰富的调度能力。