节点关闭
在 Kubernetes 集群中,一个 节点 可以以计划的优雅方式关闭,也可以由于电源故障或其他外部原因意外关闭。如果节点在关闭之前未被清空,则节点关闭可能会导致工作负载失败。节点关闭可以是 **优雅的** 或 **非优雅的**。
优雅节点关闭
Kubernetes v1.21 [beta]
Kubelet 尝试检测节点系统关闭并终止在节点上运行的 Pod。
Kubelet 确保 Pod 在节点关闭期间遵循正常的 Pod 终止过程。在节点关闭期间,Kubelet 不会接受新的 Pod(即使这些 Pod 已绑定到节点)。
优雅节点关闭功能依赖于 systemd,因为它利用了 systemd 抑制锁 来延迟节点关闭给定的持续时间。
优雅节点关闭由 GracefulNodeShutdown
功能开关 控制,该开关在 1.21 中默认启用。
请注意,默认情况下,下面描述的两个配置选项 shutdownGracePeriod
和 shutdownGracePeriodCriticalPods
都设置为零,因此不会激活优雅节点关闭功能。要激活该功能,应适当地配置这两个 Kubelet 配置设置并将其设置为非零值。
一旦 systemd 检测到或通知节点关闭,Kubelet 就会在节点上设置一个 NotReady
条件,并将 reason
设置为 "node is shutting down"
。Kube-调度器会尊重此条件,不会将任何 Pod 调度到受影响的节点;其他第三方调度器预计会遵循相同的逻辑。这意味着不会将新 Pod 调度到该节点,因此不会启动任何 Pod。
Kubelet 还会在 PodAdmission
阶段拒绝 Pod,如果检测到正在进行的节点关闭,即使 Pod 具有 容忍度 针对 node.kubernetes.io/not-ready:NoSchedule
也不在那里启动。
与 Kubelet 通过 API 在其节点上设置该条件的同时,Kubelet 还开始终止在本地运行的任何 Pod。
在优雅关闭期间,Kubelet 分两个阶段终止 Pod
- 终止在节点上运行的常规 Pod。
- 终止在节点上运行的 关键 Pod。
优雅节点关闭功能通过两个 KubeletConfiguration
选项配置
shutdownGracePeriod
:- 指定节点应延迟关闭的总持续时间。这是常规 Pod 和 关键 Pod 的 Pod 终止的总宽限期。
shutdownGracePeriodCriticalPods
:- 指定用于在节点关闭期间终止 关键 Pod 的持续时间。此值应小于
shutdownGracePeriod
。
- 指定用于在节点关闭期间终止 关键 Pod 的持续时间。此值应小于
注意
在某些情况下,节点终止会被系统取消(或者可能是管理员手动取消)。在这两种情况下,节点都会恢复到Ready
状态。但是,已经开始终止过程的 Pod 不会被 Kubelet 恢复,需要重新调度。例如,如果 shutdownGracePeriod=30s
,而 shutdownGracePeriodCriticalPods=10s
,则 Kubelet 将延迟节点关闭 30 秒。在关闭期间,前 20 秒(30-10)将保留用于优雅地终止常规 Pod,最后 10 秒将保留用于终止 关键 Pod。
注意
在优雅节点关闭期间驱逐 Pod 后,它们将被标记为关闭。运行 kubectl get pods
会显示被驱逐 Pod 的状态为 Terminated
。而 kubectl describe pod
会指出 Pod 被驱逐是因为节点关闭
Reason: Terminated
Message: Pod was terminated in response to imminent node shutdown.
基于 Pod 优先级的优雅节点关闭
Kubernetes v1.24 [beta]
为了在优雅节点关闭期间提供更多灵活性,以便在关闭期间对 Pod 的排序进行调整,优雅节点关闭会尊重 Pod 的 PriorityClass,前提是您在集群中启用了此功能。该功能允许集群管理员根据 优先级类 明确定义优雅节点关闭期间 Pod 的排序。
优雅节点关闭 功能(如上所述)分两个阶段关闭 Pod,非关键 Pod,然后是关键 Pod。如果需要额外的灵活性以更细粒度的方式明确定义关闭期间 Pod 的排序,则可以使用基于 Pod 优先级的优雅节点关闭。
当优雅节点关闭尊重 Pod 优先级时,这使得可以在多个阶段执行优雅节点关闭,每个阶段都关闭特定优先级类的 Pod。Kubelet 可以配置每个阶段的确切阶段和关闭时间。
假设集群中有以下自定义 Pod 优先级类,
Pod 优先级类名称 | Pod 优先级类值 |
---|---|
custom-class-a | 100000 |
custom-class-b | 10000 |
custom-class-c | 1000 |
regular/unset | 0 |
在 Kubelet 配置 中,shutdownGracePeriodByPodPriority
的设置可能如下所示
Pod 优先级类值 | 关闭期间 |
---|---|
100000 | 10 秒 |
10000 | 180 秒 |
1000 | 120 秒 |
0 | 60 秒 |
相应的 Kubelet 配置 YAML 配置将是
shutdownGracePeriodByPodPriority:
- priority: 100000
shutdownGracePeriodSeconds: 10
- priority: 10000
shutdownGracePeriodSeconds: 180
- priority: 1000
shutdownGracePeriodSeconds: 120
- priority: 0
shutdownGracePeriodSeconds: 60
上表意味着任何 priority
值 >= 100000 的 Pod 都只有 10 秒的时间停止,任何值 >= 10000 且 < 100000 的 Pod 都只有 180 秒的时间停止,任何值 >= 1000 且 < 10000 的 Pod 都只有 120 秒的时间停止。最后,所有其他 Pod 将有 60 秒的时间停止。
不必指定与所有类相对应的值。例如,您可以使用以下设置
Pod 优先级类值 | 关闭期间 |
---|---|
100000 | 300 秒 |
1000 | 120 秒 |
0 | 60 秒 |
在上述情况下,custom-class-b
的 Pod 将与 custom-class-c
的 Pod 进入相同的关闭桶。
如果某个特定范围内没有 Pod,则 Kubelet 不会等待该优先级范围内的 Pod。相反,Kubelet 会立即跳到下一个优先级类值范围。
如果启用了此功能并且没有提供任何配置,则不会执行任何排序操作。
使用此功能需要启用 GracefulNodeShutdownBasedOnPodPriority
功能开关,并将 Kubelet 配置 中的 ShutdownGracePeriodByPodPriority
设置为包含 Pod 优先级类值及其各自关闭期间的所需配置。
注意
在 Kubernetes v1.23 中,在优雅节点关闭期间考虑 Pod 优先级的功能作为 Alpha 功能引入。在 Kubernetes 1.31 中,该功能为 Beta,默认启用。指标 graceful_shutdown_start_time_seconds
和 graceful_shutdown_end_time_seconds
在 Kubelet 子系统下发出,用于监控节点关闭。
非优雅节点关闭处理
Kubernetes v1.28 [稳定]
Kubelet 的节点关闭管理器可能无法检测到节点关闭操作,原因可能是命令没有触发 Kubelet 使用的抑制锁机制,或者是因为用户错误,即 ShutdownGracePeriod 和 ShutdownGracePeriodCriticalPods 未正确配置。有关更多详细信息,请参考上面的部分 优雅节点关闭。
当节点关闭但未被 Kubelet 的节点关闭管理器检测到时,属于 StatefulSet 的 Pod 将停留在关闭节点上的终止状态,并且无法移动到新的运行节点。这是因为关闭节点上的 Kubelet 无法删除 Pod,因此 StatefulSet 无法创建具有相同名称的新 Pod。如果 Pod 使用了卷,则 VolumeAttachments 不会从原始关闭节点中删除,因此这些 Pod 使用的卷无法附加到新的运行节点。结果,在 StatefulSet 上运行的应用程序无法正常运行。如果原始关闭节点启动,Kubelet 会删除这些 Pod,并在不同的运行节点上创建新的 Pod。如果原始关闭节点未启动,这些 Pod 将永远停留在关闭节点上的终止状态。
为了缓解上述情况,用户可以手动将污点 node.kubernetes.io/out-of-service
添加到节点,并使用 NoExecute
或 NoSchedule
效果标记其为停用。如果在 kube-controller-manager 上启用了 NodeOutOfServiceVolumeDetach
功能开关,并且节点使用此污点标记为停用,如果节点上没有匹配的容忍度,则节点上的 Pod 将被强制删除,并且在节点上终止的 Pod 的卷分离操作将立即发生。这使得停用节点上的 Pod 可以在其他节点上快速恢复。
在非优雅关闭期间,Pod 分两个阶段终止
- 强制删除没有匹配
out-of-service
容忍度的 Pod。 - 立即对这些 Pod 执行分离卷操作。
注意
- 在添加污点
node.kubernetes.io/out-of-service
之前,应验证节点是否已处于关闭或断电状态(而不是处于重启过程中)。 - 在将 Pod 移动到新节点并检查已关闭的节点已恢复后,用户需要手动删除 `out-of-service` 污点,因为是用户最初添加了该污点。
超时强制存储分离
在任何情况下,如果 Pod 删除在 6 分钟内未成功,并且节点此时处于不健康状态,Kubernetes 将强制分离正在卸载的卷。任何仍在节点上运行并使用强制分离卷的工作负载都将违反 CSI 规范,该规范指出 `ControllerUnpublishVolume` “**必须**在所有卷上的 `NodeUnstageVolume` 和 `NodeUnpublishVolume` 被调用并成功后调用”。在这种情况下,问题节点上的卷可能会遇到数据损坏。
强制存储分离行为是可选的;用户可以选择使用“非正常节点关闭”功能。
可以通过在 `kube-controller-manager` 中设置 `disable-force-detach-on-timeout` 配置字段来禁用超时强制存储分离。禁用超时强制分离功能意味着托管在超过 6 分钟处于不健康状态的节点上的卷不会与其关联的 VolumeAttachment 被删除。
应用此设置后,仍然附加到卷的不健康 Pod 必须通过上面提到的 非正常节点关闭 过程来恢复。
注意
- 使用 非正常节点关闭 过程时必须谨慎。
- 偏离上述文档步骤会导致数据损坏。
下一步
了解更多信息