75·调度与资源高级

污点与容忍

kubernetesschedulertaintstolerations

污点与容忍

学习目标

  1. 理解 Taints 和 Tolerations 的概念和作用
  2. 掌握 Taints 的三种效果类型
  3. 了解如何使用 Taints 实现节点专用化

核心概念

一句话解释

Taints(污点)标记节点拒绝某些 Pod,Tolerations(容忍)允许 Pod 忽略这些污点。

工作原理

┌─────────────────────────────────────────────────────────┐
│                    Taints & Tolerations                 │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Node with Taint:                                       │
│  ┌─────────────────────────────────────────┐           │
│  │  Node1                                  │           │
│  │  Taint: gpu=true:NoSchedule             │           │
│  │                                         │           │
│  │  ┌─────────────┐  ┌─────────────┐      │           │
│  │  │   Pod A     │  │   Pod B     │      │           │
│  │  │ No Toleration│  │ Toleration: │      │           │
│  │  │      X      │  │ gpu=true    │      │           │
│  │  └─────────────┘  │     ✓       │      │           │
│  │                    └─────────────┘      │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  - Pod A 没有容忍,被拒绝调度                           │
│  - Pod B 有容忍,可以调度到该节点                        │
│                                                         │
└─────────────────────────────────────────────────────────┘

Taint 效果类型

效果说明行为
NoSchedule不调度新 Pod 不会调度到该节点,已存在的 Pod 不受影响
PreferNoSchedule尽量不调度软性版本,尽量不调度但不保证
NoExecute不执行新 Pod 不会调度,已存在的 Pod 也会被驱逐

Taint 操作

# 给节点添加 Taint
kubectl taint nodes node1 gpu=true:NoSchedule
kubectl taint nodes node1 dedicated=gpu:PreferNoSchedule
kubectl taint nodes node1 node-role.kubernetes.io/master=:NoSchedule

# 删除 Taint
kubectl taint nodes node1 gpu=true:NoSchedule-
kubectl taint nodes node1 dedicated=gpu:PreferNoSchedule-

# 查看节点 Taints
kubectl describe node node1 | grep Taints

# 查看所有节点的 Taints
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

Toleration 语法

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  tolerations:
  # 精确匹配
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"

  # 存在匹配(忽略 value)
  - key: "dedicated"
    operator: "Exists"
    effect: "NoSchedule"

  # 匹配所有 effect
  - key: "special"
    operator: "Exists"

  # 容忍所有 Taint(谨慎使用)
  - operator: "Exists"

  containers:
  - name: app
    image: nginx

Toleration 操作符

# Equal:key、value、effect 都必须匹配
tolerations:
- key: "gpu"
  operator: "Equal"
  value: "true"
  effect: "NoSchedule"

# Exists:只要有这个 key 就行,忽略 value
tolerations:
- key: "gpu"
  operator: "Exists"
  effect: "NoSchedule"

# 无 key:容忍所有 Taint
tolerations:
- operator: "Exists"

使用场景

1. 专用节点
   - GPU 节点:taint gpu=true:NoSchedule
   - 数据库节点:taint dedicated=database:NoSchedule

2. 特殊硬件
   - SSD 节点:taint disktype=ssd:NoSchedule
   - 大内存节点:taint memory=large:NoSchedule

3. 环境隔离
   - 生产节点:taint environment=production:NoSchedule
   - 测试节点:taint environment=test:NoSchedule

4. 节点维护
   - 维护节点:taint node.kubernetes.io/unschedulable:NoSchedule
   - 问题节点:taint node.kubernetes.io/unreachable:NoExecute

NoExecute 效果详解

# NoExecute 会驱逐已存在的 Pod
# 可以设置 tolerationSeconds 延迟驱逐

tolerations:
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 300  # 300 秒后驱逐
┌─────────────────────────────────────────────────────────┐
│                    NoExecute 行为                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Node 添加 Taint: node.kubernetes.io/unreachable       │
│                    :NoExecute                           │
│                                                         │
│  ┌─────────────────────────────────────────┐           │
│  │  Pod A: 无 Toleration                    │           │
│  │  → 立即驱逐                              │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  ┌─────────────────────────────────────────┐           │
│  │  Pod B: tolerationSeconds: 300           │           │
│  │  → 300 秒后驱逐                          │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
│  ┌─────────────────────────────────────────┐           │
│  │  Pod C: toleration 无 tolerationSeconds  │           │
│  │  → 永不驱逐                              │           │
│  └─────────────────────────────────────────┘           │
│                                                         │
└─────────────────────────────────────────────────────────┘

实践练习

练习 1:创建专用 GPU 节点

# 给节点添加 GPU Taint
kubectl taint nodes node1 gpu=true:NoSchedule

# 查看 Taint
kubectl describe node node1 | grep Taints

练习 2:调度到 GPU 节点

# gpu-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  nodeSelector:
    gpu: "true"
  containers:
  - name: gpu-app
    image: nvidia/cuda:11.0-base
    command: ["nvidia-smi"]
kubectl apply -f gpu-pod.yaml
kubectl get pod gpu-pod -o wide
# 应该调度到 node1

练习 3:观察 NoSchedule 效果

# 普通 Pod(没有 Toleration)
apiVersion: v1
kind: Pod
metadata:
  name: normal-pod
spec:
  containers:
  - name: nginx
    image: nginx
kubectl apply -f normal-pod.yaml
kubectl get pod normal-pod -o wide
# 如果 node1 是唯一节点,Pod 会 Pending
# 描述查看调度失败原因
kubectl describe pod normal-pod | grep -A 5 Events

练习 4:NoExecute 驱逐

# 给正在运行 Pod 的节点添加 NoExecute Taint
kubectl taint nodes node1 maintenance=true:NoExecute

# 观察 Pod 被驱逐
kubectl get pods -o wide
# 没有容忍的 Pod 会被驱逐到其他节点

练习 5:使用 tolerationSeconds

# pod-toleration-seconds.yaml
apiVersion: v1
kind: Pod
metadata:
  name: toleration-seconds
spec:
  tolerations:
  - key: "maintenance"
    operator: "Equal"
    value: "true"
    effect: "NoExecute"
    tolerationSeconds: 60
  containers:
  - name: nginx
    image: nginx

练习 6:容忍所有 Taint

# pod-tolerate-all.yaml
apiVersion: v1
kind: Pod
metadata:
  name: tolerate-all
spec:
  tolerations:
  - operator: "Exists"
  containers:
  - name: nginx
    image: nginx

内置 Taints

# 节点不可达
node.kubernetes.io/unreachable:NoExecute

# 节点未就绪
node.kubernetes.io/not-ready:NoExecute

# 节点内存压力
node.kubernetes.io/memory-pressure:NoSchedule

# 节点磁盘压力
node.kubernetes.io/disk-pressure:NoSchedule

# 节点 PID 压力
node.kubernetes.io/pid-pressure:NoSchedule

# 网络不可用
node.kubernetes.io/network-unavailable:NoSchedule

# 节点不可调度
node.kubernetes.io/unschedulable:NoSchedule

# 污点驱逐(集群自动缩容)
node.kubernetes.io/scaled-down-node:NoSchedule

常见问题

1. Pod 一直 Pending

# 检查节点 Taints
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

# 检查 Pod Tolerations
kubectl get pod <pod-name> -o yaml | grep -A 10 tolerations

# 检查调度事件
kubectl describe pod <pod-name> | grep -A 10 Events

2. Taints 与 nodeSelector 的关系

# Taints 拒绝不匹配的 Pod
# nodeSelector/affinity 选择节点

# 两者结合使用实现专用节点
spec:
  nodeSelector:
    gpu: "true"  # 选择 GPU 节点
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"  # 容忍 GPU Taint

3. 为什么要有 Taints 和 nodeSelector 两个机制?

Taints(节点视角):
- 节点管理员设置
- 拒绝不匹配的 Pod
- 实现"专用节点"

nodeSelector/Affinity(Pod 视角):
- Pod 开发者设置
- 选择特定节点
- 实现"节点偏好"

两者配合:
- Taints 确保节点只接受特定 Pod
- nodeSelector 确保 Pod 调度到特定节点

小结

要点说明
Taints节点上的标记,拒绝不匹配的 Pod
TolerationsPod 上的标记,忽略节点的 Taint
NoSchedule新 Pod 不调度到该节点
PreferNoSchedule尽量不调度(软性)
NoExecute新 Pod 不调度,已存在 Pod 驱逐
使用场景专用节点、特殊硬件、环境隔离

练习编辑器

bash
Loading...

继续学习

完成本课后,建议继续学习下一课「资源请求」 以巩固所学知识。