2、NodeSelector 与节点标签:节点标签管理、nodeSelector 用法、简单节点选择场景

2.1 节点标签(Node Label)—— 调度的基础元数据

Kubernetes 节点标签是附着在 Node 对象上的键值对(Key-Value),用于标识节点的属性,例如:硬件配置(GPU、SSD)、地理位置(机房、可用区)、环境归属(生产、测试)、或自定义业务分组。标签是 NodeSelector 和后续亲和性调度策略的基石。

2.1.1 节点标签管理常用命令

操作 命令示例 说明
查看节点现有标签 kubectl get nodes --show-labels 列出所有节点及其全部标签
为节点添加标签 kubectl label node node01 disktype=ssd 添加或覆盖标签 disktype=ssd
为节点添加多个标签 kubectl label node node01 disktype=ssd gpu=nvidia-t4 空格分隔多个键值对
删除节点标签 kubectl label node node01 disktype- 键名后加 - 表示删除该标签
按标签筛选节点 kubectl get nodes -l disktype=ssd -l 参数支持 =、!=、in 等选择器
最佳实践: 建议在集群初始化或节点加入时,通过 --node-labels 参数(kubelet 配置)自动注入基础标签,避免人工遗漏。例如:--node-labels="topology.kubernetes.io/zone=us-east-1a,node-role.kubernetes.io/worker="。

2.1.2 常见节点标签分类

  • 基础设施层: topology.kubernetes.io/zone(可用区)、topology.kubernetes.io/region(地域)、kubernetes.io/hostname(主机名)。
  • 硬件特性层: disktype(ssd/hdd)、gpu(nvidia-t4/amd-mi250)、instance-type(c5.2xlarge)。
  • 环境归属层: env(prod/staging/dev)、team(platform/biz-a)、node-role.kubernetes.io/control-plane(控制面)。

2.2 nodeSelector —— 最简节点选择机制

nodeSelector 是 Pod 规约中的一个字段,类型为 map[string]string。它要求 Pod 只能调度到 包含所有指定标签 的节点上。匹配逻辑是“等值且必须全部满足”(AND 语义)。

2.2.1 基本用法示例

假设集群中有两个节点:node-ssd(标签 disktype=ssd)和 node-hdd(标签 disktype=hdd)。我们希望一个高性能数据库 Pod 只运行在 SSD 节点上:

apiVersion: v1
kind: Pod
metadata:
  name: db-ssd-pod
spec:
  nodeSelector:
    disktype: ssd
  containers:
  - name: db-container
    image: postgres:15
    resources:
      requests:
        cpu: "2"
        memory: "4Gi"

调度器在调度该 Pod 时,会过滤掉所有不包含 disktype=ssd 标签的节点。如果没有任何节点满足条件,Pod 将一直处于 Pending 状态。

2.2.2 多标签匹配(AND 逻辑)

当 nodeSelector 中包含多个键值对时,节点必须同时满足所有条件:

spec:
  nodeSelector:
    disktype: ssd
    topology.kubernetes.io/zone: us-east-1a

上述配置要求节点 既是 SSD 磁盘,又位于 us-east-1a 可用区。缺少任何一个标签的节点都会被排除。

2.3 简单节点选择场景与对比

适用场景: nodeSelector 最适合 静态、确定性强、标签数量少(通常 1~3 个) 的调度需求。例如:将批处理任务固定到高内存节点、将 GPU 推理服务固定到 GPU 节点、将日志采集 DaemonSet 固定到特定标签的节点池。

2.3.1 场景对比:nodeSelector vs. 节点亲和性(NodeAffinity)

对比维度 nodeSelector nodeAffinity(后续章节展开)
匹配语法 仅支持 key=value 等值匹配 支持 In、NotIn、Exists、DoesNotExist、Gt、Lt
逻辑运算符 隐式 AND(所有条件必须满足) 支持 AND/OR 组合,以及 requiredDuringScheduling / preferredDuringScheduling
软约束(偏好) 不支持 支持 preferredDuringSchedulingIgnoredDuringExecution
表达式复杂度 低,适合简单场景 中高,适合复杂路由策略
推荐使用 标签数量 ≤ 3,且为确定性等值匹配 需要范围匹配、排除、或软偏好时

2.4 节点选择流程示意图

下图展示了 nodeSelector 在调度周期中的过滤阶段(Predicates)所扮演的角色:

nodeSelector 调度过滤流程 nodeSelector 在调度周期中的过滤阶段 Pod 提交(含 nodeSelector) 调度器过滤阶段(Predicates) nodeSelector 标签匹配检查 匹配? 通过 → 进入优选阶段 不通过 → Pod Pending 说明:nodeSelector 在过滤阶段执行严格的等值 AND 匹配,不满足条件的节点直接被排除

2.5 常见问题与避坑指南

⚠️ 常见陷阱:
  • 标签不存在导致 Pod 一直 Pending: 如果 nodeSelector 引用了集群中不存在的标签键值对,调度器无法找到任何匹配节点,Pod 将无限期 Pending。建议先通过 kubectl get nodes -l <key>=<value> 验证标签是否存在。
  • 大小写敏感: 标签键值对是大小写敏感的。disktype=SSD 与 disktype=ssd 被视为不同标签。
  • nodeSelector 不支持排除或范围: 无法表达“不要调度到 HDD 节点”或“调度到内存大于 64GB 的节点”。这类需求必须使用 nodeAffinity 的 NotIn 或 Gt 操作符。
  • 不要与控制面节点标签冲突: 如果显式设置 nodeSelector: { node-role.kubernetes.io/control-plane: "" },Pod 会被调度到控制面节点,通常这不符合生产安全要求。

2.6 实战:为日志采集 DaemonSet 绑定特定节点池

假设集群中有两个节点池:pool-a(标签 node-pool=pool-a)和 pool-b(标签 node-pool=pool-b)。我们希望日志采集器只运行在 pool-a 上:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-log-collector
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      nodeSelector:
        node-pool: pool-a
      containers:
      - name: fluentd
        image: fluent/fluentd:v1.16

通过这种简单的标签选择,可以精确控制工作负载的分布范围,避免日志采集器占用非目标节点池的资源。