污点与容忍
学习目标
- 理解 Taints 和 Tolerations 的概念和作用
- 掌握 Taints 的三种效果类型
- 了解如何使用 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 |
| Tolerations | Pod 上的标记,忽略节点的 Taint |
| NoSchedule | 新 Pod 不调度到该节点 |
| PreferNoSchedule | 尽量不调度(软性) |
| NoExecute | 新 Pod 不调度,已存在 Pod 驱逐 |
| 使用场景 | 专用节点、特殊硬件、环境隔离 |
练习编辑器
bash
Loading...