3. 节点选择与标签机制:节点标签、节点选择器与节点亲和性基础概念

在 Kubernetes 集群中,Pod 被调度到哪个节点运行,并非完全随机。调度器(kube-scheduler)通过一套灵活的标签与选择器机制,实现从“被动分配”到“主动引导”的调度控制。本章深入解析节点标签(Node Labels)、节点选择器(nodeSelector)和节点亲和性(nodeAffinity)三个核心概念,为后续网络拓扑感知调度奠定基础。

3.1 节点标签(Node Labels)—— 调度的“元数据基石”

节点标签是附着在 Node 对象上的键值对(Key-Value),用于标识节点的属性,如硬件配置、地理位置、可用区、磁盘类型等。标签本身不直接决定调度行为,但它是所有选择器和亲和性规则的操作对象。

3.1.1 常用节点标签示例

标签键(Key) 标签值(Value)示例 说明
kubernetes.io/hostname node-01 节点主机名,由系统自动添加
topology.kubernetes.io/zone us-east-1a 节点所在的可用区(云环境)
node.kubernetes.io/instance-type g4dn.xlarge 云实例类型,标识计算/GPU能力
disktype ssd / hdd 自定义标签,标识磁盘类型
accelerator nvidia-tesla-t4 自定义标签,标识GPU加速器

3.1.2 节点标签操作命令

# 为节点添加标签
kubectl label node node-01 disktype=ssd

# 查看节点标签(以列表形式)
kubectl get node node-01 --show-labels

# 覆盖已有标签值
kubectl label node node-01 disktype=nvme --overwrite

# 删除节点标签(键名后加减号)
kubectl label node node-01 disktype-
最佳实践:标签键建议使用前缀(如 topology.kubernetes.io/)避免冲突;值应使用小写字母、数字和连字符,保持语义清晰。避免使用含义模糊的标签如 type=good。

3.2 节点选择器(nodeSelector)—— 最简单的约束方式

nodeSelector 是 Pod 规范中的一个字段,它使用键值对精确匹配节点标签。调度器只会将 Pod 分配到包含所有指定标签的节点上。这是 Kubernetes 最早提供的节点选择机制,简单直接,但表达能力有限——仅支持“等于”(Equality)匹配。

3.2.1 nodeSelector 使用示例

apiVersion: v1
kind: Pod
metadata:
  name: ssd-pod
spec:
  nodeSelector:
    disktype: ssd          # 只调度到 disktype=ssd 的节点
  containers:
  - name: app
    image: nginx

3.2.2 nodeSelector 的局限性

  • 仅支持精确匹配:无法表达“不在某组节点上”或“值大于某个数”等逻辑。
  • 不支持多条件组合:多个标签之间是 AND 关系,无法表达 OR 或 NOT。
  • 无软性偏好:要么必须满足(硬约束),要么不调度,没有“尽量满足”的选项。
注意:当集群中没有节点满足 nodeSelector 条件时,Pod 将一直处于 Pending 状态,直到有符合条件的节点加入或标签被修改。生产环境中应避免过度依赖单一标签。

3.3 节点亲和性(nodeAffinity)—— 灵活且强大的调度规则

节点亲和性是 nodeSelector 的进化版,属于调度策略的一部分,定义在 Pod 的 spec.affinity.nodeAffinity 字段下。它支持更丰富的匹配运算符(In、NotIn、Exists、DoesNotExist、Gt、Lt),并区分硬性要求(required)和软性偏好(preferred)两种语义。

3.3.1 节点亲和性核心结构

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬约束
        nodeSelectorTerms:
        - matchExpressions:
          - key: accelerator
            operator: In
            values:
            - nvidia-tesla-t4
            - nvidia-a100
      preferredDuringSchedulingIgnoredDuringExecution:  # 软约束
      - weight: 80
        preference:
          matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - us-east-1a
  containers:
  - name: gpu-app
    image: tensorflow:latest

3.3.2 两种调度语义对比

语义类型 字段名 行为说明 调度失败后果
硬约束 requiredDuringSchedulingIgnoredDuringExecution Pod 必须调度到满足条件的节点;不满足则不调度 Pod 处于 Pending
软约束 preferredDuringSchedulingIgnoredDuringExecution 调度器优先选择满足条件的节点;不满足时仍可调度到其他节点 Pod 正常调度,但优先级较低

3.3.3 支持的运算符

  • In:标签值在给定的值列表中(等价于 nodeSelector 的等值匹配)
  • NotIn:标签值不在给定的值列表中(排除特定节点)
  • Exists:节点存在该标签键(无论值是什么)
  • DoesNotExist:节点不存在该标签键
  • Gt / Lt:标签值(数值型字符串)大于或小于给定值
关键区别:nodeSelector 只支持 In 运算符(隐式),而 nodeAffinity 支持 6 种运算符,且可以组合多个 matchExpressions 实现复杂的调度逻辑。

3.4 节点选择机制对比总览

特性 nodeSelector nodeAffinity(硬约束) nodeAffinity(软约束)
匹配方式 精确键值对 表达式 + 运算符 表达式 + 运算符 + 权重
运算符支持 仅 In(隐式) In, NotIn, Exists, DoesNotExist, Gt, Lt 同左
多条件组合 AND(多个标签) AND(多个 matchExpressions) 加权求和(多个 preference)
是否强制 是 是 否(尽量满足)
适用场景 简单固定分配 严格硬件/合规要求 性能优化、负载均衡

3.5 节点选择与亲和性工作流程

下图展示了从节点标签定义到 Pod 调度决策的完整流程,以及三种选择机制在调度器中的执行顺序。

节点选择与亲和性调度流程 节点标签层(Node Labels) disktype=ssd | accelerator=nvidia-tesla-t4 | topology.kubernetes.io/zone=us-east-1a 调度决策层(Scheduler Decision) nodeSelector 精确键值对匹配(AND) nodeAffinity 硬约束 表达式匹配(In/NotIn/Exists…) nodeAffinity 软约束 加权偏好(weight + preference) 执行顺序:先检查 nodeSelector → 再检查硬约束 → 最后计算软约束权重 所有硬条件必须同时满足;软约束在候选节点中择优选择 调度结果(Scheduling Result) Pod 被分配到满足所有硬约束且软约束权重最高的节点

3.6 实际应用场景与案例

3.6.1 场景一:GPU 工作负载严格绑定

要求 AI 训练 Pod 必须运行在带有 NVIDIA A100 GPU 的节点上,且优先选择可用区 us-east-1a。

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: accelerator
          operator: In
          values:
          - nvidia-a100
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 90
      preference:
        matchExpressions:
        - key: topology.kubernetes.io/zone
          operator: In
          values:
          - us-east-1a

3.6.2 场景二:避免将 Pod 调度到特定节点组

使用 NotIn 运算符排除已标记为 maintenance=true 的节点。

requiredDuringSchedulingIgnoredDuringExecution:
  nodeSelectorTerms:
  - matchExpressions:
    - key: maintenance
      operator: NotIn
      values:
      - "true"

3.6.3 场景三:按磁盘类型软性分流

希望日志 Pod 优先调度到 SSD 节点,但如果没有 SSD 节点,HDD 节点也可以接受。

preferredDuringSchedulingIgnoredDuringExecution:
- weight: 70
  preference:
    matchExpressions:
    - key: disktype
      operator: In
      values:
      - ssd
生产建议:在集群初始化阶段,就为节点规划统一的标签体系(如 topology.kubernetes.io/zone、node.kubernetes.io/instance-type),避免后期临时打标导致调度混乱。对于关键业务 Pod,始终使用硬约束保证合规性;对于非关键 Pod,使用软约束配合权重实现负载均衡。

3.7 本章小结

  • 节点标签是调度的元数据基础,通过 kubectl label 管理,支持自定义键值对。
  • nodeSelector 提供最简单的精确匹配,适合快速约束,但表达能力有限。
  • nodeAffinity 提供硬约束和软约束两种模式,支持 6 种运算符和权重机制,是生产环境的首选方案。
  • 三种机制可以组合使用,调度器按 nodeSelector → 硬约束 → 软约束 的顺序执行决策。