Unlike Deployments and StatefulSets—which are designed to keep long-running processes alive indefinitely—Jobs and CronJobs are designed for run-to-completion batch tasks. When the workload process terminates with exit code 0, Kubernetes marks the Pod as
Completed.TL;DR (Quick Summary)#
- Job: Creates one or more Pods and ensures that a specified number of them successfully terminate (
completions). Supports parallel execution (parallelism). - CronJob: Manages time-based Jobs using standard 5-field cron syntax (
*/5 * * * *). - Restart Policy: Pods in a Job must set
restartPolicy: NeverorrestartPolicy: OnFailure(settingAlwaysis invalid). - Cleanup Policy: Set
ttlSecondsAfterFinishedto automatically garbage-collect completed Job pods.
1. Job vs CronJob Workflow#
graph TD
CJ["CronJob: db-backup-cronjob
Schedule: 0 2 * * * (Daily at 2 AM)"] -->|Triggers at 02:00| J["Job: db-backup-2891230"]
J -->|Spawns| Pod["Pod: db-backup-2891230-x8k9l"]
Pod -->|Executes pg_dump| Execution["PostgreSQL Backup Execution"]
Execution -->|Exit Code 0| Status["Pod Status: Completed
Job Status: Successful"]
2. Kubernetes Job Manifest (Batch Processing)#
Create job-db-migration.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: database-migration-job
namespace: default
spec:
completions: 1 # Total successful completions required
parallelism: 1 # Max parallel pods running concurrently
backoffLimit: 3 # Number of retries before marking Job failed
ttlSecondsAfterFinished: 300 # Auto-delete completed Pods after 5 mins
template:
spec:
containers:
- name: migration-runner
image: python:3.11-alpine
command:
- sh
- -c
- |
echo "Starting database schema migration..."
sleep 5
echo "Schema migration complete. Exit code 0."
resources:
requests:
cpu: "100m"
memory: "128Mi"
restartPolicy: OnFailureApply and inspect Job execution:
kubectl apply -f job-db-migration.yaml
kubectl get job database-migration-job --watchExpected Terminal Output:
NAME COMPLETIONS DURATION AGE
database-migration-job 0/1 2s 2s
database-migration-job 1/1 7s 7sCheck Pod completion status:
kubectl get pods -l job-name=database-migration-jobNAME READY STATUS RESTARTS AGE
database-migration-job-4k9lp 0/1 Completed 0 12s3. Kubernetes CronJob Manifest (Scheduled Backups)#
Create cronjob-backup.yaml:
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup-cronjob
namespace: default
spec:
schedule: "0 2 * * *" # Runs daily at 2:00 AM UTC
concurrencyPolicy: Forbid # Prevents overlapping jobs if previous run hangs
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
containers:
- name: backup-tool
image: alpine
command:
- sh
- -c
- "echo 'Running nightly automated backup snapshot...' && sleep 10"
restartPolicy: OnFailureApply manifest:
kubectl apply -f cronjob-backup.yamlManually Triggering a CronJob for Testing#
Instead of waiting until 2:00 AM to test your schedule, manually trigger an ad-hoc Job run from the CronJob definition:
kubectl create job --from=cronjob/nightly-backup-cronjob test-manual-backup-run4. Concurrency Policies Explained#
When a scheduled CronJob trigger fires while a previous Job execution is still running:
Allow(Default): Allows concurrent Jobs to run simultaneously.Forbid: Skips the new Job execution if the previous Job has not finished yet.Replace: Cancels the currently running Job execution and replaces it with the new Job execution.
5. Summary & Next Steps#
Jobs and CronJobs handle batch execution and scheduled tasks cleanly.
In Episode 12: Namespaces, Resource Quotas & LimitRanges, we will dive into multi-tenancy cluster administration, learning how to isolate teams and enforce CPU/Memory limits to prevent noisy-neighbor outages!

