为你的应用指定中断预算

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

本页介绍如何限制应用程序可能遇到的并发中断次数,从而在集群管理员管理集群节点时允许更高的可用性。

准备工作

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

要查看版本,请输入 kubectl version

  • 你是运行在 Kubernetes 集群上需要高可用性的应用程序的所有者。
  • 你应该知道如何部署无状态应用的副本和/或有状态应用的副本
  • 你应该已经阅读了关于Pod 中断的内容。
  • 你应该向集群所有者或服务提供商确认他们是否遵守 Pod 中断预算(Pod Disruption Budgets)。

使用 PodDisruptionBudget 保护应用程序

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

确定要保护的应用程序

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

  • Deployment
  • ReplicationController
  • ReplicaSet
  • StatefulSet

在这种情况下,请记下控制器的 `.spec.selector`;相同的选择器也将用于 PDB 的 `.spec.selector`。

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

你也可以将 PDB 用于不受上述任何控制器控制的 Pod 或任意 Pod 组,但这存在一些限制,详见任意工作负载和任意选择器

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

决定由于自愿中断,在短时间内可以有多少个实例同时处于不可用状态。

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

指定百分比时的舍入逻辑

值 `minAvailable` 或 `maxUnavailable` 可以表示为整数或百分比。

  • 当你指定一个整数时,它代表 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 不存在的情况下,在驱逐后仍必须可用的 Pod 数量。`minAvailable` 可以是绝对数量或百分比。
  • `.spec.maxUnavailable`(在 Kubernetes 1.7 及更高版本中可用),描述了从该 Pod 集中,在驱逐后可以不可用的 Pod 数量。它可以是绝对数量或百分比。

你只能在单个 `PodDisruptionBudget` 中指定 `maxUnavailable` 和 `minAvailable` 中的一个。`maxUnavailable` 只能用于控制由关联控制器管理的 Pod 的驱逐。在下面的示例中,“期望的副本数”是管理由 `PodDisruptionBudget` 选择的 Pod 的控制器的 `规模(scale)`。

示例 1:如果 `minAvailable` 设置为 5,则只要在 PodDisruptionBudget 的 `selector` 选择的 Pod 中留下 5 个或更多健康的 Pod,就允许进行驱逐。

示例 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 的健康性

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

不健康 Pod 驱逐策略

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

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

策略

如果预算健康
处于运行状态 (`.status.phase="Running"`) 但尚未健康的 Pod,只有在受保护的应用程序未中断(`.status.currentHealthy` 至少等于 `.status.desiredHealthy`)时才能被驱逐。

此策略确保已中断应用程序的运行中 Pod 有最好的机会变得健康。这会对节点排空产生负面影响,因为受 PDB 保护的应用程序行为异常可能会阻止节点排空。更具体地说,是由于 bug 或配置错误导致 Pod 处于 `CrashLoopBackOff` 状态的应用程序,或仅仅是未能报告 `Ready` 状况的 Pod。

始终允许
处于运行状态 (`.status.phase="Running"`) 但尚未健康的 Pod 被视为已中断,无论 PDB 中的标准是否满足,都可以被驱逐。

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

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

如果你只将 PDB 与内置工作负载资源(Deployment、ReplicaSet、StatefulSet 和 ReplicationController)一起使用,或者与实现了自定义资源中 `规模(scale)` 子资源的资源一起使用,并且 PDB 选择器与 Pod 拥有资源的精确匹配,则可以跳过本节。

你可以将 PDB 用于由其他资源、"Operator" 或裸 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)