节点关闭
在 Kubernetes 集群中,节点 可以通过计划内的优雅方式关闭,也可以因为断电或其他外部原因意外关闭。如果节点在关闭之前没有被清空,节点关闭可能会导致工作负载失败。节点关闭可以是**优雅的**,也可以是**非优雅的**。
优雅的节点关闭
Kubernetes v1.21 [测试版]
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-scheduler 会遵守此条件,并且不会将任何 Pod 调度到受影响的节点;其他第三方调度器预计也会遵循相同的逻辑。这意味着新的 Pod 不会被调度到该节点,因此不会有任何 Pod 启动。
如果检测到正在进行的节点关闭,kubelet 在 PodAdmission
阶段也会拒绝 Pod,这样即使是对 node.kubernetes.io/not-ready:NoSchedule
具有 容忍 的 Pod 也不会在那里启动。
同时,当 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 [测试版]
为了在优雅的节点关闭期间围绕 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 |
常规/未设置 | 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.30 中,该功能为 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 将永远停留在关闭节点上的终止状态。
为了缓解上述情况,用户可以手动将带有 NoExecute
或 NoSchedule
效果的污点 node.kubernetes.io/out-of-service
添加到节点,将其标记为停止服务。如果在 kube-controller-manager 上启用了 NodeOutOfServiceVolumeDetach
功能门控,并且使用此污点将节点标记为停止服务,则如果节点上没有匹配的容忍度,则将强制删除该节点上的 Pod,并且将立即执行针对在该节点上终止的 Pod 的卷分离操作。这允许停止服务节点上的 Pod 在其他节点上快速恢复。
在非正常关闭期间,Pod 将分两个阶段终止
- 强制删除没有匹配
out-of-service
容忍度的 Pod。 - 立即对这些 Pod 执行分离卷操作。
注意
- 在添加污点
node.kubernetes.io/out-of-service
之前,应验证节点是否已处于关闭或断电状态(不在重启过程中)。 - 在 Pod 被移动到新节点并且用户已检查关闭节点已恢复后,用户需要手动删除停止服务污点,因为用户是最初添加该污点的人。
超时时强制存储分离
在任何情况下,如果 Pod 删除在 6 分钟内未成功,并且节点在该时刻不健康,则 Kubernetes 将强制分离正在卸载的卷。任何仍在节点上运行并使用强制分离卷的工作负载都将违反 CSI 规范,该规范指出 ControllerUnpublishVolume
“**必须**在调用卷上的所有 NodeUnstageVolume
和 NodeUnpublishVolume
并成功后调用”。在这种情况下,相关节点上的卷可能会遇到数据损坏。
强制存储分离行为是可选的;用户可以选择使用“非正常节点关闭”功能。
可以通过在 kube-controller-manager
中设置 disable-force-detach-on-timeout
配置字段来禁用超时时强制存储分离。禁用超时时强制分离功能意味着,对于托管在不健康节点上超过 6 分钟的卷,不会删除其关联的 VolumeAttachment。
应用此设置后,仍附加到卷的不健康 Pod 必须通过上述非正常节点关闭过程进行恢复。
注意
- 使用非正常节点关闭过程时必须小心谨慎。
- 偏离上述步骤可能会导致数据损坏。
下一步
详细了解以下内容