Skip to content

第 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:NoSchedule
yaml
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:NoSchedule
yaml
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/gpuresource 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-

两种方式对比:

维度drainNoExecute 污点
驱逐方式走 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: 30
yaml
# 有状态服务(如数据库):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 是故障转移速度与稳定性的调节旋钮。