节点关机
在 Kubernetes 集群中,节点(node)可以以计划的优雅方式关机,也可以因停电或其它外部原因意外关机。如果在关机前未对节点执行 Drain(驱逐),节点关机可能会导致工作负载故障。节点关机可以分为优雅(graceful)关机和非优雅(non-graceful)关机。
优雅节点关机
Kubernetes v1.21 [beta]
(默认启用:true)Kubelet 尝试检测节点系统关机并终止在该节点上运行的 Pod。
Kubelet 确保 Pod 在节点关机期间遵循正常的Pod 终止过程。在节点关机期间,Kubelet 不接受新的 Pod(即使这些 Pod 已绑定到该节点)。
优雅节点关机特性依赖于 systemd,因为它利用 systemd inhibitor locks 来按照给定的持续时间延迟节点关机。
优雅节点关机由 GracefulNodeShutdown
Feature Gate 控制,该 Feature Gate 在 1.21 版本中默认启用。
请注意,默认情况下,下面描述的两个配置选项 shutdownGracePeriod
和 shutdownGracePeriodCriticalPods
都设置为零,因此不会激活优雅节点关机功能。要激活该功能,应适当配置这两个选项并将其设置为非零值。
一旦 systemd 检测到或收到节点关机通知,kubelet 会在节点上设置 NotReady
状态,并将 reason
设置为 "node is shutting down"
。kube-scheduler 会遵守此状态,不会将任何 Pod 调度到受影响的节点上;其他第三方调度器也应遵循相同的逻辑。这意味着新的 Pod 不会被调度到该节点上,因此不会启动。
如果检测到正在进行的节点关机,Kubelet 在 PodAdmission
阶段也会拒绝 Pod,以便即使是具有与 node.kubernetes.io/not-ready:NoSchedule
匹配的容忍度(toleration)的 Pod 也不会在此启动。
当 kubelet 通过 API 在其节点上设置该状态时,kubelet 也开始终止所有在本地运行的 Pod。
在优雅关机期间,kubelet 分两个阶段终止 Pod:
- 终止在该节点上运行的常规 Pod。
- 终止在该节点上运行的关键 Pod。
优雅节点关机功能可通过两个 KubeletConfiguration
选项进行配置:
shutdownGracePeriod
:指定节点应延迟关机的总持续时间。这是常规 Pod 和关键 Pod 终止的总优雅限期。
shutdownGracePeriodCriticalPods
:指定在节点关机期间用于终止关键 Pod 的持续时间。此值应小于
shutdownGracePeriod
。
注意
在某些情况下,节点终止可能会被系统取消(或者由管理员手动取消)。在这些情况下,节点将返回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]
(默认启用:true)为了在优雅节点关机期间,针对 Pod 终止顺序提供更高的灵活性,优雅节点关机会遵守 Pod 的 PriorityClass(前提是你在集群中启用了此特性)。此特性允许集群管理员基于优先级类别(priority classes)明确定义优雅节点关机期间 Pod 的终止顺序。
优雅节点关机特性如上所述,分两个阶段关闭 Pod:非关键 Pod,然后是关键 Pod。如果需要更多灵活性来以更精细的方式明确定义关机期间 Pod 的顺序,可以使用基于 Pod 优先级的优雅关机。
当优雅节点关机遵守 Pod 优先级时,可以在多个阶段进行优雅节点关机,每个阶段关闭特定优先级类别的 Pod。可以为 kubelet 配置精确的阶段和每个阶段的关机时间。
假设集群中有以下自定义的 Pod 优先级类别(priority classes):
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,则 kubelet 不会等待该优先级范围内的 Pod。相反,kubelet 会立即跳到下一个优先级类别值范围。
如果此特性已启用但未提供配置,则不会执行任何排序操作。
使用此特性需要启用 GracefulNodeShutdownBasedOnPodPriority
Feature Gate,并在 kubelet 配置中将 ShutdownGracePeriodByPodPriority
设置为所需的配置,其中包含 Pod 优先级类别值及其相应的关机周期。
注意
在优雅节点关机期间考虑 Pod 优先级的特性在 Kubernetes v1.23 中作为 Alpha 特性引入。在 Kubernetes 1.33 中,此特性为 Beta,并默认启用。指标 graceful_shutdown_start_time_seconds
和 graceful_shutdown_end_time_seconds
在 kubelet 子系统下发出,用于监视节点关机。
非优雅节点关机处理
Kubernetes v1.28 [stable]
(默认启用:true)Kubelet 的节点关机管理器可能无法检测到节点关机操作,这可能是因为该命令没有触发 kubelet 使用的 inhibitor locks 机制,也可能是由于用户错误,即 ShutdownGracePeriod 和 ShutdownGracePeriodCriticalPods 未正确配置。请参考上面关于优雅节点关机的章节了解更多详情。
当节点关机但未被 kubelet 的节点关机管理器检测到时,属于有状态集合(StatefulSet)的 Pod 将停留在关机节点上的 Terminating 状态,无法移动到新的运行节点。这是因为关机节点上的 kubelet 不可用,无法删除 Pod,因此 StatefulSet 无法创建同名的新 Pod。如果 Pod 使用了卷,VolumeAttachment 将不会从原始关机节点中删除,因此这些 Pod 使用的卷无法挂接到新的运行节点。结果是,运行在 StatefulSet 上的应用程序无法正常工作。如果原始关机节点启动,kubelet 将删除 Pod,并在不同的运行节点上创建新的 Pod。如果原始关机节点未启动,这些 Pod 将永远停留在关机节点上的 Terminating 状态。
为了缓解上述情况,用户可以手动为节点添加带有 NoExecute
或 NoSchedule
效果的污点 node.kubernetes.io/out-of-service
,将其标记为停止服务(out-of-service)。如果节点被标记为停止服务并带有此污点,则节点上的 Pod 如果没有匹配的容忍度,将被强制删除,并且正在终止的 Pod 的卷分离(detach volume)操作将立即发生。这使得停止服务节点上的 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 必须通过上述的非优雅节点关机流程来恢复。
注意
- 使用非优雅节点关机流程时必须小心谨慎。
- 偏离上述文档中的步骤可能导致数据损坏。
Windows 优雅节点关机
Kubernetes v1.32 [alpha]
(默认启用:false)Windows 优雅节点关机特性依赖于 kubelet 作为 Windows 服务运行,然后它将拥有一个注册的 服务控制处理程序(service control handler),以给定的持续时间延迟 preshutdown 事件。
Windows 优雅节点关机由 WindowsGracefulNodeShutdown
Feature Gate 控制,该 Feature Gate 在 1.32 版本中作为 Alpha 特性引入。
Windows 优雅节点关机无法取消。
如果 kubelet 未作为 Windows 服务运行,它将无法设置和监视 Preshutdown 事件,节点将不得不经历上述的非优雅节点关机流程。
在启用了 Windows 优雅节点关机特性,但 kubelet 未作为 Windows 服务运行的情况下,kubelet 将继续运行而不是失败。但是,它会记录一条错误,指示需要将其作为 Windows 服务运行。
下一步
了解更多关于以下内容的信息: