Kubernetes v1.34: Job 的 Pod 替换策略进入 GA 阶段

在 Kubernetes v1.34 中,**Pod 替换策略(Pod replacement policy)** 特性已达到正式发布(GA)阶段。这篇博文将介绍 Pod 替换策略特性以及如何在你的 Job 中使用它。

关于 Pod 替换策略

默认情况下,Job 控制器会在 Pod 失败或开始终止(当它们具有删除时间戳时)时立即重新创建 Pod。

因此,在某些 Pod 正在终止时,一个 Job 的正在运行的 Pod 总数可能会暂时超过指定的并行度。对于 Indexed Job,这甚至可能意味着多个 Pod 同时为同一个索引运行。

这种行为对许多工作负载来说没有问题,但在某些情况下可能会导致问题。

例如,像 TensorFlow 和 JAX 这样流行的机器学习框架,期望每个工作程序索引(worker index)只有一个 Pod。如果两个 Pod 同时运行,你可能会遇到类似下面的错误:

/job:worker/task:4: Duplicate task registration with task_name=/job:worker/replica:0/task:4

此外,在旧 Pod 完全终止之前启动替换 Pod 可能会导致:

  • 由于节点仍被占用,kube-scheduler 会出现调度延迟。
  • 为了容纳替换的 Pod,集群会进行不必要的扩容。
  • Kueue 这样的工作负载编排器会暂时绕过配额检查。

有了 Pod 替换策略,Kubernetes 让你能够控制控制平面何时替换正在终止的 Pod,从而帮助你避免这些问题。

Pod 替换策略的工作原理

这项增强意味着 Kubernetes 中的 Job 有一个可选字段 .spec.podReplacementPolicy
你可以选择以下两种策略之一:

  • TerminatingOrFailed(默认):一旦 Pod 开始终止就替换它们。
  • Failed:仅在 Pod 完全终止并转换到 Failed 阶段后才替换它们。

将策略设置为 Failed 可以确保只有在前一个 Pod 完全终止后才会创建新的 Pod。

对于具有 Pod 失效策略(Pod Failure Policy)的 Job,默认的 podReplacementPolicyFailed,并且不允许其他值。要了解更多关于 Job 的 Pod 失效策略的信息,请参阅Pod 失效策略

你可以通过检查 Job 的 .status.terminating 字段来查看当前有多少 Pod 正在终止:

kubectl get job myjob -o=jsonpath='{.status.terminating}'

示例

下面是一个 Job 示例,它并行执行一个任务两次(spec.completions: 2),并行度为 2(spec.parallelism: 2),并且仅在 Pod 完全终止后才替换它们(spec.podReplacementPolicy: Failed):

apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  completions: 2
  parallelism: 2
  podReplacementPolicy: Failed
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: your-image

如果 Pod 收到 SIGTERM 信号(删除、驱逐、抢占...),它将开始终止。当容器优雅地处理终止时,清理工作可能需要一些时间。

当 Job 启动时,我们会看到两个 Pod 正在运行:

kubectl get pods

NAME                READY   STATUS    RESTARTS   AGE
example-job-qr8kf   1/1     Running   0          2s
example-job-stvb4   1/1     Running   0          2s

让我们删除其中一个 Pod(example-job-qr8kf)。

使用 TerminatingOrFailed 策略时,一旦一个 Pod(example-job-qr8kf)开始终止,Job 控制器会立即创建一个新的 Pod(example-job-b59zk)来替换它。

kubectl get pods

NAME                READY   STATUS        RESTARTS   AGE
example-job-b59zk   1/1     Running       0          1s
example-job-qr8kf   1/1     Terminating   0          17s
example-job-stvb4   1/1     Running       0          17s

使用 Failed 策略时,当旧 Pod(example-job-qr8kf)正在终止时,不会创建新的 Pod(example-job-b59zk)。

kubectl get pods

NAME                READY   STATUS        RESTARTS   AGE
example-job-qr8kf   1/1     Terminating   0          17s
example-job-stvb4   1/1     Running       0          17s

当正在终止的 Pod 完全转换到 Failed 阶段时,才会创建一个新的 Pod:

kubectl get pods

NAME                READY   STATUS        RESTARTS   AGE
example-job-b59zk   1/1     Running       0          1s
example-job-stvb4   1/1     Running       0          25s

如何了解更多?

致谢

与任何 Kubernetes 特性一样,许多人都为完成这项工作做出了贡献,从测试、提交错误到代码审查。

在这个特性经过 2 年的发展进入稳定阶段之际,我们想感谢以下人员:

参与其中

这项工作由 Kubernetes 批处理工作组(batch working group)赞助,并与 SIG Apps 社区密切合作。

如果你有兴趣在该领域开发新功能,我们建议你订阅我们的 Slack 频道并参加定期的社区会议。