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)或删除操作。
核心执行流程:
- 节点封锁(Cordon): 设置节点
spec.unschedulable = true,阻止新 Pod 调度到该节点。 - Pod 筛选: 列出节点上所有 Pod,排除 DaemonSet 管理的 Pod(默认行为,可通过
--ignore-daemonsets控制)和镜像 Pod(Mirror Pod)。 - 驱逐尝试: 对每个符合条件的 Pod,优先尝试通过 Eviction API 发起驱逐。如果 Pod 没有关联的 PDB,则直接调用 API Server 删除 Pod。
- 等待与重试: 如果驱逐请求被 PDB 阻止,
kubectl drain会等待并重试,直到超时(由--timeout参数控制)。 - 强制删除(可选): 如果设置了
--force或--grace-period=0,将跳过 PDB 检查并直接删除 Pod。
关键参数:
--ignore-daemonsets:忽略 DaemonSet Pod,避免排空失败。--delete-emptydir-data:允许删除挂载了 emptyDir 卷的 Pod。--force:即使 PDB 不允许,也强制删除 Pod。--grace-period:设置 Pod 优雅终止的宽限期(秒)。--timeout:排空操作的整体超时时间。
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 |
| 适用场景 | 集群升级、节点排空等需要保证服务可用性的场景 | 故障排查、强制清理等紧急场景 |
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钩子自动执行节点排空和恢复操作。