主题
第 5 章:实战场景
本章覆盖生产环境中污点/容忍的四大经典用法,每个场景给出完整可复现的操作。
场景一:专用节点(Dedicated Nodes)
需求:团队 A 买了 3 台专用服务器,只允许团队 A 的服务调度上去。
完整配方(label + taint + affinity + toleration 四件套)
bash
# 1. 打标签(供 Pod 的 nodeAffinity 定向)
kubectl label nodes node-a{1,2,3} team=team-a
# 2. 打污点(挡住其他团队的 Pod)
kubectl taint nodes node-a{1,2,3} dedicated=team-a:NoScheduleyaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: team-a-app
spec:
replicas: 3
selector:
matchLabels:
app: team-a-app
template:
metadata:
labels:
app: team-a-app
spec:
# 吸引:必须落在 team=team-a 的节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: team
operator: In
values: ["team-a"]
# 通行证:容忍专用节点的污点
tolerations:
- key: "dedicated"
operator: "Equal"
value: "team-a"
effect: "NoSchedule"
containers:
- name: app
image: nginx为什么 label 和 taint 都要?
| 机制 | 作用 | 缺了它会怎样 |
|---|---|---|
| label + nodeAffinity | 保证 A 的 Pod 必须去专用节点 | Pod 可能散落到其他节点 |
| taint | 保证其他团队的 Pod 不能来 | 别人的 Pod 可能占用专用节点 |
⚠️ 但注意:taint 防不住"故意配置容忍"的 Pod——其他团队完全可以照着写 toleration 混进来。真正的强隔离要配合准入控制(如 OPA Gatekeeper / Kyverno)限制谁能配置容忍,或用独立命名空间 + ResourceQuota + 节点池(云厂商方案)。
场景二:GPU / 特殊硬件节点
需求:GPU 节点昂贵,只允许申请了 GPU 资源的 Pod 调度上去。
bash
kubectl label nodes gpu-node1 accelerator=nvidia-a100
kubectl taint nodes gpu-node1 nvidia.com/gpu=true:NoScheduleyaml
apiVersion: v1
kind: Pod
metadata:
name: trainer
spec:
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: trainer
image: pytorch/pytorch:latest
resources:
limits:
nvidia.com/gpu: 1 # 资源请求本身就会把 Pod 引导到 GPU 节点说明:
nvidia.com/gpu的 resource limit 已经保证 Pod 只会去有 GPU 的节点(这是 device plugin 报告的 extended resource),所以这里 nodeAffinity 可以省略;taint + toleration 负责反向隔离:挡住不需要 GPU 的普通 Pod,避免它们白占宝贵节点。
场景三:节点维护(NoExecute 优雅驱逐)
需求:node1 需要内核升级,要把它上面的业务 Pod 迁走,并阻止新 Pod 上来。
方式 A:kubectl drain(推荐)
bash
kubectl drain node1 --ignore-daemonsets --delete-emptydir-data
# 维护完成后恢复
kubectl uncordon node1方式 B:手动 NoExecute 污点(更细粒度控制)
bash
# 打 NoExecute:立即驱逐无容忍 Pod + 阻止新 Pod
kubectl taint nodes node1 maintenance=true:NoExecute
# 观察迁移过程
kubectl get pods -o wide -w
# 维护完成后删除污点
kubectl taint nodes node1 maintenance=true:NoExecute-两种方式对比:
| 维度 | drain | NoExecute 污点 |
|---|---|---|
| 驱逐方式 | 走 Eviction API,尊重 PodDisruptionBudget | 直接删除,不看 PDB |
| 优雅期 | 尊重 terminationGracePeriodSeconds | 尊重 |
| 可控性 | 一刀切 | 可配合 tolerationSeconds 让特定 Pod 多留一会 |
| 适合 | 计划内维护 | 故障演练、细粒度驱逐 |
⚠️ 生产环境的计划维护优先用
drain;NoExecute 驱逐不尊重 PDB,可能造成服务可用副本瞬间不足。
给关键服务配"延迟撤离"
yaml
# 数据库类有状态服务:节点被维护时,多给它 10 分钟完成数据同步/主从切换
tolerations:
- key: "maintenance"
operator: "Equal"
value: "true"
effect: "NoExecute"
tolerationSeconds: 600场景四:节点故障自动隔离(Taint-Based Eviction 实战)
需求:节点宕机时,让无状态服务快速在健康节点重建,有状态服务谨慎迁移。
yaml
# 无状态 Web 服务:30 秒快速故障转移
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
template:
spec:
tolerations:
- key: "node.kubernetes.io/not-ready"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 30
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 30yaml
# 有状态服务(如数据库):10 分钟,宁可等节点恢复也不轻易迁移
# (StatefulSet Pod 迁移涉及存储挂载/卸载,太快反而危险)
tolerations:
- key: "node.kubernetes.io/not-ready"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 600
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 600设计权衡:tolerationSeconds 太短 → 网络抖动导致 Pod 频繁迁移(抖动放大);太长 → 真故障时服务恢复慢。无状态服务可以激进(30s),有状态服务要保守(300s+)。
场景五(进阶):PreferNoSchedule 做资源倾斜
需求:大促期间,优先把流量型 Pod 调度到高配节点,高配节点满了也能溢出到普通节点。
bash
# 高配节点打软污点
kubectl taint nodes high-perf-{1,2,3} class=high-perf:PreferNoSchedule普通 Pod(无容忍):尽量不来高配节点,但集群资源紧张时仍可调度上来(柔性保护,避免硬隔离造成的资源浪费)。
生产配置检查清单
- [ ] 控制面节点有
node-role.kubernetes.io/control-plane:NoSchedule污点(kubeadm 默认有) - [ ] 监控/日志/安全 Agent(DaemonSet)配置了 control-plane 污点容忍
- [ ] 专用节点同时配置了 label + taint,业务 Pod 同时配置了 affinity + toleration
- [ ] 关键服务显式配置了 not-ready/unreachable 的 tolerationSeconds
- [ ] 节点维护走
drain而非直接打 NoExecute(尊重 PDB) - [ ] 业务 Pod 不使用"万能容忍"(
operator: Exists无 key) - [ ] 通过准入策略限制普通用户配置任意容忍(防绕过隔离)
本章小结
- 专用节点 = label+taint(节点侧)+ affinity+toleration(Pod 侧),四件套缺一不可。
- GPU 节点:taint 负责反向隔离,resource limit 负责正向引导。
- 计划维护用 drain(尊重 PDB);NoExecute 用于故障隔离和演练。
- tolerationSeconds 是故障转移速度与稳定性的调节旋钮。