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

介绍 Suspended Jobs

Job 是 Kubernetes API 的重要组成部分。虽然 DeploymentReplicaSetStatefulSetDaemonSet 等其他类型的工作负载解决了需要 Pod 永久运行的用例,但 Job 在 Pod 需要运行到完成时非常有用。Job 通常用于并行批处理,可用于各种应用,从视频渲染和数据库维护到发送批量电子邮件和科学计算。

虽然 Job 的并行度及完成条件可配置,但 Kubernetes API 缺乏暂停和恢复 Job 的能力。当集群资源有限,需要让更高优先级的 Job 顶替另一个 Job 执行时,通常会需要这个能力。删除低优先级 Job 是一个糟糕的权宜之计,因为 Pod 完成历史和与 Job 相关的其他指标都会丢失。

随着最近发布的 Kubernetes 1.21 版本,你将能够通过更新 Job 的 Spec 来暂停 Job。此功能目前处于 Alpha 阶段,使用它需要在 API servercontroller manager 上启用 SuspendJob feature gate

API 变更

我们在 Job 的 .spec 中引入了一个新的布尔字段 suspend。假设我创建以下 Job:

apiVersion: batch/v1
kind: Job
metadata:
  name: my-job
spec:
  suspend: true
  parallelism: 2
  completions: 10
  template:
    spec:
      containers:
      - name: my-container
        image: busybox
        command: ["sleep", "5"]
      restartPolicy: Never

Job 默认不会被暂停,因此我在上述 Job 清单的 .spec 中显式将 suspend 字段设置为 true。在上述示例中,Job Controller 将暂停创建 Pod,直到我准备好启动 Job,这可以通过将 suspend 更新为 false 来实现。

再举一个例子,考虑一个创建时省略 suspend 字段的 Job。Job Controller 会正常创建 Pod 来推进 Job 的完成。然而,在 Job 完成之前,如果我通过更新 Job 将该字段显式设置为 true,Job Controller 将终止所有正在运行的活动 Pod,并无限期等待该标志被重新设置为 false。通常,Pod 终止是通过向 Pod 中的所有容器进程发送 SIGTERM 信号来完成的;Pod spec 中定义的优雅终止周期将会被遵守。以这种方式终止的 Pod 不会被 Job Controller 计为失败。

需要注意的是,Job 暂停后,之前已经成功或失败的 Pod 会继续存在。也就是说,当你恢复 Job 后,它们仍然会计入 Job 的完成状态。你可以在暂停 Job 前后查看 Job 的 Status 来验证这一点。

阅读文档以全面了解此新功能。

这个功能在哪些场景有用?

假设我是一个大型集群的运维人员。有很多用户向集群提交 Job,但不是所有 Job 都同等重要——有些 Job 比其他 Job 更重要。集群资源也不是无限的,所以所有用户必须共享资源。如果所有 Job 都以暂停状态创建并放入待处理队列中,我可以通过按正确顺序恢复 Job 来实现基于优先级的 Job 调度。

另一个激励性用例是,考虑一个云提供商,其计算资源夜间比白天便宜。如果我有一个需要多天才能完成的长时间运行的 Job,每天早上暂停 Job,晚上再恢复它,可以降低成本。

由于此字段是 Job spec 的一部分,CronJob 也自动获得了这个功能。

参考资料和后续步骤

如果您有兴趣深入了解此功能背后的原理和我们做出的决策,请考虑阅读增强提案。在Job 的文档中有关于暂停和恢复 Job 的更多详细信息。

如前所述,此功能目前处于 Alpha 阶段,只有通过 SuspendJob feature gate 显式选择启用才能使用。如果您对此功能感兴趣,请考虑在您的集群中测试暂停的 Job 并提供反馈。您可以在 GitHub 上讨论此增强功能。SIG Apps 社区也定期举行会议,您可以通过 Slack 或邮件列表联系到他们。除非 API 发生意外变化,否则我们打算在 Kubernetes 1.22 版本中将此功能升级到 Beta 阶段,届时该功能将默认可用。