diff --git a/content/zh-cn/docs/concepts/cluster-administration/node-shutdown.md b/content/zh-cn/docs/concepts/cluster-administration/node-shutdown.md new file mode 100644 index 0000000000..fc6c769999 --- /dev/null +++ b/content/zh-cn/docs/concepts/cluster-administration/node-shutdown.md @@ -0,0 +1,518 @@ +--- +title: 节点关闭 +content_type: concept +weight: 10 +--- + + + + +在 Kubernetes 集群中,{{< glossary_tooltip text="节点" term_id="node" >}}可以按计划的体面方式关闭, +也可能因断电或其他某些外部原因被意外关闭。如果节点在关闭之前未被排空,则节点关闭可能会导致工作负载失败。 +节点可以**体面关闭**或**非体面关闭**。 + + + + +## 节点体面关闭 {#graceful-node-shutdown} + +{{< feature-state feature_gate_name="GracefulNodeShutdown" >}} + + +kubelet 会尝试检测节点系统关闭事件并终止在节点上运行的所有 Pod。 + +在节点终止期间,kubelet 保证 Pod 遵从常规的 +[Pod 终止流程](/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination), +且不接受新的 Pod(即使这些 Pod 已经绑定到该节点)。 + + +节点体面关闭特性依赖于 systemd,因为它要利用 +[systemd 抑制器锁](https://www.freedesktop.org/wiki/Software/systemd/inhibit/)机制, +在给定的期限内延迟节点关闭。 + + +节点体面关闭特性受 `GracefulNodeShutdown` +[特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/)控制, +在 1.21 版本中是默认启用的。 + + +注意,默认情况下,下面描述的两个配置选项,`shutdownGracePeriod` 和 +`shutdownGracePeriodCriticalPods` 都是被设置为 0 的,因此不会激活节点体面关闭功能。 +要激活此功能特性,这两个 kubelet 配置选项要适当配置,并设置为非零值。 + + +一旦 systemd 检测到或通知节点关闭,kubelet 就会在节点上设置一个 +`NotReady` 状况,并将 `reason` 设置为 `"node is shutting down"`。 +kube-scheduler 会重视此状况,不将 Pod 调度到受影响的节点上; +其他第三方调度程序也应当遵循相同的逻辑。这意味着新的 Pod 不会被调度到该节点上, +因此不会有新 Pod 启动。 + + +如果检测到节点关闭正在进行中,kubelet **也会**在 `PodAdmission` +阶段拒绝 Pod,即使是该 Pod 带有 `node.kubernetes.io/not-ready:NoSchedule` +的{{< glossary_tooltip text="容忍度" term_id="toleration" >}},也不会在此节点上启动。 + + +同时,当 kubelet 通过 API 在其 Node 上设置该状况时,kubelet +也开始终止在本地运行的所有 Pod。 + + +在体面关闭节点过程中,kubelet 分两个阶段来终止 Pod: + +1. 终止在节点上运行的常规 Pod。 +2. 终止在节点上运行的[关键 Pod](/zh-cn/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/#marking-pod-as-critical)。 + + +节点体面关闭的特性对应两个 +[`KubeletConfiguration`](/zh-cn/docs/tasks/administer-cluster/kubelet-config-file/) 选项: + +* `shutdownGracePeriod`: + * 指定节点应延迟关闭的总持续时间。这是 Pod 体面终止的时间总和,不区分常规 Pod + 还是[关键 Pod](/zh-cn/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/#marking-pod-as-critical)。 +* `shutdownGracePeriodCriticalPods`: + * 在节点关闭期间指定用于终止[关键 Pod](/zh-cn/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/#marking-pod-as-critical) + 的持续时间。该值应小于 `shutdownGracePeriod`。 + +{{< note >}} + +在某些情况下,节点终止过程会被系统取消(或者可能由管理员手动取消)。 +无论哪种情况下,节点都将返回到 `Ready` 状态。然而,已经开始终止进程的 +Pod 将不会被 kubelet 恢复,需要被重新调度。 +{{< /note >}} + + +例如,如果设置了 `shutdownGracePeriod=30s` 和 `shutdownGracePeriodCriticalPods=10s`, +则 kubelet 将延迟 30 秒关闭节点。 +在关闭期间,将保留前 20(30 - 10)秒用于体面终止常规 Pod, +而保留最后 10 秒用于终止[关键 Pod](/zh-cn/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/#marking-pod-as-critical)。 + +{{< note >}} + +当 Pod 在正常节点关闭期间被驱逐时,它们会被标记为关闭。 +运行 `kubectl get pods` 时,被驱逐的 Pod 的状态显示为 `Terminated`。 +并且 `kubectl describe pod` 表示 Pod 因节点关闭而被驱逐: + +``` +Reason: Terminated +Message: Pod was terminated in response to imminent node shutdown. +``` +{{< /note >}} + + +### 基于 Pod 优先级的节点体面关闭 {#pod-priority-graceful-node-shutdown} + +{{< feature-state feature_gate_name="GracefulNodeShutdownBasedOnPodPriority" >}} + + +为了在节点体面关闭期间提供更多的灵活性,尤其是处理关闭期间的 Pod 排序问题, +节点体面关闭机制能够关注 Pod 的 PriorityClass 设置,前提是你已经在集群中启用了此功能特性。 +此特性允许集群管理员基于 Pod +的[优先级类(Priority Class)](/zh-cn/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass) +显式地定义节点体面关闭期间 Pod 的处理顺序。 + + +前文所述的[节点体面关闭](#graceful-node-shutdown)特性能够分两个阶段关闭 Pod, +首先关闭的是非关键的 Pod,之后再处理关键 Pod。 +如果需要显式地以更细粒度定义关闭期间 Pod 的处理顺序,需要一定的灵活度, +这时可以使用基于 Pod 优先级的体面关闭机制。 + + +当节点体面关闭能够处理 Pod 优先级时,节点体面关闭的处理可以分为多个阶段, +每个阶段关闭特定优先级类的 Pod。可以配置 kubelet 按确切的阶段处理 Pod, +且每个阶段可以独立设置关闭时间。 + + +假设集群中存在以下自定义的 Pod +[优先级类](/zh-cn/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass)。 + + +| Pod 优先级类名称 | Pod 优先级类数值 | +|-------------------------|------------------------| +|`custom-class-a` | 100000 | +|`custom-class-b` | 10000 | +|`custom-class-c` | 1000 | +|`regular/unset` | 0 | + + +在 [kubelet 配置](/zh-cn/docs/reference/config-api/kubelet-config.v1beta1/)中, +`shutdownGracePeriodByPodPriority` 看起来可能是这样: + + +| Pod 优先级类数值 | 关闭期限 | +|------------------------|-----------| +| 100000 | 10 秒 | +| 10000 | 180 秒 | +| 1000 | 120 秒 | +| 0 | 60 秒 | + + +对应的 kubelet 配置 YAML 将会是: + +```yaml +shutdownGracePeriodByPodPriority: + - priority: 100000 + shutdownGracePeriodSeconds: 10 + - priority: 10000 + shutdownGracePeriodSeconds: 180 + - priority: 1000 + shutdownGracePeriodSeconds: 120 + - priority: 0 + shutdownGracePeriodSeconds: 60 +``` + + +上面的表格表明,所有 `priority` 值大于等于 100000 的 Pod 停止期限只有 10 秒, +所有 `priority` 值介于 10000 和 100000 之间的 Pod 停止期限是 180 秒, +所有 `priority` 值介于 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` +[特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/), +并将 [kubelet 配置](/zh-cn/docs/reference/config-api/kubelet-config.v1beta1/) +中的 `shutdownGracePeriodByPodPriority` 设置为期望的配置, +其中包含 Pod 的优先级类数值以及对应的关闭期限。 + +{{< note >}} + +在节点体面关闭期间考虑 Pod 优先级的能力是作为 Kubernetes v1.23 中的 Alpha 功能引入的。 +在 Kubernetes {{< skew currentVersion >}} 中该功能是 Beta 版,默认启用。 +{{< /note >}} + + +kubelet 子系统中会生成 `graceful_shutdown_start_time_seconds` 和 +`graceful_shutdown_end_time_seconds` 度量指标以便监视节点关闭行为。 + + +## 处理节点非体面关闭 {#non-graceful-node-shutdown} + +{{< feature-state feature_gate_name="NodeOutOfServiceVolumeDetach" >}} + + +节点关闭的操作可能无法被 kubelet 的节点关闭管理器检测到, +或是因为该命令没有触发 kubelet 所使用的抑制器锁机制,或是因为用户错误, +即 ShutdownGracePeriod 和 ShutdownGracePeriodCriticalPod 配置不正确。 +请参考以上[节点体面关闭](#graceful-node-shutdown)部分了解更多详细信息。 + + +当某节点关闭但 kubelet 的节点关闭管理器未检测到这一事件时, +在那个已关闭节点上、属于 {{< glossary_tooltip text="StatefulSet" term_id="statefulset" >}} +的 Pod 将停滞于终止状态,并且不能移动到新的运行节点上。 +这是因为已关闭节点上的 kubelet 已不存在,亦无法删除 Pod, +因此 StatefulSet 无法创建同名的新 Pod。 +如果 Pod 使用了卷,则 VolumeAttachments 无法从原来的已关闭节点上删除, +因此这些 Pod 所使用的卷也无法挂接到新的运行节点上。 +最终,那些以 StatefulSet 形式运行的应用无法正常工作。 +如果原来的已关闭节点被恢复,kubelet 将删除 Pod,新的 Pod 将被在不同的运行节点上创建。 +如果原来的已关闭节点没有被恢复,那些在已关闭节点上的 Pod 将永远滞留在终止状态。 + + +为了缓解上述情况,用户可以手动将具有 `NoExecute` 或 `NoSchedule` 效果的 +`node.kubernetes.io/out-of-service` 污点添加到节点上,标记其无法提供服务。 +如果在 {{< glossary_tooltip text="kube-controller-manager" term_id="kube-controller-manager" >}} +上启用了 `NodeOutOfServiceVolumeDetach` +[特性门控](/zh-cn/docs/reference/command-line-tools-reference/feature-gates/), +并且节点被污点标记为无法提供服务,如果节点 Pod 上没有设置对应的容忍度, +那么这样的 Pod 将被强制删除,并且该在节点上被终止的 Pod 将立即进行卷分离操作。 +这样就允许那些在无法提供服务节点上的 Pod 能在其他节点上快速恢复。 + + +在非体面关闭期间,Pod 分两个阶段终止: + +1. 强制删除没有匹配的 `out-of-service` 容忍度的 Pod。 +2. 立即对此类 Pod 执行分离卷操作。 + +{{< note >}} + +- 在添加 `node.kubernetes.io/out-of-service` 污点之前, + 应该验证节点已经处于关闭或断电状态(而不是在重新启动中)。 +- 将 Pod 移动到新节点后,用户需要手动移除停止服务的污点, + 并且用户要检查关闭节点是否已恢复,因为该用户是最初添加污点的用户。 +{{< /note >}} + + +### 存储超时强制解除挂接 {#storage-force-detach-on-timeout} + +在任何情况下,当 Pod 未能在 6 分钟内删除成功,如果节点当时不健康, +Kubernetes 将强制解除挂接正在被卸载的卷。 +任何运行在使用了强制解除挂接卷的节点之上的工作负载, +都将违反 [CSI 规范](https://github.com/container-storage-interface/spec/blob/master/spec.md#controllerunpublishvolume), +该规范指出 `ControllerUnpublishVolume` +"**必须**在调用卷上的所有 `NodeUnstageVolume` 和 `NodeUnpublishVolume` 执行且成功后被调用"。 +在这种情况下,相关节点上的卷可能会遇到数据损坏。 + + +强制存储解除挂接行为是可选的;用户可以选择使用"非体面节点关闭"特性。 + + +可以通过在 `kube-controller-manager` 中设置 `disable-force-detach-on-timeout` +配置字段来禁用超时时存储强制解除挂接。 +禁用超时强制解除挂接特性意味着,托管在异常超过 6 分钟的节点上的卷将不会保留其关联的 +[VolumeAttachment](/zh-cn/docs/reference/kubernetes-api/config-and-storage-resources/volume-attachment-v1/)。 + + +应用此设置后,仍然关联卷到不健康 Pod 必须通过上述[非体面节点关闭](#non-graceful-node-shutdown)过程进行恢复。 + +{{< note >}} + +- 使用[非体面节点关闭](#non-graceful-node-shutdown)过程时必须小心。 +- 偏离上述步骤可能会导致数据损坏。 +{{< /note >}} + +## {{% heading "whatsnext" %}} + + +了解更多以下信息: + +- 博客:[非体面节点关闭](/zh-cn/blog/2023/08/16/kubernetes-1-28-non-graceful-node-shutdown-ga/)。 +- 集群架构:[节点](/zh-cn/docs/concepts/architecture/nodes/)。