本文已发布超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

优雅节点关机进入 Beta 阶段

节点优雅关停,在 1.21 中进入 Beta,它使 kubelet 能够在节点关停期间优雅地驱逐 Pod。

Kubernetes 是一个分布式系统,因此我们需要为不可避免的故障做好准备 — 节点会发生故障,容器可能会崩溃或重启,理想情况下,你的工作负载应该能够承受这些灾难性事件。

常见的问题类别之一是节点关停或重启时的工作负载故障。在关闭节点之前,最佳实践是安全地排空并标记该节点。这将确保在该节点上运行的所有 Pod 都能安全地被驱逐。驱逐将确保你的 Pod 可以遵循预期的Pod 终止生命周期,这意味着你的容器将接收到 SIGTERM 信号和/或运行 preStopHooks

在 Kubernetes 1.20 之前(节点优雅关停作为 Alpha 特性引入),安全的节点排空并不容易:它需要用户手动操作并在事前排空节点。如果有人或某个东西在没有首先排空节点的情况下将其关闭,你的 Pod 很可能无法安全地从节点中被驱逐,并会突然关停。与这些 Pod 通信的其他服务可能会因为 Pod 突然退出而看到错误。这种情况的一些例子可能由于安全补丁导致的重启或短生命周期云计算实例的抢占引起。

Kubernetes 1.21 将节点优雅关停带入 Beta 阶段。节点优雅关停让你对一些意外关停情况有更多控制。启用节点优雅关停后,kubelet 会感知到底层系统关停事件,并将这些事件传播给 Pod,确保容器可以尽可能优雅地关停。这给了容器保存状态或释放所持资源的機會。

请注意,为了获得最佳可用性,即使启用了节点优雅关停,你仍应设计你的部署,使其能够容忍节点故障。

它是如何工作的?

在 Linux 上,你的系统可以在许多不同情况下关停。

  • 用户或脚本运行 shutdown -h nowsystemctl poweroffsystemctl reboot
  • 物理按下机器上的电源按钮。
  • 在云提供商上停止 VM 实例,例如在 GCP 上运行 gcloud compute instances stop
  • 你的云提供商可以意外终止的抢占式 VM 或 Spot 实例,但会发出简短警告。

其中许多情况可能是意外的,并且无法保证集群管理员在这些事件发生之前已排空节点。借助节点优雅关停功能,kubelet 使用名为“Inhibitor Locks”的 systemd 机制,以便在大多数情况下允许排空。使用 Inhibitor Locks,kubelet 会指示 systemd 将系统关停推迟一段指定的时间,从而为节点排空和驱逐系统上的 Pod 提供了机会。

Kubelet 利用此机制来确保你的 Pod 将干净地终止。当 kubelet 启动时,它会获取一个 systemd 延迟类型的抑制锁 (delay-type inhibitor lock)。当系统即将关停时,kubelet 可以利用其先前获取的延迟类型抑制锁,将关停延迟一段可配置的短暂时间。这为你的 Pod 提供了额外的终止时间。因此,即使在意外关停期间,你的应用也将接收到 SIGTERM,preStop hooks 将执行,并且 kubelet 会正确地将 Ready 节点状态和相应的 Pod 状态更新到 api-server。

例如,在一个启用了节点优雅关停的节点上,你可以看到 inhibitor lock 已被 kubelet 获取:

kubelet-node ~ # systemd-inhibit --list
    Who: kubelet (UID 0/root, PID 1515/kubelet)
    What: shutdown
    Why: Kubelet needs time to handle node shutdown
    Mode: delay

1 inhibitors listed.

在设计此功能时,我们考虑的一个重要因素是并非所有 Pod 都平等。例如,运行在节点上的一些 Pod,如与日志相关的 DaemonSet,应该尽可能长时间地运行,以便在关停期间捕获重要日志。因此,Pod 被分为两类:“常规”和“关键”。关键 Pod 是指 priorityClassName 设置为 system-cluster-criticalsystem-node-critical 的 Pod;所有其他 Pod 都被视为常规。

在我们的例子中,日志 DaemonSet 将作为关键 Pod 运行。在节点优雅关停期间,常规 Pod 首先终止,然后是关键 Pod。例如,这将允许与日志 DaemonSet 相关的关键 Pod 继续运行,并在常规 Pod 终止期间收集日志。

我们将在 Beta 阶段评估是否需要为不同的 Pod 优先级类提供更多灵活性,并在需要时添加支持,如果你有任何想法或场景,请告知我们。

如何使用它?

节点优雅关停由 GracefulNodeShutdown 特性门 控制,并在 Kubernetes 1.21 中默认启用。

你可以使用两个 kubelet 配置选项配置节点优雅关停行为:ShutdownGracePeriodShutdownGracePeriodCriticalPods。要配置这些选项,你需要编辑通过 --config 标志传递给 kubelet 的 kubelet 配置文件;更多详细信息请参阅通过配置文件设置 kubelet 参数

在关停期间,kubelet 分两个阶段终止 Pod。

  1. 终止在节点上运行的常规 Pod。
  2. 终止在节点上运行的关键 Pod。

控制关停持续时间的设置是:

  • ShutdownGracePeriod
    • 指定节点应延迟关停的总持续时间。这是常规 Pod 和关键 Pod 终止的总宽限期。
  • ShutdownGracePeriodCriticalPods
    • 指定节点关停期间用于终止关键 Pod 的持续时间。这应该小于 ShutdownGracePeriod

例如,如果 ShutdownGracePeriod=30s,并且 ShutdownGracePeriodCriticalPods=10s,kubelet 将延迟节点关停 30 秒。在此期间,前 20 秒 (30-10) 将保留用于优雅地终止常规 Pod,最后 10 秒将保留用于终止关键 Pod。

请注意,默认情况下,上述两个配置选项 ShutdownGracePeriodShutdownGracePeriodCriticalPods 都设置为零,因此你需要根据你的环境进行适当配置才能激活节点优雅关停功能。

如何了解更多?

如何参与?

随时欢迎你的反馈!SIG Node 定期召开会议,可通过Slack (频道 #sig-node) 或 SIG 的邮件列表联系。