调度艺术:利用K8s污点与容忍,实现Pod的精准“着陆”

2026/01/23 k8s 共 4356 字,约 13 分钟

调度艺术:利用K8s污点与容忍,实现Pod的精准“着陆”

在Kubernetes的广阔世界里,调度器(Scheduler)扮演着“空中交通管制员”的角色,负责将成千上万的Pod(飞机)安全、高效地调度到合适的Node(机场)上运行。默认的调度规则基于资源请求和节点标签,这就像只考虑机场的跑道长度和天气。但当我们有特殊需求时,比如“某些机场只允许货机降落”或“这架飞机装有特殊设备,只能在特定机场降落”,就需要更精细的控制。这时,Taints(污点)Tolerations(容忍) 这对强大的特性就派上了用场。

一、核心概念:污点与容忍是什么?

让我们先打个比方来理解这两个抽象的概念:

  • Taint(污点): 是打在Node节点上的一个“标记”或“属性”。它意味着这个节点有一些“特性”或“问题”,会排斥所有不能“忍受”这个特性的Pod。一个节点可以有多个污点。
  • Toleration(容忍): 是配置在Pod上的一个“声明”。它表示这个Pod能够“忍受”某些类型的污点。只有Pod的容忍度与节点的污点“匹配”时,这个Pod才有可能被调度到该节点上。

关键点: 污点作用于节点,是“排斥”机制;容忍作用于Pod,是“准入”机制。两者结合,共同决定了Pod能否在某个节点上运行。

二、污点(Taints)的组成与效果

为节点添加污点的命令是 kubectl taint。一个污点由三部分组成:

key=value:effect
  • key: 污点的键,用于标识污点的类别(如 gpudedicated)。
  • value: 污点的值,提供更具体的描述(如 nvidia-tesla-v100team-a)。value可以为空。
  • effect: 污点的效果,即当Pod不容忍此污点时,调度器或kubelet会采取的行动。这是核心,主要有三种:
    1. NoSchedule硬排斥。调度器绝不会将不容忍此污点的Pod调度到该节点。这是最常用的效果。
    2. PreferNoSchedule软建议。调度器会尽量避免将不容忍此污点的Pod调度到此节点,但如果没有其他合适节点,仍然会调度。是“NoSchedule”的宽松版本。
    3. NoExecute驱逐。该效果不仅影响调度,还影响已经运行的Pod。
      • 如果Pod不能容忍节点上新添加的 NoExecute 污点,它会被立即驱逐
      • 如果Pod不能容忍节点上已存在的 NoExecute 污点,则不会被调度

管理节点污点

# 为节点 node-01 添加一个污点,表示它专属于 team-a,不容忍的Pod不可调度
kubectl taint nodes node-01 dedicated=team-a:NoSchedule

# 查看节点的污点信息
kubectl describe node node-01 | grep Taints

# 删除污点(通过指定key和effect,如果指定了value也需要匹配)
kubectl taint nodes node-01 dedicated:NoSchedule-
# 或者删除指定key的所有污点
kubectl taint nodes node-01 dedicated-

三、容忍(Tolerations)的配置方式

容忍度定义在Pod的 spec.tolerations 字段中。以下是一些常见的配置示例。

示例1:容忍一个具体的污点

apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  containers:
  - name: cuda-app
    image: nvidia/cuda:11.0-base
  tolerations:
  - key: "gpu-type"           # 污点的key
    operator: "Equal"         # 操作符,Equal表示key和value都要精确匹配
    value: "nvidia-a100"      # 污点的value
    effect: "NoSchedule"      # 污点的effect

这个Pod可以容忍 gpu-type=nvidia-a100:NoSchedule 这个污点。

示例2:容忍某个key的所有污点(无论value和effect)

tolerations:
- key: "critical-addons"
  operator: "Exists"          # Exists 表示只要存在这个key的污点,无论value和effect是什么,都容忍
  effect: "NoExecute"         # 这里仍然可以指定effect,如果为空则表示容忍所有effect

这个Pod可以容忍任何 keycritical-addons 的污点,无论其 value 是什么,但只容忍 effectNoExecute 的。

示例3:容忍所有污点(谨慎使用!)

tolerations:
- operator: "Exists"          # key为空且operator为Exists,表示容忍所有污点

这个Pod可以被调度到集群中的任何节点,无视所有污点。这通常用于像网络插件、监控Agent这样的系统级Pod。

四、经典应用场景实战

场景1:专用节点/节点隔离

需求: 你有三台性能极强的物理服务器(node-gpu-01, 02, 03),希望只运行需要GPU的AI训练任务,禁止其他普通业务Pod调度上来。

操作

  1. 给GPU节点打上污点。
    kubectl taint nodes node-gpu-01 gpu=true:NoSchedule
    kubectl taint nodes node-gpu-02 gpu=true:NoSchedule
    kubectl taint nodes node-gpu-03 gpu=true:NoSchedule
    
  2. 在需要GPU的Pod模板中添加对应的容忍。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ai-training
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: trainer
      template:
        metadata:
          labels:
            app: trainer
        spec:
          containers:
          - name: trainer
            image: tensorflow/tensorflow:latest-gpu
            resources:
              limits:
                nvidia.com/gpu: 2
          tolerations:
          - key: "gpu"
            operator: "Equal"
            value: "true"
            effect: "NoSchedule"
          # 通常还会配合节点选择器 nodeSelector 或节点亲和性 nodeAffinity 来确保Pod一定落在GPU节点上
          nodeSelector:
            hardware-type: gpu
    

    这样,只有携带了 tolerations 的AI Pod才能被调度到GPU节点,普通Pod则被完全隔离在外。

场景2:基于污点的Pod驱逐与维护

需求: 你需要对节点 node-web-01 进行内核升级,需要清空其上的所有Pod(系统Pod除外)。

操作

  1. 给节点添加一个 NoExecute 污点。
    kubectl taint nodes node-web-01 maintenance=true:NoExecute
    
  2. 观察Pod被驱逐。所有不能容忍 maintenance=true:NoExecute 的Pod会被立即驱逐,并重新调度到其他节点。
  3. 进行维护操作。
  4. 维护完成后,删除污点。
    kubectl taint nodes node-web-01 maintenance:NoExecute-
    
  5. 节点恢复可调度状态。

对于像 CoreDNSCalico 这样的系统关键Pod,我们通常会在其部署中预先添加容忍所有 NoExecute 污点的配置,以确保它们即使在节点维护时也能保持运行(除非节点彻底宕机),保障集群核心功能。

# 类似这样的容忍配置常见于系统组件Deployment中
tolerations:
- key: "CriticalAddonsOnly"
  operator: "Exists"
- operator: "Exists" # 容忍所有污点,确保始终运行

场景3:区分节点类型(开发/测试/生产)

需求: 在混合使用的集群中,区分开发、测试、生产环境节点。

操作

  1. 为节点打上环境污点。
    kubectl taint nodes node-dev-01 environment=dev:PreferNoSchedule
    kubectl taint nodes node-staging-01 environment=staging:NoSchedule
    kubectl taint nodes node-prod-01 environment=prod:NoSchedule
    
  2. 为不同环境的Pod配置不同的容忍。
    • 开发Pod:容忍 environment=dev:PreferNoSchedule,这样它优先被调度到开发节点,资源不足时也可能去其他环境节点。
    • 测试Pod:容忍 environment=staging:NoSchedule,严格限制在测试节点。
    • 生产Pod:容忍 environment=prod:NoSchedule,严格限制在生产节点。

这样可以有效避免开发测试的Pod占用生产环境资源,实现逻辑上的隔离。

五、最佳实践与注意事项

  1. 与亲和性(Affinity)配合使用: 容忍只是获得了在某个节点上运行的“资格”,但它并不“偏好”这个节点。通常需要结合 nodeSelectornodeAffinity 来明确指定Pod希望调度到的节点。容忍是“开门”,亲和性是“选择房间”
  2. 避免过度使用 Exists 操作符: 特别是没有指定 keyoperator: Exists,这会让Pod容忍所有污点,可能破坏你精心设计的隔离策略。仅对集群必需的系统级组件使用。
  3. NoExecute 的谨慎使用NoExecute 会导致Pod被驱逐,可能影响服务可用性。对于需要高可用的应用,确保其有多个副本并能够快速在其它节点重建。
  4. 内置污点: Kubernetes控制面节点(Master)默认带有 node-role.kubernetes.io/control-plane:NoSchedule 污点,以防止普通工作负载调度到控制面。部署系统组件时需要注意这一点。
  5. 清晰的命名规范: 为污点的 keyvalue 设计清晰、一致的命名规范(如 domain/usageteam-alpha/dedicated),便于团队管理和理解。

总结

Taints和Tolerations是Kubernetes调度系统中用于实现“反亲和性”和“节点隔离”的利器。它们提供了一种声明式的、灵活的方式,将Pod的调度选择权从简单的资源匹配,提升到了基于节点“身份”和“状态”的逻辑匹配层面。通过将污点与容忍和节点亲和性、Pod亲和性/反亲和性等特性结合使用,你可以构建出极其复杂、精准且符合实际业务需求的调度策略,真正掌握Pod在K8s集群中“着陆”的艺术。

文档信息

Search

    Table of Contents