一、核心定义:它是什么?

PodDisruptionBudget(PDB)是 Kubernetes 中一种保护应用可用性的资源对象。 它的核心作用是在"主动的"、计划内的维护操作期间,确保一定数量的应用副本始终保持运行,防止服务中断。

简单来说,PDB 就像是你的应用的"免死金牌"或"最低保障线"。它告诉 Kubernetes:"在进行维护时,我这个应用至少要保证有 N 个副本能正常服务,不能全部停掉。"

二、为什么要用它?解决什么问题?

在 Kubernetes 集群中,有两种类型的中断:

  1. 非自愿中断:意外故障,如节点硬件损坏、操作系统崩溃、网络分区等。Kubernetes 会自动处理这种情况,将 Pod 重新调度到其他健康节点。

  2. 自愿中断计划内的、主动的操作,这正是 PDB 要管理的场景,例如:

    • 节点排水kubectl drain <node-name>(例如,节点系统升级、节点缩容)

    • 集群自动扩缩容 移除节点

    • 手动删除 Podkubectl delete pod

    • 更新 Pod 模板,触发了滚动更新(虽然 Deployment 本身有自己的策略,但 PDB 提供了额外保障)

没有 PDB 的问题:
假设你有一个 3 副本的线上支付服务。如果管理员直接对运行着这 3 个 Pod 的 3 个节点执行 drain 操作,Kubernetes 会同时驱逐这 3 个 Pod。在它们被重新调度并启动完成之前,支付服务将完全不可用,导致线上故障。

有 PDB 的解决方案:
通过创建一个 PDB,你可以规定:"支付服务最多只能有 1 个 Pod 同时不可用"。这样,Kubernetes 在执行 drain 等操作时,会"感知"到这个约束,并逐个地、安全地驱逐 Pod,确保任何时候都有至少 2 个副本在运行,服务始终可用。

三、核心工作原理

PDB 通过在 Pod 的 metadata.ownerReferences 中找到其控制器(如 Deployment、StatefulSet),并与该控制器进行"对话"来工作。

当你执行一个会引发自愿中断的命令(如 kubectl drain)时:

  1. 命令查询 PDBkubectl drain 命令会向 API Server 查询所有会受到影响的 PDB。

  2. 检查约束:Kubernetes 会计算如果允许此次驱逐,会导致多少 Pod 不可用。

  3. 决策

    • 如果驱逐后,不可用 Pod 数量仍在 PDB 允许的范围内,则允许驱逐。

    • 如果驱逐会违反 PDB 的约束,则阻止此次驱逐drain 命令会等待,直到有 Pod 被成功重新调度并变为 Ready 状态,满足了 PDB 的条件后,才会继续驱逐下一个 Pod。

  4. 这个过程是逐 Pod 进行的,确保了服务的中断始终被控制在可接受的范围内。

四、如何定义 PodDisruptionBudget

一个 PDB 资源主要包含两个关键字段:

  • .spec.selector:用于选择受保护的 Pod 的标签选择器。通常与你的 Deployment 或 StatefulSet 的 selector 一致。

  • 约束条件(二选一)

    • .spec.minAvailable:必须保持可用的 Pod 的最小数量。可以是绝对数(如 2)或百分比(如 "50%")。

    • .spec.maxUnavailable:允许不可用的 Pod 的最大数量。同样可以是绝对数或百分比。

注意: minAvailable 和 maxUnavailable 只能使用其中一个。

五、配置示例

假设我们有一个名为 frontend 的 Deployment,它运行着 5 个副本。

示例 1:使用 minAvailable(推荐方式)

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  minAvailable: 4  # 保证任何时候至少有 4 个 frontend Pod 是运行的
  selector:
    matchLabels:
      app: frontend  # 选择所有带有标签 app=frontend 的 Pod

效果:在执行节点排水时,Kubernetes 会确保 frontend 应用最多只有 1 个 Pod 被同时驱逐(5 - 4 = 1)。

示例 2:使用 maxUnavailable

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  maxUnavailable: 1  # 保证任何时候最多只有 1 个 frontend Pod 不可用
  selector:
    matchLabels:
      app: frontend

效果:与示例 1 完全相同。

示例 3:使用百分比

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  maxUnavailable: "20%"  # 最多 20% 的 Pod 不可用 (5 * 20% = 1)
  selector:
    matchLabels:
      app: frontend

六、最佳实践与注意事项

  1. 为关键服务配置 PDB:特别是那些有状态、启动较慢或对可用性要求高的服务(如数据库、消息队列、核心业务后端)。

  2. 合理设置约束

    • 对于无状态服务,maxUnavailable: 1 是一个安全且常见的起点。

    • 对于有状态服务(如 StatefulSet),可能需要更保守的策略,例如 maxUnavailable: 1,即使它有 3 个副本。

    • 确保你的约束不会过于严格,否则可能导致节点永远无法被排空("排空饥饿")。

  3. PDB 与滚动更新:PDB 也会影响 Deployment 的滚动更新过程。Kubernetes 会尊重 PDB 的约束,确保在更新过程中不会一次性杀掉太多 Pod。

  4. PDB 不保护非自愿中断:PDB 只针对计划内的自愿中断。对于节点故障等非自愿中断,由 Pod 的副本数量(如 Deployment 的 replicas)来保证恢复。

总结

PodDisruptionBudget 是 Kubernetes 生产环境中保证应用高可用性的一个至关重要的"安全阀"。它通过在计划维护期间(如节点升级、集群缩容)智能地控制 Pod 的驱逐节奏,确保了关键业务服务的连续性和稳定性。将它与你应用的 Deployment 或 StatefulSet 一起定义,是一种标准的运维最佳实践。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐