✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes Job Management

Kubernetes Job Management ensures reliable task execution through automated lifecycle management and orchestration within containerized environments.

Kubernetes Job Management is the set of controllers, API objects, and operational practices used to run finite, run-to-completion workloads on a Kubernetes cluster. Unlike a Deployment or a ReplicaSet, which are designed to keep a set of Pods running indefinitely, a Job is designed to run one or more Pods until a specified number of them terminate successfully. Job Management covers the lifecycle of these objects: creation, Pod scheduling, retry handling on failure, completion tracking, parallelism control, and cleanup.

The core API object is the batch/v1 Job. A Job creates one or more Pods and ensures that a target number of them complete successfully. When a Pod fails or is deleted before completion, the Job controller creates a new Pod to replace it, subject to a configurable backoff limit. When enough Pods finish successfully, the Job itself is marked Complete.


Core Concepts

Completions and Parallelism

Two fields control how much work a Job represents and how it is distributed:

  • .spec.completions defines how many successful Pod completions are required before the Job is considered done.
  • .spec.parallelism defines how many Pods may run concurrently while the Job is active.

Combining these fields produces three usage patterns:

  • Non-parallel Jobs: completions and parallelism are both left at their default of 1. A single Pod runs, and the Job is complete as soon as that Pod succeeds.
  • Parallel Jobs with a fixed completion count: completions is set to a value greater than 1, and parallelism controls concurrency. The controller keeps launching Pods until the total number of successful completions matches completions.
  • Parallel Jobs with a work queue: completions is left unset, and Pods coordinate among themselves (typically through an external queue) to decide when there is no more work left. The Job is complete once any one Pod exits successfully and no other Pods are running, or once all Pods exit.

Completion Mode

The .spec.completionMode field determines how the Job assigns identity to its Pods:

  • NonIndexed (default): Pods are not distinguished from one another; the Job is simply satisfied once completions successful Pods have finished.
  • Indexed: each Pod receives a completion index from 0 to completions - 1, exposed through the JOB_COMPLETION_INDEX environment variable and a Pod annotation. This mode is used for workloads that need to partition input data deterministically across Pods, such as batch data processing shards.

Backoff Limit and Failure Handling

The .spec.backoffLimit field caps the number of retries before a Job is marked Failed. Each time a Pod fails, the Job controller recreates it, applying an exponential backoff delay between attempts to avoid overwhelming the cluster with rapid restart loops. Once the number of failed Pods exceeds the backoff limit, the Job stops retrying and transitions to a terminal failed state.

For finer-grained control, .spec.podFailurePolicy allows a Job to react differently depending on the exit code or condition of a failed Pod — for example, treating an infrastructure-induced eviction as ignorable while treating an application exit code as a genuine failure that should count against the backoff limit.

Active Deadline and TTL Cleanup

  • .spec.activeDeadlineSeconds bounds the total wall-clock time a Job is allowed to run. If the deadline is exceeded, the Job and all of its Pods are terminated and the Job is marked Failed with reason DeadlineExceeded.
  • .spec.ttlSecondsAfterFinished enables automatic cleanup: once a Job reaches a terminal state, the TTL controller removes it, along with its Pods, after the configured number of seconds. This prevents clusters from accumulating large numbers of completed Job objects over time.

Job Patterns

CronJob-Driven Jobs

Jobs are frequently created on a recurring schedule through the batch/v1 CronJob resource, which wraps a Job template with a cron-formatted schedule. CronJob management introduces its own concerns:

  • .spec.concurrencyPolicy (Allow, Forbid, Replace) determines what happens if a previous run has not finished when the next scheduled time arrives.
  • .spec.successfulJobsHistoryLimit and .spec.failedJobsHistoryLimit bound how many completed Job objects are retained for inspection.
  • .spec.startingDeadlineSeconds bounds how late a missed schedule may still be honored before being skipped.

Indexed Jobs for Batch Sharding

Indexed Jobs are the standard pattern for parallel batch processing where each Pod must operate on a distinct partition of data. The completion index lets each Pod compute which shard, offset, or file range it owns without needing an external coordinator.

Suspended Jobs

Setting .spec.suspend: true allows a Job to be created without immediately scheduling Pods. This is used by queueing systems and batch schedulers (for example, Kueue) that admit Jobs onto the cluster only when sufficient resources are available, toggling suspend back to false once admission is granted.


Operational Practices

Monitoring Job State

Job status is tracked through .status.active, .status.succeeded, and .status.failed counters, as well as .status.conditions of type Complete, Failed, or Suspended. Operational tooling typically watches these fields rather than polling individual Pods, since the Job object is the authoritative summary of progress.

Resource Requests and Limits

Because Jobs frequently run batch or data-processing workloads with variable resource consumption, setting accurate CPU and memory requests and limits on the Pod template is essential for scheduler placement and for avoiding node-level resource contention with long-running Deployments.

Garbage Collection of Pods

By default, a Job's Pods are not deleted automatically when the Job succeeds; they remain for log inspection until the Job itself is deleted or its TTL expires. Operators managing large volumes of Jobs typically pair ttlSecondsAfterFinished with log aggregation so that Pod logs are captured externally before cleanup occurs.


Example Job Manifest

apiVersion: batch/v1
kind: Job
metadata:
  name: codartium-batch-import
spec:
  completions: 5
  parallelism: 2
  completionMode: Indexed
  backoffLimit: 4
  activeDeadlineSeconds: 600
  ttlSecondsAfterFinished: 3600
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: importer
          image: codartium/batch-importer:latest
          env:
            - name: JOB_COMPLETION_INDEX
              valueFrom:
                fieldRef:
                  fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
          resources:
            requests:
              cpu: "500m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
kubectl apply -f job.yaml
kubectl get jobs
kubectl describe job codartium-batch-import
kubectl logs -l job-name=codartium-batch-import