4. 节点排空(Drain)核心机制:kubectl drain 工作原理、PodDisruptionBudget(PDB) 的作用、Eviction API

节点排空(Node Drain)是 Kubernetes 集群升级、节点下线或故障隔离前的关键操作。其核心目标是将节点上的所有 Pod 安全地迁移到其他可用节点,同时最小化对运行中服务的影响。本章深入剖析 kubectl drain 的内部机制、PodDisruptionBudget(PDB)的约束逻辑以及 Eviction API 的调用链路。

4.1 kubectl drain 工作原理

kubectl drain 并非一个原子操作,而是一个由多个步骤组成的协调流程。它首先将节点标记为不可调度(Cordon),然后逐一对节点上的 Pod 执行驱逐(Eviction)或删除操作。

核心执行流程:
  1. 节点封锁(Cordon): 设置节点 spec.unschedulable = true,阻止新 Pod 调度到该节点。
  2. Pod 筛选: 列出节点上所有 Pod,排除 DaemonSet 管理的 Pod(默认行为,可通过 --ignore-daemonsets 控制)和镜像 Pod(Mirror Pod)。
  3. 驱逐尝试: 对每个符合条件的 Pod,优先尝试通过 Eviction API 发起驱逐。如果 Pod 没有关联的 PDB,则直接调用 API Server 删除 Pod。
  4. 等待与重试: 如果驱逐请求被 PDB 阻止,kubectl drain 会等待并重试,直到超时(由 --timeout 参数控制)。
  5. 强制删除(可选): 如果设置了 --force 或 --grace-period=0,将跳过 PDB 检查并直接删除 Pod。
关键参数:
  • --ignore-daemonsets:忽略 DaemonSet Pod,避免排空失败。
  • --delete-emptydir-data:允许删除挂载了 emptyDir 卷的 Pod。
  • --force:即使 PDB 不允许,也强制删除 Pod。
  • --grace-period:设置 Pod 优雅终止的宽限期(秒)。
  • --timeout:排空操作的整体超时时间。
kubectl drain 工作流程 1. 节点封锁 (Cordon) 2. 筛选 Pod 3. 驱逐尝试 (Eviction API) PDB? 等待 PDB 允许 重试 / 超时 直接删除 Pod 调用 API Server 4. 节点排空完成

4.2 PodDisruptionBudget (PDB) 的作用

PDB 是 Kubernetes 提供的一种资源策略,用于限制在同一时间因自愿中断(Voluntary Disruption,如节点排空、集群升级)而不可用的 Pod 数量。它不保护非自愿中断(如节点硬件故障)。

PDB 字段 说明 示例
minAvailable 指定在中断期间必须保持可用的 Pod 最小数量或百分比 minAvailable: 2 或 minAvailable: 50%
maxUnavailable 指定在中断期间允许不可用的 Pod 最大数量或百分比 maxUnavailable: 1 或 maxUnavailable: 25%
selector 标签选择器,用于匹配 PDB 所保护的 Pod 集合 matchLabels: { app: my-app }
PDB 设计原则:
  • 避免过度约束: 设置 maxUnavailable: 0 或 minAvailable: 100% 会完全阻止任何自愿中断,导致排空操作永久阻塞。
  • 与 HPA 协同: 确保 PDB 的约束与 Horizontal Pod Autoscaler (HPA) 的扩缩容策略兼容,避免在排空期间因 Pod 数量不足而触发扩容。
  • 无状态 vs 有状态: 无状态应用通常可以容忍较高的 maxUnavailable(如 25%-50%),而有状态应用(如数据库)应设置更保守的值(如 maxUnavailable: 1)。

4.3 Eviction API 详解

Eviction API 是 Kubernetes 提供的一种优雅驱逐 Pod 的机制。与直接删除 Pod 不同,Eviction API 会先检查 PDB 约束,只有在满足 PDB 条件时才会触发 Pod 的优雅终止流程。

Eviction API 调用示例:

# 发起驱逐请求
kubectl evict pod my-pod -n my-namespace

# 底层 API 调用 (JSON)
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "apiVersion": "policy/v1",
    "kind": "Eviction",
    "metadata": {
      "name": "my-pod",
      "namespace": "my-namespace"
    }
  }' \
  https://<api-server>/api/v1/namespaces/my-namespace/pods/my-pod/eviction

Eviction API 与直接删除的对比:

特性 Eviction API 直接删除 (kubectl delete pod)
PDB 检查 是,必须满足 PDB 约束 否,直接删除
优雅终止 是,遵循 Pod 的 terminationGracePeriodSeconds 是,遵循 Pod 的 terminationGracePeriodSeconds
触发条件 API Server 验证 PDB 后执行 立即执行,不验证 PDB
适用场景 集群升级、节点排空等需要保证服务可用性的场景 故障排查、强制清理等紧急场景
Eviction API 调用链路与 PDB 验证 kubectl / 客户端 POST /eviction API Server PDB 验证 通过? 删除 Pod 优雅终止 拒绝请求 返回 429 Too Many Requests 说明 Eviction API 通过 PDB 验证后,触发 Pod 的优雅终止流程(preStop hook → SIGTERM → 等待 terminationGracePeriodSeconds → SIGKILL)。 如果 PDB 验证失败,API Server 返回 HTTP 429 状态码,客户端应重试。

4.4 排空参数调优实战要点

在 Helm 集群升级场景中,节点排空参数的调优直接影响升级速度和业务稳定性。以下是关键调优参数及其推荐配置:

参数 推荐值 说明
--timeout 5m-15m 根据节点上 Pod 数量和 PDB 约束设置,避免过早超时导致升级失败
--grace-period 30s-120s 与应用的优雅关闭时间匹配,确保请求处理完成
--delete-emptydir-data 按需启用 如果应用不依赖 emptyDir 持久化数据,可以启用以加速排空
--ignore-daemonsets 始终启用 DaemonSet Pod 由节点控制器管理,排空时不应删除
--force 谨慎使用 仅在紧急故障隔离时使用,会绕过 PDB 检查
最佳实践:
  • 分批排空: 在集群升级时,不要同时排空所有节点,建议每次只排空 1-2 个节点,观察业务稳定性后再继续。
  • 监控 PDB 状态: 使用 kubectl get pdb -n <namespace> 监控 PDB 的 DISRUPTIONS ALLOWED 字段,确保排空操作不会导致服务降级。
  • 设置合理的 PDB: 对于关键服务,建议设置 maxUnavailable: 1 或 minAvailable: 75%,在保证可用性的同时允许排空操作进行。
  • 使用 Helm 钩子: 在 Helm Chart 中通过 pre-upgrade 和 post-upgrade 钩子自动执行节点排空和恢复操作。