为应用程序指定中断预算

特性状态: Kubernetes v1.21 [stable]

本页面展示了如何限制应用程序所经历的并发中断次数,从而在允许集群管理员管理集群节点的同时,提高应用程序的可用性。

准备工作

你的 Kubernetes 服务器版本必须是 v1.21 或更高。

要检查版本,请输入 kubectl version

使用 PodDisruptionBudget 保护应用程序

  1. 识别你想使用 PodDisruptionBudget (PDB) 保护的应用程序。
  2. 思考你的应用程序如何应对中断。
  3. 创建一个 YAML 文件的 PDB 定义。
  4. 从 YAML 文件创建 PDB 对象。

识别要保护的应用程序

最常见的用例是,你想保护由内置 Kubernetes 控制器之一指定的应用程序。

  • 部署
  • 复制控制器
  • 副本集
  • StatefulSet

在这种情况下,记下控制器的 .spec.selector;同样的 Selector 也将用于 PDB 的 .spec.selector

从版本 1.15 开始,PDB 支持启用了扩缩子资源的自定义控制器。

你也可以将 PDB 与不受上述控制器控制的 Pod 或任意 Pod 组一起使用,但有一些限制,请参阅任意工作负载和任意选择器

思考你的应用程序如何应对中断

决定在由于自愿中断而导致的短时间内,可以同时有多少个实例停机。

  • 无状态前端
    • 问题:不要将服务容量减少超过 10%。
      • 解决方案:例如,使用 PDB 并设置 minAvailable 为 90%。
  • 单实例有状态应用程序
    • 问题:未经我同意,请勿终止此应用程序。
      • 可能解决方案 1:不使用 PDB 并容忍偶尔的停机时间。
      • 可能解决方案 2:设置 PDB 并设置 maxUnavailable=0。达成一项(在 Kubernetes 之外的)协议,即集群操作员在终止前需要咨询你。当集群操作员联系你时,准备停机,然后删除 PDB 以表示已准备好中断。之后重新创建。
  • 多实例有状态应用程序,例如 Consul、ZooKeeper 或 etcd
    • 问题:不要将实例数量减少到仲裁以下,否则写入将失败。
      • 可能解决方案 1:将 maxUnavailable 设置为 1(适用于不同规模的应用程序)。
      • 可能解决方案 2:将 minAvailable 设置为仲裁大小(例如,当规模为 5 时设置为 3)。 (允许更多中断同时发生)。
  • 可重启的批处理作业
    • 问题:作业在自愿中断时需要完成。
      • 可能解决方案:不创建 PDB。Job 控制器将创建一个替换 Pod。

指定百分比时的舍入逻辑

minAvailablemaxUnavailable 的值可以表示为整数或百分比。

  • 当你指定一个整数时,它表示 Pod 的数量。例如,如果你将 minAvailable 设置为 10,那么即使在中断期间,也必须始终有 10 个 Pod 可用。
  • 当你通过将值设置为百分比的字符串表示(例如 "50%")来指定百分比时,它表示总 Pod 的百分比。例如,如果你将 minAvailable 设置为 "50%",那么在中断期间,至少有 50% 的 Pod 保持可用。

当你将值指定为百分比时,它可能无法映射到精确的 Pod 数量。例如,如果你有 7 个 Pod 并将 minAvailable 设置为 "50%",那么这意味着必须有 3 个 Pod 还是 4 个 Pod 可用,这并不立即显而易见。Kubernetes 会向上舍入到最接近的整数,因此在这种情况下,必须有 4 个 Pod 可用。当你将 maxUnavailable 值指定为百分比时,Kubernetes 会向上舍入可能被中断的 Pod 数量。因此,中断可能会超过你定义的 maxUnavailable 百分比。你可以查看控制此行为的代码

指定 PodDisruptionBudget

PodDisruptionBudget 有三个字段

  • 一个标签选择器 .spec.selector,用于指定它适用的 Pod 集合。此字段是必需的。
  • .spec.minAvailable,描述了从该集合中在驱逐后仍必须可用的 Pod 数量,即使没有被驱逐的 Pod。minAvailable 可以是绝对数量或百分比。
  • .spec.maxUnavailable(在 Kubernetes 1.7 及更高版本中可用),描述了从该集合中在驱逐后可以不可用的 Pod 数量。它可以是绝对数量或百分比。

在一个 PodDisruptionBudget 中,你只能指定 maxUnavailableminAvailable 中的一个。maxUnavailable 只能用于控制拥有关联控制器管理的 Pod 的驱逐。在下面的示例中,“所需副本数”是管理由 PodDisruptionBudget 选择的 Pod 的控制器的 scale

示例 1:当 minAvailable 为 5 时,只要 PodDisruptionBudget 的 selector 所选的 Pod 中,剩余 健康的 Pod 数量为 5 个或更多,就允许驱逐。

示例 2:当 minAvailable 为 30% 时,只要所需副本总数的至少 30% 是健康的,就允许驱逐。

示例 3:当 maxUnavailable 为 5 时,只要所需副本总数中不健康的副本数量最多为 5 个,就允许驱逐。

示例 4:当 maxUnavailable 为 30% 时,只要不健康副本的数量不超过所需副本总数的 30%(向上取整到最接近的整数),就允许驱逐。如果所需副本总数只有一个,则该单个副本仍然允许中断,导致有效不可用性达到 100%。

在典型用法中,一个预算将用于由控制器管理的 Pod 集合——例如,单个 ReplicaSet 或 StatefulSet 中的 Pod。

如果你将 maxUnavailable 设置为 0% 或 0,或者将 minAvailable 设置为 100% 或副本数,则你要求零自愿驱逐。当你为一个工作负载对象(例如 ReplicaSet)设置零自愿驱逐时,你将无法成功排空运行其中一个 Pod 的节点。如果你尝试排空一个运行不可驱逐 Pod 的节点,排空将永远无法完成。这符合 PodDisruptionBudget 的语义,是被允许的。

你可以在下面找到定义的 Pod 中断预算示例。它们匹配带有标签 app: zookeeper 的 Pod。

使用 minAvailable 的 PDB 示例

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

使用 maxUnavailable 的 PDB 示例

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: zookeeper

例如,如果上述 zk-pdb 对象选择大小为 3 的 StatefulSet 中的 Pod,则这两个规范具有完全相同的含义。建议使用 maxUnavailable,因为它会自动响应相应控制器副本数的变化。

创建 PDB 对象

你可以使用 kubectl 创建或更新 PDB 对象。

kubectl apply -f mypdb.yaml

检查 PDB 的状态

使用 kubectl 检查你的 PDB 是否已创建。

假设你的命名空间中实际上没有匹配 app: zookeeper 的 Pod,那么你会看到类似这样的内容

kubectl get poddisruptionbudgets
NAME     MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
zk-pdb   2               N/A               0                     7s

如果有匹配的 Pod(例如 3 个),那么你会看到类似这样的内容

kubectl get poddisruptionbudgets
NAME     MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
zk-pdb   2               N/A               1                     7s

ALLOWED DISRUPTIONS 的非零值表示中断控制器已经看到了 Pod,计算了匹配的 Pod,并更新了 PDB 的状态。

你可以使用此命令获取有关 PDB 状态的更多信息

kubectl get poddisruptionbudgets zk-pdb -o yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  annotations:

  creationTimestamp: "2020-03-04T04:22:56Z"
  generation: 1
  name: zk-pdb

status:
  currentHealthy: 3
  desiredHealthy: 2
  disruptionsAllowed: 1
  expectedPods: 3
  observedGeneration: 1

Pod 的健康状态

当前的实现将健康的 Pod 视为 .status.conditions 项中 type="Ready"status="True" 的 Pod。这些 Pod 通过 PDB 状态中的 .status.currentHealthy 字段进行跟踪。

不健康 Pod 的驱逐策略

特性状态: Kubernetes v1.31 [stable] (默认启用:true)

保护应用程序的 PodDisruptionBudget 确保通过不允许驱逐健康的 Pod,使 .status.currentHealthy 的 Pod 数量不会低于 .status.desiredHealthy 中指定的数量。通过使用 .spec.unhealthyPodEvictionPolicy,你还可以定义何时应考虑驱逐不健康 Pod 的标准。未指定策略时的默认行为对应于 IfHealthyBudget 策略。

策略

IfHealthyBudget
正在运行 (.status.phase="Running") 但尚未健康的 Pod 只有在受保护的应用程序未中断 (.status.currentHealthy 至少等于 .status.desiredHealthy) 时才能被驱逐。

此策略确保已中断应用程序中正在运行的 Pod 有最佳机会变得健康。这对于排空节点具有负面影响,因为它们可能被受 PDB 保护的行为异常应用程序(例如,由于错误或配置错误而处于 CrashLoopBackOff 状态的 Pod,或未能报告 Ready 状况的 Pod)阻塞。

AlwaysAllow
正在运行 (.status.phase="Running") 但尚未健康的 Pod 被视为已中断,无论 PDB 中的标准是否满足,都可以被驱逐。

这意味着中断应用程序中预期运行的 Pod 可能没有机会变得健康。通过使用此策略,集群管理员可以轻松驱逐受 PDB 保护的行为异常应用程序。更具体地说,是由于 bug 或配置错误而处于 CrashLoopBackOff 状态的应用程序,或者只是未能报告 Ready 状况的 Pod。

任意工作负载和任意选择器

如果你只将 PDB 与内置工作负载资源(Deployment、ReplicaSet、StatefulSet 和 ReplicationController)或实现 scale 子资源自定义资源一起使用,并且 PDB 选择器与 Pod 的拥有资源的选择器完全匹配,则可以跳过此部分。

你可以将 PDB 与由其他资源、"操作符" 或裸 Pod 控制的 Pod 一起使用,但有以下限制:

  • 只能使用 .spec.minAvailable,不能使用 .spec.maxUnavailable
  • .spec.minAvailable 只能使用整数值,不能使用百分比。

无法使用其他可用性配置,因为 Kubernetes 在没有受支持的拥有资源的情况下无法派生 Pod 的总数。

你可以使用选择器来选择属于工作负载资源的 Pod 的子集或超集。驱逐 API 将不允许驱逐被多个 PDB 覆盖的任何 Pod,因此大多数用户会希望避免重叠的选择器。重叠 PDB 的一个合理用途是在 Pod 从一个 PDB 转换到另一个 PDB 时。

上次修改时间:2024 年 2 月 21 日 晚上 11:53 PST:将 PDBUnhealthyPodEvictionPolicy 提升为 GA (f364b4c247)