A Kubernetes Job is a controller object designed to run a batch task to completion.
Unlike Deployments or ReplicaSets (which keep applications running indefinitely) or CronJobs (which trigger tasks on a schedule), a Job creates one or more Pods, executes the workload, and ensures they terminate cleanly. Once the specified number of Pods complete successfully, the Job itself is marked as complete and stops.
Standard Job Manifest
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration-job
spec:
backoffLimit: 4 # Number of retries before marking the job failed
completions: 1 # Number of successful pod completions required
parallelism: 1 # How many pods run concurrently
ttlSecondsAfterFinished: 600 # Clean up job & pods 10 minutes after completion
template:
spec:
containers:
- name: migration-task
image: python:3.11-slim
command: ["python", "-c", "print('Running database migration...'); import time; time.sleep(10); print('Done!')"]
restartPolicy: OnFailure # Required: OnFailure or Never (Always is invalid)
Core Execution Patterns
Kubernetes Jobs support three primary workload execution models:
- 1. Non-Parallel Jobs
- Behavior: Starts a single Pod and waits for it to complete successfully.
- Use Case: One-off database schema migrations, report generation, or administrative scripts.
- 2. Parallel Jobs with Fixed Completions
- Behavior: Runs multiple Pods in parallel until a total number of successful completions (spec.completions) is reached.
- Use Case: Batch processing where $N$ independent tasks need to be completed.
- 3. Parallel Jobs with Work Queue
- Behavior: Pods coordinate via an external message queue (e.g., RabbitMQ, Redis, SQS). Each Pod pulls work until the queue is empty, then exits.
- Use Case: High-throughput task processing, media transcoding, or distributed data transformation.
Key Configuration Fields
Field
- Default
- Description
restartPolicy
- Required
- Must be OnFailure (restarts container inside same Pod) or Never (spawns a new Pod on failure).
backoffLimit
- 6
- Maximum number of retries before marking the Job as failed.
completions
- 1
- Total number of successful Pod terminations needed for Job completion.
parallelism
- 1
- Max number of Pods allowed to run concurrently at any given moment.
activeDeadlineSeconds
- Unlimited
- Max time allowed for the entire Job (including retries) before terminating all running Pods.
completionMode
- NonIndexed
- Set to Indexed to assign each Pod a unique completion index ($0$ to $\text{completions}-1$) via environment variables.
ttlSecondsAfterFinished
- Disabled
- Automatically deletes the Job and its underlying Pods after $N$ seconds of finishing.
ttlSecondsAfterFinished is a field in a Kubernetes Job specification (spec.ttlSecondsAfterFinished) that controls the automatic cleanup of completed or failed Jobs and their associated Pods via the TTL-after-finished controller.
It is a good practice to set sensible ttlSecondsAfterFinished / history limits on Jobs / CronJobs so dead pods don't accumulate.
How It Works
- Automatic Cleanup: Once a Job reaches a terminal state (Complete or Failed), the TTL controller starts a clock using the completion timestamp. When the specified number of seconds elapses, the Job resource is deleted.
- Cascading Garbage Collection: Deleting the Job also automatically cleans up its dependent Pods.
- Immediate Deletion (0): Setting ttlSecondsAfterFinished: 0 makes the Job eligible for immediate removal upon completion or failure.
- Unset / Omitted: If left undefined or set to null, the Job and its Pods remain in the cluster indefinitely until manually deleted.
Manifest Example
apiVersion: batch/v1
kind: Job
metadata:
name: database-migration
spec:
ttlSecondsAfterFinished: 300 # Deletes Job and Pods 5 minutes after finishing
template:
spec:
containers:
- name: migration-runner
image: my-app-migrations:v1.2.0
command: ["npm", "run", "db:migrate"]
restartPolicy: Never
Key Considerations
- Clock Trigger: For successful Jobs, the timer counts down from .status.completionTime. For failed Jobs, it uses the transition timestamp of the Failed condition.
- Live Modifications: You can update or extend ttlSecondsAfterFinished while a Job is running or even after it finishes (as long as the original TTL hasn't already expired).
- Log Loss: Because Pods are destroyed during garbage collection, application logs will be lost unless forwarded to an external logging system (e.g., Loki, OpenSearch, Datadog).
Essential kubectl Commands
Operation Command
================== ===========
Create a Job imperatively kubectl create job my-job --image=busybox -- echo "Hello World"
Get Job status kubectl get jobs
Inspect job details kubectl describe job my-job
List Pods associated with Job kubectl get pods --selector=batch.kubernetes.io/job-name=my-job
View logs of Job Pods kubectl logs job/my-job
Delete Job and its Pods kubectl delete job my-job
Jobs vs Deployments vs CronJobs
┌─────────────────────────┐
│ Workload Type │
└────────────┬────────────┘
│
┌─────────────────────┴─────────────────────┐
▼ ▼
Long-Running Services Batch Tasks / One-Off
(Deployments, StatefulSets) (Jobs & CronJobs)
│ │
Maintains target Pod Executes task, then
count indefinitely. terminates cleanly.
│
┌────────────────┴────────────────┐
▼ ▼
Single Run Scheduled Run
(Job) (CronJob)
