发布人:开发技术推广工程师 Sandeep Dinesh
谈到分布式系统,故障处理是关键。Kubernetes 利用控制器来监控系统状态并重新启动已停止执行的服务,可有效解决这个问题。另一方面,Kubernetes 通常可以在系统正常运行过程中强制终止应用程序。
本期的"Kubernetes 最佳实践"系列视频中,我们来看看如何帮助 Kubernetes 更高效地完成工作并减少应用程序的停机时间。
多数应用程序都在虚拟机或物理机上运行。如果某个应用程序崩溃,启动替代程序需要很长时间。如果您只有一两台机器运行应用程序,这种恢复时间是不可接受的。
相比之下,较为常见的做法是通过进程级别的监控来重新启动崩溃的应用程序。如果应用程序崩溃,监控进程可以捕获退出代码并立即重新启动应用程序。
随着 Kubernetes 等系统的出现,已不再需要进程监控系统,因为 Kubernetes 自己会重新启动崩溃的应用程序。Kubernetes 使用事件循环来确保容器和节点等资源的健康状况。这意味着您不用再手动运行这些监控进程。如果某个资源未通过运行状况检查,Kubernetes 会自动启动替代资源。
Kubernetes 终止生命周期
Kubernetes 不仅仅可以监控应用程序崩溃,它还可以创建更多的应用程序副本以在多台机器上运行,更新应用程序,甚至同时运行多个版本的应用程序!
这意味着 Kubernetes 可以出于多种原因终止一个完全健康的容器。如果您通过滚动更新来更新部署,Kubernetes 会慢慢终止旧的 pod,同时加速生成新的 pod。如果您排空节点,Kubernetes 会终止该节点上的所有 pod。如果某个节点的资源耗尽,Kubernetes 会终止 pod 以释放这些资源(查看此前的这篇博文,详细了解资源)。
为了最大程度减小对最终用户的影响,并尽可能缩短恢复时间,应用程序能够正常终止十分重要。
实际上,这意味着您的应用程序需要处理 SIGTERM 消息,并在收到此类消息后开始关闭。这意味着要保存所有需要保存的数据、关闭网络连接、完成剩下的工作以及其他类似任务。
一旦 Kubernetes 决定终止 pod,将发生一系列事件。我们来看看 Kubernetes 终止生命周期的各个步骤。
1 - 将 pod 设置为“正在终止”状态,并将其从所有服务的端点列表中移除
此时,pod 停止获取新流量,Pod 中运行的容器不受影响。
2 - 执行 preStop 钩子
preStop 钩子是向 pod 中的容器发送的特殊命令或 http 请求。
如果您的应用程序在收到 SIGTERM 后未正常关闭,可使用此钩子触发正常关闭。大多数程序在收到 SIGTERM 后都会正常关闭,但如果您使用的是第三方代码或管理的系统不受您控制,preStop 钩子将是一个不错的方案,可帮您在不修改应用程序的情况下触发正常关闭。
3 - 向 pod 发送 SIGTERM 信号
此时,Kubernetes 将向 pod 中的容器发送 SIGTERM 信号。此信号通知容器它们即将被关闭。
您的代码应侦听此事件,并在此时开始“干净地”关闭。这可能包括停止所有长时间连接(如数据库连接或 WebSocket 流)、保存当前状态或类似任务。
即使您现在已经在使用 preStop 钩子,也有必要测试一下应用程序在您向它发送 SIGTERM 信号后的反应,以免在实际使用时对实际情况感到惊讶!
4 - Kubernetes 等待片刻(宽限期)
此时,Kubernetes 将等待片刻,此时间称为终止宽限期,具体值可指定。默认值为 30 秒。需要注意的是,这与 preStop 钩子和 SIGTERM 信号并行发生。Kubernetes 不会等待 preStop 钩子完成。
如果您的应用在 terminationGracePeriod 完成之前完成关闭并退出,Kubernetes 将立即转到下一步。
如果您的 pod 通常需要 30 秒以上的时间才能关闭,请务必延长宽限期。您可以通过在 Pod YAML
中设置 terminationGracePeriodSeconds 选项来实现此目的。例如,可将该值改为 60 秒:
5 - 向 pod 发送 SIGKILL 信号,pod 随即被移除
如果宽限期结束后容器仍在运行,将向容器发送 SIGKILL 信号并强制将它们移除。此时,所有 Kubernetes 对象将被一同清理。
结论
Kubernetes 可以出于各种原因终止 pod,确保您的应用程序正常执行这些终止操作是创建稳定系统和提供良好用户体验的核心。
推荐阅读: