3. Node Drain 核心原理:Eviction API、PodDisruptionBudget 与 Graceful Shutdown

Node Drain 是集群升级、节点下线、故障修复等场景下的标准操作。其本质是安全驱逐节点上所有 Pod,确保工作负载在迁移过程中不中断、不丢失数据。理解其底层机制——Eviction API、PodDisruptionBudget(PDB)和 Graceful Shutdown——是掌握集群治理的关键。

3.1 驱逐流程总览

当执行 kubectl drain <node> 时,kubelet 并非直接杀死 Pod,而是通过以下步骤实现优雅驱逐:

  1. 标记节点不可调度:设置 node.Spec.Unschedulable = true,阻止新 Pod 调度到该节点。
  2. 逐 Pod 发起 Eviction API 请求:按优先级和 PDB 约束,向 API Server 提交 Eviction 子资源。
  3. 检查 PDB 合规性:API Server 验证驱逐后是否违反 PDB 规则(如最小可用副本数)。
  4. 触发 Graceful Shutdown:若合规,kubelet 向 Pod 发送 SIGTERM 信号,等待 terminationGracePeriodSeconds 后发送 SIGKILL。
  5. 清理资源:Pod 被删除,卷、网络等资源释放。
关键原则:Drain 操作是协作式的,而非强制终止。PDB 和 Graceful Shutdown 共同保障了工作负载的可用性。
Node Drain 驱逐流程 Node Drain 驱逐流程 kubectl drain 标记 node.Spec.Unschedulable 逐 Pod 发起 Eviction API 检查 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 优雅终止时序

  1. Pod 进入 Terminating 状态:kubelet 收到删除 Pod 的指令。
  2. 执行 preStop 钩子:若定义了 lifecycle.preStop,kubelet 执行该命令(如通知负载均衡器摘除节点)。
  3. 发送 SIGTERM:向 Pod 主进程发送 SIGTERM 信号。
  4. 等待宽限期:kubelet 等待 terminationGracePeriodSeconds(默认 30 秒)。
  5. 发送 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 操作
Graceful Shutdown 时序 Graceful Shutdown 时序 T0: 删除请求 T1: preStop 执行 T2: SIGTERM 发送 T3: 宽限期结束 T4: SIGKILL terminationGracePeriodSeconds 关键配置 preStop 钩子:用于摘除流量、持久化状态 terminationGracePeriodSeconds:建议 ≥ 60s,覆盖 preStop + 请求处理时间

3.5 三者协同:Drain 操作的安全保障

Eviction API、PDB 和 Graceful Shutdown 构成了 Node Drain 的三层安全机制:

  • Eviction API:提供合规的驱逐通道,确保操作可审计、可控制。
  • PDB:在集群层面保障应用的最小可用性,防止批量驱逐导致服务降级。
  • Graceful Shutdown:在 Pod 层面保障进程的优雅退出,避免数据丢失和请求中断。
治理要点:在集群升级前,应审计所有关键应用的 PDB 配置,校准 terminationGracePeriodSeconds 与业务超时时间,确保 Drain 操作在资源配额约束下安全执行。