bigywater.tech
Kubernetes · 54

Job:backoffLimit、并行度与完成数

Job 怎么控制并行度?失败了会重试几次、多久重试一次?Pod 会不会被留下来?这篇用同一个 busybox 容器,把 completions、parallelism、backoffLimit、两种 restartPolicy、deadline、suspend 和 TTL 都实测了一遍。

0 / 10 / 30 秒
backoffLimit=2、restartPolicy: Never 时三个 Pod 的创建时刻(10 秒、20 秒的指数退避)
18 秒
completions=6、parallelism=2、每个 Pod 3 秒时 Job 从开始到完成的时间(3 批)
7.8 秒
ttlSecondsAfterFinished=8 的 Job 在 Complete 之后被自动删除的时间

并行与分批

实测 · 本机执行输出
  (active, succeeded) 的变化:(2, 0)@0.1s → (2, 2)@6.0s → (2, 4)@12.0s → (0, 6)@18.0s
  最多同时 2 个 Pod 在跑;总共 6 个 Pod;conditions=[('SuccessCriteriaMet', 'True'), ('Complete', 'True')];startTime→completionTime 用了 18 秒
  completionMode: Indexed(4 个):idx-0-4qgz2→index 注解 0、日志「我是第 0 个」; idx-1-rvd82→index 注解 1、日志「我是第 1 个」; idx-2-s9xvr→index 注解 2、日志「我是第 2 个」 …

completions: 6、parallelism: 2,每个 Pod 睡 3 秒:active 始终是 2,succeeded 以 2 为步长涨到 6,3 批共 18 秒(每批还包含调度与启动的开销)。completionMode: Indexed 给每个 Pod 一个序号(注解 batch.kubernetes.io/job-completion-index,环境变量 JOB_COMPLETION_INDEX),分片处理数据时很方便。

失败与重试

实测 · 本机执行输出
  fail-never(backoffLimit 2,restartPolicy: Never):每次失败都新建一个 Pod:共 3 个 Pod,创建时刻(相对第一个)[0, 10, 30] 秒(间隔 10 秒、20 秒的指数退避);status.failed=3;33 秒时 Failed:reason=BackoffLimitExceeded message=Job has reached the specified backoff limit
  fail-onfail(backoffLimit 2,restartPolicy: OnFailure):始终只有 1 个 Pod,容器在原地重启,轮询到的最大 restartCount=2;15 秒时 Failed:reason=BackoffLimitExceeded;失败后 Pod 数 0(Job 失败时把 Pod 删除了);status.failed=1

backoffLimit: 2 的 Job 总是 exit 1。restartPolicy: Never:每次失败都新建一个 Pod,创建时刻 0、10、30 秒(退避 10 秒、20 秒),共 3 个 Pod 全部保留,方便逐个看日志,33 秒后 Job Failed,reason: BackoffLimitExceeded。restartPolicy: OnFailure:始终是同一个 Pod,容器在原地重启,重启次数也计入 backoffLimit(restartCount 到 2),15 秒后 Job 同样失败,并且 Job 失败时把这个 Pod 删掉了——想留日志就用 Never。

时间上限

实测 · 本机执行输出
  activeDeadlineSeconds=8、容器 sleep 60:8.8 秒后 Job 条件 Failed reason=DeadlineExceeded message=Job was active longer than specified deadline;active=0;Pod:(已被删除)

activeDeadlineSeconds: 8、容器 sleep 60:8.8 秒后 Job 失败,reason: DeadlineExceeded,还在运行的 Pod 被终止并删除。它限制的是整个 Job 的存活时间,无论重试了几次。

暂停与自动清理

实测 · 本机执行输出
  suspend: true 创建 4 秒后:Pod 数 0;conditions=[('Suspended', 'True', 'JobSuspended')]
  取消暂停之后 4.8 秒 Job Complete;Pod 数 1
  ttlSecondsAfterFinished=8:Complete 之后 7.8 秒 Job 与它的 Pod 被自动删除:Job 已删除;剩余 Pod 0 个

suspend: true 的 Job 创建后不产生任何 Pod,条件 Suspended;改成 false 之后 4.8 秒就跑完了。ttlSecondsAfterFinished: 8 让 Job 完成 7.8 秒后连同 Pod 被自动删除;不设的话 Job 和 Pod 会一直留着,日积月累就是对象泄漏。

分步演示

Job 的行为
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0);Job 的容器是 busybox:1.36;(active, succeeded) 每 0.2 秒取自 Job status;第 2 节每秒轮询 Job 与 Pod,创建时刻取自 Pod 的 creationTimestamp(只有 Never 的 Job 在失败后仍留着 Pod),OnFailure 的 restartCount 取轮询中见到的最大值;每种情形各一次(时间每次运行不同,例如第一次运行 OnFailure 的 Job 在 15 秒、Never 的在 33 秒失败,与本文一致)
    • 没有验证:podFailurePolicy(按退出码决定是否重试);backoffLimitPerIndex;successPolicy;Job 的 Pod 被节点驱逐时是否计入 backoffLimit;maxFailedIndexes;managedBy;长任务下 backoff 的上限(6 分钟);kubectl wait --for=condition=complete 的用法;并行度大时对 apiserver 的压力
    京ICP备2026067502号-1京公网安备11010502063487号