Kubernetes v1.35: 通过就地重启 Pod 实现更高的效率
Kubernetes 1.35 版本引入了一项强大的新特性,满足了用户对 Pod 就地重启的迫切需求。
这项名为“重启所有容器”(Restart All Containers,1.35 版本为 Alpha 版)的特性,
相比于资源用量较高的删除并重建整个 Pod 的方式,能够更高效地重置 Pod 的状态。
该特性对于 AI/ML 工作负载尤为实用,使应用程序开发人员能够专注于核心训练逻辑,
同时将复杂的故障处理和恢复机制交给边车容器和声明式 Kubernetes 配置来处理。
凭借 RestartAllContainers 和其他计划中的增强特性,
Kubernetes 将继续构建更灵活、更健壮、更高效的 AI/ML 工作负载平台。
启用 RestartAllContainersOnContainerExits 特性门控即可使用此新特性。
此 Alpha 特性扩展了容器重启规则特性,
该特性在 Kubernetes 1.35 中升级为 Beta 版。
问题:当单个容器重启不足以解决问题,而重新创建 Pod 成本过高时
Kubernetes 长期以来一直支持 Pod 级别的重启策略(restartPolicy),
最近也支持单个容器级别的重启策略。
这些策略非常适合处理单个独立进程中的崩溃。然而,许多现代应用程序具有更复杂的容器间依赖关系。例如:
- 初始化容器通过挂载卷或生成配置文件来准备环境。如果主应用程序容器损坏了此环境, 仅仅重启该容器是不够的,需要重新运行整个初始化过程。
- 监视边车监控系统健康状况。如果它检测到不可恢复但可重试的错误状态,则必须触发主应用程序容器从头开始重启。
- 管理远程资源的边车发生故障。即使边车自行重启,主容器也可能因为尝试访问过时或损坏的连接而卡住。
在所有这些情况下,我们期望的操作并非重启单个容器,而是重启所有容器。 此前,实现此目的的唯一方法是删除 Pod,然后由控制器(例如 Job 或 ReplicaSet)创建一个新的 Pod。 这个过程缓慢且成本高昂,涉及调度器、节点资源分配以及网络和存储的重新初始化。
在处理大规模 AI/ML 工作负载(≥ 1000 个节点,每个节点一个 Pod)时,这种低效性会更加严重。 这些同步工作负载的一个常见要求是,当发生故障(例如节点崩溃)时, 必须重新创建集群中的所有 Pod 以重置状态,然后才能恢复训练, 即使其他 Pod 并未直接受到故障的影响。 同时删除、创建和调度数千个 Pod 会造成巨大的瓶颈。 此次故障造成的损失估计每月可能高达 10 万美元(资源浪费)。
处理 AI/ML 训练任务的这些故障需要复杂的集成,涉及训练框架和 Kubernetes, 而这两者通常都很脆弱且繁琐。 此特性引入了一种 Kubernetes 原生解决方案, 提高了系统健壮性,并使应用程序开发人员能够专注于其核心训练逻辑。
就地重启 Pod 的另一个主要优势在于,将 Pod 保留在其分配的节点上可以进行进一步的优化。 例如,可以实现与特定 Pod 标识绑定的节点级缓存, 而当 Pod 不必要地在不同的节点上重新创建时,这种优化方式是无法实现的。
引入 RestartAllContainers 操作
为了解决这个问题,Kubernetes v1.35 在容器重启规则中添加了一个新的操作:RestartAllContainers。
当容器以符合此操作规则的方式退出时,kubelet 会启动对 Pod 的快速就地重启。
这种就地重启非常高效,因为它保留了 Pod 最重要的资源:
- Pod 的 UID、IP 地址和网络命名空间。
- Pod 的沙箱及其所有连接的设备。
- 所有卷,包括
emptyDir和从 PVC 挂载的卷。
终止所有正在运行的容器后,Pod 的启动序列将从头开始重新执行。 这意味着所有初始化容器将按顺序再次运行,随后是边车容器和常规容器, 从而确保在已知良好的环境中完全重新启动。 除了临时容器(会被终止)之外,所有其他容器——包括之前成功或失败的容器——都将重新启动, 而不管它们各自的重启策略如何。
应用案例
1. 高效重启机器学习/批处理作业
对于机器学习训练作业, 在工作节点 Pod 发生故障时重新调度是一项代价高昂的操作, 会浪费宝贵的计算资源。 在一个拥有 1000 个节点的训练集群中, 重新调度带来的开销每月可能会浪费超过 10 万美元的计算资源。
借助 RestartAllContainers 操作,你可以启用一种速度更快、混合的恢复策略来解决这个问题:
仅重新创建“故障”Pod(例如,位于不健康节点上的 Pod),同时对其余健康的 Pod
触发 RestartAllContainers 操作。基准测试表明,这可以将恢复开销从几分钟降低到几秒钟。
通过就地重启,监视器边车可以监控主训练过程。如果遇到特定的可重试错误, 监视器可以退出并返回指定的代码,从而触发工作 Pod 的快速重置, 使其能够从上一个检查点重新启动,而无需 Job 控制器的参与。Kubernetes 现在原生支持此特性。
有关未来开发和 JobSet 特性的更多详细信息,请参阅 KEP-467 JobSet 就地重启。
apiVersion: v1
kind: Pod
metadata:
name: ml-worker-pod
spec:
restartPolicy: Never
initContainers:
# 此初始化容器将在每次就地重启时重新运行。
- name: setup-environment
image: my-repo/setup-worker:1.0
- name: watcher-sidecar
image: my-repo/watcher:1.0
restartPolicy: Always
restartPolicyRules:
- action: RestartAllContainers
onExit:
exitCodes:
operator: In
# 监视器返回特定退出代码会触发 Pod 完全重启。
values: [88]
containers:
- name: main-application
image: my-repo/training-app:1.0
2. 重新运行初始化容器以确保干净状态
设想这样一种场景:初始化容器负责获取凭据或设置共享卷。 如果主应用程序发生故障,导致共享状态损坏,则需要重新运行初始化容器。
通过配置主应用程序在检测到此类损坏时以特定代码退出,你可以触发 RestartAllContainers
操作,从而确保初始化容器在应用程序重启之前提供一个干净的设置。
3. 处理高频率的类似任务执行
有些情况下,任务最好以 Pod 执行的形式呈现。每个任务都需要干净利落地执行。例如,游戏会话后端或队列项处理。 如果任务频率很高,运行完整的 Pod 创建、调度和初始化流程会非常耗费资源, 尤其是在任务执行时间可能很短的情况下。 Kubernetes 原生支持从头开始重启所有容器,无需自定义解决方案或框架即可处理这种情况。
使用方法
要试用此特性,你必须在运行 Kubernetes v1.35 或更高版本的 Kubernetes
集群组件(API 服务器和 kubelet)上启用 RestartAllContainersOnContainerExits 特性门控。
此 Alpha 特性扩展了 ContainerRestartRules 特性,后者已在 v1.35 版本中升级为 beta 版,并默认启用。
启用后,你可以将 restartPolicyRules 添加到任何容器(Init、边车或常规容器),
并使用 RestartAllContainers 操作。
该特性旨在方便现有应用程序使用。但是,如果应用程序不遵循某些最佳实践,
则可能会导致应用程序本身或可观测性工具出现问题。
启用此特性时,请确保所有容器都是可重入的,并且外部工具已准备好用于重新启动初始化容器。
此外,重启所有容器时,kubelet 不会运行 preStop 钩子。
这意味着容器必须设计为能够处理突然终止的情况,而无需依赖 preStop 钩子来实现优雅关闭。
观察重启
为了使重启过程可观察,Pod 的状态中添加了一个新的条件 AllContainersRestarting。
当触发重启时,此条件变为 True;当所有容器终止且 Pod 准备好重新开始其生命周期时,
此条件变为 False。这为用户和其他集群组件提供了关于 Pod 状态的清晰信号。
所有通过此操作重启的容器,其容器状态中的重启计数都会递增。
了解更多
- 阅读 Pod 生命周期的官方文档。
- 阅读 KEP-5532:容器退出时重启所有容器中的详细提案。
- 阅读 JobSet issue #467 中关于 JobSet 就地重启的提案。
我们期待你的反馈!
作为一项 Alpha 特性,RestartAllContainers 现已开放试用,
欢迎你提出任何使用案例和反馈意见。
此特性由 SIG Node 社区驱动。
如果你有兴趣参与、分享想法或做出贡献,请加入我们!
你可以通过以下方式联系 SIG Node: