Skip to content

第 3 章:Tolerations 容忍详解

3.1 Toleration 的完整字段结构

Toleration 定义在 Pod 的 spec.tolerations 中,完整字段如下:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  tolerations:
  - key: "dedicated"            # 要匹配的污点 key
    operator: "Equal"           # 运算符:Equal(默认)或 Exists
    value: "gpu"                # 仅 Equal 时有效;Exists 时必须省略
    effect: "NoSchedule"        # 要匹配的污点 effect;省略表示匹配所有 effect
    tolerationSeconds: 3600     # 仅对 NoExecute 有效:被驱逐前可存活的秒数
  containers:
  - name: app
    image: nginx

3.2 匹配规则(核心!)

一个 Toleration 能"容忍"一个 Taint,需满足:

  1. key 相同
  2. effect 相同(或 toleration 省略 effect,匹配所有 effect)
  3. value 匹配
    • operator: Equal → toleration 的 value 必须等于 taint 的 value(默认值,此时 value 省略等价于空字符串)
    • operator: Exists不关心 value,只要 key 存在即匹配(此时不能写 value

匹配示例速查表

节点污点:dedicated=gpu:NoSchedule

Toleration 写法是否匹配说明
key: dedicated, operator: Equal, value: gpu, effect: NoSchedule完全匹配(标准写法)
key: dedicated, operator: Exists, effect: NoScheduleExists 忽略 value
key: dedicated, operator: Exists(无 effect)匹配该 key 的所有 effect
key: dedicated, operator: Equal, value: cpu, effect: NoSchedulevalue 不相等
key: dedicated, operator: Equal, value: gpu(无 effect)省略 effect 匹配所有 effect
key: dedicated, operator: Equal, value: gpu, effect: NoExecuteeffect 不匹配
空的 toleration {}(key、effect 都省略 + Exists)✅ 匹配一切容忍所有污点(慎用!)

"万能容忍"(危险但有用)

yaml
tolerations:
- operator: "Exists"    # key、value、effect 全省略 = 容忍所有污点

常见于:监控 Agent、日志采集等需要"无处不在"的 DaemonSet。业务 Pod 不要这么写,会绕过所有节点隔离保护。

3.3 operator 详解

Equal(默认值)

yaml
tolerations:
- key: "dedicated"
  operator: "Equal"      # 可省略,默认就是 Equal
  value: "gpu"
  effect: "NoSchedule"

精确匹配 dedicated=gpu:NoSchedule

Exists

yaml
tolerations:
- key: "dedicated"
  operator: "Exists"
  effect: "NoSchedule"

匹配 key 为 dedicated、effect 为 NoSchedule 的污点,不管 value 是什么dedicated=gpudedicated=cpu 都匹配)。

⚠️ 使用 Exists 时写 value 会报错:value must be empty when operator is Exists

3.4 effect 省略的含义

yaml
tolerations:
- key: "dedicated"
  operator: "Exists"
  # 没有 effect 字段

匹配 key 为 dedicated所有污点,无论 effect 是 NoSchedule、PreferNoSchedule 还是 NoExecute。

特例:如果 key 也省略、operator 为 Exists,则容忍一切污点(3.2 节的"万能容忍")。

3.5 tolerationSeconds —— NoExecute 专属

tolerationSeconds 只在 effect 为 NoExecute 时有效(其他 effect 写了也没意义),表示:节点被加上 NoExecute 污点后,Pod 还能继续存活多少秒才被驱逐。

yaml
tolerations:
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 300    # 节点失联后,Pod 最多再活 300 秒
  • 不设置 → 永久容忍(永远不被该污点驱逐)。
  • 设置为 0 → 立即驱逐(等同没有容忍)。
  • 典型用途:有状态应用希望节点短暂故障时不要立刻被赶走(避免不必要的迁移抖动),故障持续超过阈值再迁移。

K8s 自动添加的默认容忍

从 1.6 起,API Server 的 DefaultTolerationSeconds 准入控制器会自动给每个 Pod 添加:

yaml
tolerations:
- key: "node.kubernetes.io/not-ready"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 300
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 300

这就是为什么节点宕机后,上面的 Pod 默认 5 分钟才被驱逐重建。你可以在自己的 Pod spec 里显式覆盖这两个容忍来缩短/延长这个时间(详见第 4 章)。

3.6 在各类工作负载中配置容忍

Deployment

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gpu-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: gpu-app
  template:
    metadata:
      labels:
        app: gpu-app
    spec:
      tolerations:                  # 写在 Pod template 的 spec 里
      - key: "dedicated"
        operator: "Equal"
        value: "gpu"
        effect: "NoSchedule"
      containers:
      - name: app
        image: mygpuapp:latest

DaemonSet

DaemonSet 通常需要跑在所有节点(包括 Master),所以系统自动给它加一堆容忍(见第 4 章),手动也可以补充:

yaml
spec:
  template:
    spec:
      tolerations:
      - key: "dedicated"
        operator: "Exists"
        effect: "NoSchedule"

Job / CronJob / StatefulSet

同理,都写在 spec.template.spec.tolerations 中,不再赘述。

3.7 一个常见误区:容忍 ≠ 定向调度

yaml
# ❌ 错误认知:加了容忍,Pod 就会调度到 GPU 节点
tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "gpu"
  effect: "NoSchedule"

这个 Pod 只是"可以"去 GPU 节点,调度器也可能把它放到普通节点!如果业务要求"必须在 GPU 节点",要加 nodeAffinity:

yaml
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: dedicated
            operator: In
            values: ["gpu"]
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

口诀:NodeAffinity 负责"吸引"(往哪儿去),Taint/Toleration 负责"排斥"(谁能来)。专用节点方案 = 节点打 label + 打污点,Pod 配 nodeAffinity + toleration。 详见第 6 章。

本章小结

  • Toleration 五字段:key / operator(Equal|Exists) / value / effect / tolerationSeconds。
  • Exists 忽略 value 且不能写 value;effect 省略 = 匹配所有 effect;全省略 + Exists = 容忍一切。
  • tolerationSeconds 只对 NoExecute 有效,控制延迟驱逐时长。
  • K8s 默认给 Pod 加 not-ready/unreachable 的 300 秒容忍。
  • 容忍只是通行证,定向调度要配 nodeAffinity。

动手练习

  1. 写两个 Pod:一个用 Equal 精确容忍,一个用 Exists 容忍,验证它们都能调度到打了 dedicated=gpu:NoSchedule 的节点。
  2. 给一个运行中的 Pod 所在节点打 NoExecute 污点,对比"无容忍 / 容忍但 tolerationSeconds=30 / 永久容忍"三种 Pod 的不同命运。
  3. kubectl get pod <任意pod> -o yaml | grep -A12 tolerations,观察系统自动注入的默认容忍。