3. Node Drain 核心原理:Eviction API、PodDisruptionBudget 与 Graceful Shutdown
Node Drain 是集群升级、节点下线、故障修复等场景下的标准操作。其本质是安全驱逐节点上所有 Pod,确保工作负载在迁移过程中不中断、不丢失数据。理解其底层机制——Eviction API、PodDisruptionBudget(PDB)和 Graceful Shutdown——是掌握集群治理的关键。
3.1 驱逐流程总览
当执行 kubectl drain <node> 时,kubelet 并非直接杀死 Pod,而是通过以下步骤实现优雅驱逐:
- 标记节点不可调度:设置
node.Spec.Unschedulable = true,阻止新 Pod 调度到该节点。 - 逐 Pod 发起 Eviction API 请求:按优先级和 PDB 约束,向 API Server 提交
Eviction子资源。 - 检查 PDB 合规性:API Server 验证驱逐后是否违反 PDB 规则(如最小可用副本数)。
- 触发 Graceful Shutdown:若合规,kubelet 向 Pod 发送 SIGTERM 信号,等待
terminationGracePeriodSeconds后发送 SIGKILL。 - 清理资源:Pod 被删除,卷、网络等资源释放。
关键原则:Drain 操作是协作式的,而非强制终止。PDB 和 Graceful Shutdown 共同保障了工作负载的可用性。
3.2 Eviction API:驱逐的“合法通道”
Eviction API 是 Kubernetes 提供的标准驱逐接口,位于 policy/v1 API 组。与直接删除 Pod 不同,Eviction API 会经过 PDB 校验和 API Server 的准入控制,确保驱逐操作符合集群策略。
3.2.1 Eviction 请求结构
# Eviction 对象示例
apiVersion: policy/v1
kind: Eviction
metadata:
name: my-pod-xxx
namespace: default
deleteOptions:
gracePeriodSeconds: 30 # 可选,覆盖 Pod 的 terminationGracePeriodSeconds
3.2.2 驱逐 vs 直接删除
| 对比维度 | Eviction API | 直接删除 Pod |
|---|---|---|
| PDB 校验 | 强制校验,违反则拒绝 | 不校验,直接删除 |
| 准入控制 | 经过 MutatingWebhook / ValidatingWebhook | 仅经过基本准入 |
| 优雅终止 | 默认遵循 Pod 的 terminationGracePeriodSeconds | 可指定,但无 PDB 保护 |
| 适用场景 | 集群升级、节点维护、自动扩缩容 | 调试、紧急清理、非托管 Pod |
避坑提示:直接删除 Pod 会绕过 PDB,可能导致服务中断。在自动化运维脚本中,务必使用 Eviction API 而非
kubectl delete pod。
3.3 PodDisruptionBudget(PDB):可用性“安”
PDB 定义了在自愿中断(如 Drain、缩容)期间,一个应用必须保持的最小可用或最大不可用 Pod 数量。它是集群治理中资源配额校准的关键约束。
3.3.1 PDB 定义示例
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
namespace: production
spec:
minAvailable: 2 # 至少保持 2 个 Pod 可用
# 或使用 maxUnavailable: 1 # 最多允许 1 个 Pod 不可用
selector:
matchLabels:
app: web
3.3.2 PDB 核心参数
| 参数 | 类型 | 说明 | 示例 |
|---|---|---|---|
minAvailable |
int 或 string(百分比) | 驱逐期间必须保持的最小 Pod 数量 | 2 或 50% |
maxUnavailable |
int 或 string(百分比) | 驱逐期间允许的最大不可用 Pod 数量 | 1 或 25% |
selector |
LabelSelector | 匹配目标 Pod 的标签选择器 | app: web |
3.3.3 PDB 对 Drain 的影响
- 合规驱逐:若驱逐后 Pod 数量仍满足 PDB,Eviction 请求成功。
- 违规拒绝:若驱逐后违反 PDB,API Server 返回
429 Too Many Requests或409 Conflict,Drain 操作暂停。 - 超时重试:Drain 命令默认会重试,直到 PDB 条件满足或超时。
最佳实践:为所有有状态应用和关键无状态应用配置 PDB。建议使用
maxUnavailable: 25% 或 minAvailable: 75%,在可用性和资源利用率之间取得平衡。
3.4 Graceful Shutdown:Pod 的“体面退场”
Graceful Shutdown 确保 Pod 在终止前完成正在处理的请求、释放资源、持久化状态。其核心是 terminationGracePeriodSeconds 和 preStop 钩子。
3.4.1 优雅终止时序
- Pod 进入 Terminating 状态:kubelet 收到删除 Pod 的指令。
- 执行 preStop 钩子:若定义了
lifecycle.preStop,kubelet 执行该命令(如通知负载均衡器摘除节点)。 - 发送 SIGTERM:向 Pod 主进程发送 SIGTERM 信号。
- 等待宽限期:kubelet 等待
terminationGracePeriodSeconds(默认 30 秒)。 - 发送 SIGKILL:若宽限期结束进程仍未退出,强制杀死。
3.4.2 配置示例
apiVersion: v1
kind: Pod
metadata:
name: graceful-pod
spec:
terminationGracePeriodSeconds: 60 # 总宽限期 60 秒
containers:
- name: app
image: my-app:latest
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10 && /usr/local/bin/deregister"]
3.4.3 常见问题与优化
| 问题 | 原因 | 优化方案 |
|---|---|---|
| Pod 长时间不退出 | 进程未处理 SIGTERM,或 preStop 阻塞 | 实现 SIGTERM 处理器;preStop 设置超时 |
| 请求中断 | 宽限期太短,未完成正在处理的请求 | 增加 terminationGracePeriodSeconds;使用 readiness probe 提前摘除流量 |
| 数据丢失 | 有状态应用未在 preStop 中持久化 | 在 preStop 中执行 flush/checkpoint 操作 |
3.5 三者协同:Drain 操作的安全保障
Eviction API、PDB 和 Graceful Shutdown 构成了 Node Drain 的三层安全机制:
- Eviction API:提供合规的驱逐通道,确保操作可审计、可控制。
- PDB:在集群层面保障应用的最小可用性,防止批量驱逐导致服务降级。
- Graceful Shutdown:在 Pod 层面保障进程的优雅退出,避免数据丢失和请求中断。
治理要点:在集群升级前,应审计所有关键应用的 PDB 配置,校准
terminationGracePeriodSeconds 与业务超时时间,确保 Drain 操作在资源配额约束下安全执行。