为您的应用程序指定中断预算
Kubernetes v1.21 [稳定]
此页面介绍如何限制应用程序所经历的并发中断次数,从而在允许集群管理员管理集群节点的同时实现更高的可用性。
开始之前
您的 Kubernetes 服务器必须为 v1.21 或更高版本。要检查版本,请输入kubectl version
。- 您是运行在 Kubernetes 集群上的应用程序的所有者,该应用程序需要高可用性。
- 您应该了解如何部署 复制的无状态应用程序 和/或 复制的有状态应用程序。
- 您应该阅读有关 Pod 中断 的内容。
- 您应该与集群所有者或服务提供商确认他们是否尊重 Pod 中断预算。
使用 PodDisruptionBudget 保护应用程序
- 确定您要使用 PodDisruptionBudget (PDB) 保护的应用程序。
- 考虑您的应用程序如何应对中断。
- 创建 PDB 定义作为 YAML 文件。
- 从 YAML 文件创建 PDB 对象。
确定要保护的应用程序
当您想要保护由内置 Kubernetes 控制器之一指定的应用程序时,最常见的用例
- Deployment
- 复制控制器
- 副本集
- StatefulSet
在这种情况下,记下控制器的 .spec.selector
;相同的选择器将进入 PDB 的 .spec.selector
。
从版本 1.15 开始,PDB 支持自定义控制器,其中 scale 子资源 已启用。
您还可以将 PDB 与不受上述任何控制器控制的 Pod 或任意 Pod 组一起使用,但有一些限制,如 任意工作负载和任意选择器 中所述。
考虑您的应用程序如何应对中断
决定由于自愿中断,在短时间内可以同时关闭多少实例。
- 无状态前端
- 关注点:不要将服务容量降低超过 10%。
- 解决方案:例如,使用具有 minAvailable 90% 的 PDB。
- 关注点:不要将服务容量降低超过 10%。
- 单实例有状态应用程序
- 关注点:不要在没有与我联系的情况下终止此应用程序。
- 可能的解决方案 1:不要使用 PDB 并容忍偶尔的停机时间。
- 可能的解决方案 2:将 PDB 设置为 maxUnavailable=0。要了解 (在 Kubernetes 之外) 集群操作员需要在终止之前咨询您。当集群操作员联系您时,准备好停机,然后删除 PDB 以指示准备中断。之后重新创建。
- 关注点:不要在没有与我联系的情况下终止此应用程序。
- 多实例有状态应用程序,例如 Consul、ZooKeeper 或 etcd
- 关注点:不要将实例数减少到低于法定人数,否则写入将失败。
- 可能的解决方案 1:将 maxUnavailable 设置为 1(适用于不同规模的应用程序)。
- 可能的解决方案 2:将 minAvailable 设置为法定人数规模(例如,当规模为 5 时为 3)。(允许更多中断同时发生)。
- 关注点:不要将实例数减少到低于法定人数,否则写入将失败。
- 可重启批处理作业
- 关注点:作业需要在自愿中断的情况下完成。
- 可能的解决方案:不要创建 PDB。作业控制器将创建替换 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 数量。minAvailable
可以是绝对数量或百分比。.spec.maxUnavailable
(在 Kubernetes 1.7 及更高版本中可用),它描述了在驱逐后该集合中可以不可用的 Pod 数量。它可以是绝对数量或百分比。
注意
对于 PodDisruptionBudget,空选择器的行为在 policy/v1beta1 和 policy/v1 API 之间有所不同。对于 policy/v1beta1,空选择器匹配零个 Pod,而对于 policy/v1,空选择器匹配命名空间中的所有 Pod。您只能在一个 PodDisruptionBudget
中指定 maxUnavailable
和 minAvailable
中的一个。maxUnavailable
只能用于控制与具有关联控制器的 Pod 的驱逐。在下面的示例中,“所需副本数”是指管理被 PodDisruptionBudget
的 selector
选择的 Pod 的控制器的 scale
。
示例 1:使用 minAvailable
为 5,只要驱逐后留下了 5 个或更多 健康 的 Pod(在 PodDisruptionBudget 的 selector
选择的那些 Pod 中),驱逐就被允许。
示例 2:使用 minAvailable
为 30%,只要至少 30% 的所需副本数处于健康状态,驱逐就被允许。
示例 3:使用 maxUnavailable
为 5,只要在所有所需副本数中最多有 5 个不健康的副本,驱逐就被允许。
示例 4:使用 maxUnavailable
为 30%,只要不健康的副本数不超过所需副本数总量的 30%(舍入到最接近的整数),驱逐就被允许。如果所需副本数总量仅为 1,则仍然允许单个副本中断,导致 100% 的实际不可用性。
在典型的使用情况下,单个预算将用于由控制器管理的 Pod 集合——例如,单个 ReplicaSet 或 StatefulSet 中的 Pod。
注意
中断预算并不真正保证指定数量/百分比的 Pod 将始终处于启动状态。例如,当集合处于预算中指定的最小规模时,托管集合中 Pod 的节点可能会出现故障,从而使集合中可用的 Pod 数量低于指定的规模。预算只能保护免受自愿驱逐,而不能保护免受所有不可用原因的影响。如果您将 maxUnavailable
设置为 0% 或 0,或者您将 minAvailable
设置为 100% 或副本数,则您要求零自愿驱逐。当您为 ReplicaSet 等工作负载对象设置零自愿驱逐时,您将无法成功清空运行这些 Pod 之一的节点。如果您尝试清空运行不可驱逐 Pod 的节点,则清空将永远无法完成。根据 PodDisruptionBudget
的语义,这是允许的。
您可以在下面找到定义的 Pod 中断预算的示例。它们匹配具有标签 app: zookeeper
的 Pod。
使用 minAvailable 的示例 PDB
使用 maxUnavailable 的示例 PDB
例如,如果上面的 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 [稳定]
保护应用程序的 PodDisruptionBudget 确保 .status.currentHealthy
的 Pod 数量不低于 .status.desiredHealthy
中指定的数量,方法是禁止驱逐健康 Pod。通过使用 .spec.unhealthyPodEvictionPolicy
,您还可以定义何时应考虑驱逐不健康的 Pod。当未指定任何策略时,默认行为对应于 IfHealthyBudget
策略。
策略
IfHealthyBudget
- 正在运行的 Pod(
.status.phase="Running"
),但尚未健康,只有在受保护的应用程序未中断(.status.currentHealthy
至少等于.status.desiredHealthy
)的情况下才能被驱逐。 此策略确保已中断应用程序的运行 Pod 有最大的机会变得健康。这对于清空节点具有负面影响,因为行为不端的应用程序可能会阻止节点清空,这些应用程序受到 PDB 的保护。更具体地说,具有处于
CrashLoopBackOff
状态的 Pod 的应用程序(由于错误或配置错误),或者只是无法报告Ready
条件的 Pod。AlwaysAllow
- 正在运行的 Pod(
.status.phase="Running"
),但尚未健康,被视为已中断,并且可以被驱逐,无论 PDB 中的条件是否满足。 这意味着已中断应用程序的潜在运行 Pod 可能没有机会变得健康。通过使用此策略,集群管理器可以轻松驱逐受 PDB 保护的行为不端的应用程序。更具体地说,具有处于
CrashLoopBackOff
状态的 Pod 的应用程序(由于错误或配置错误),或者只是无法报告Ready
条件的 Pod。
注意
处于Pending
、Succeeded
或 Failed
阶段的 Pod 将始终被视为驱逐对象。任意工作负载和任意选择器
如果您只使用内置工作负载资源(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 时。