Kubernetes Jobs and CronJobs for batch workloads
Ryan Nakamura
Feb 2026
1 tab
# === One-off Job: Database migration ===
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: production
spec:
ttlSecondsAfterFinished: 3600 # Auto-cleanup after 1 hour
backoffLimit: 3 # Retry up to 3 times on failure
activeDeadlineSeconds: 600 # Timeout after 10 minutes
template:
metadata:
labels:
app: db-migrate
spec:
restartPolicy: Never # Don't restart — let Job controller handle retries
serviceAccountName: migration-runner
containers:
- name: migrate
image: myapp:latest
command: ["rails", "db:migrate"]
envFrom:
- secretRef:
name: database-credentials
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
---
# === Parallel Job: Process items in batch ===
apiVersion: batch/v1
kind: Job
metadata:
name: batch-processor
namespace: production
spec:
completions: 10 # Total items to process
parallelism: 3 # Run 3 pods at a time
backoffLimit: 5
template:
spec:
restartPolicy: Never
containers:
- name: processor
image: myapp-worker:latest
command: ["python", "process_batch.py"]
env:
- name: BATCH_SIZE
value: "100"
- name: JOB_COMPLETION_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
---
# === CronJob: Nightly database backup ===
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
namespace: production
spec:
schedule: "0 2 * * *" # Daily at 2:00 AM UTC
timeZone: "America/New_York" # K8s 1.27+
concurrencyPolicy: Forbid # Don't run if previous is still running
successfulJobsHistoryLimit: 7 # Keep last 7 successful runs
failedJobsHistoryLimit: 3 # Keep last 3 failed runs
startingDeadlineSeconds: 300 # Skip if missed by > 5 min
jobTemplate:
spec:
ttlSecondsAfterFinished: 86400
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
containers:
- name: backup
image: postgres:16-alpine
command:
- /bin/sh
- -c
- |
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
FILENAME="backup-${TIMESTAMP}.sql.gz"
echo "Starting backup: ${FILENAME}"
pg_dump "$DATABASE_URL" | gzip > "/backups/${FILENAME}"
echo "Backup complete: $(ls -lh /backups/${FILENAME})"
# Prune backups older than 30 days
find /backups -name "backup-*.sql.gz" -mtime +30 -delete
envFrom:
- secretRef:
name: database-credentials
volumeMounts:
- name: backup-storage
mountPath: /backups
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 2Gi
---
# === CronJob: Cache warm-up every 5 minutes ===
apiVersion: batch/v1
kind: CronJob
metadata:
name: cache-warmer
namespace: production
spec:
schedule: "*/5 * * * *"
concurrencyPolicy: Replace # Kill old one if new one starts
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
ttlSecondsAfterFinished: 300
template:
spec:
restartPolicy: Never
containers:
- name: warmer
image: curlimages/curl:latest
command:
- /bin/sh
- -c
- |
for endpoint in /api/popular /api/categories /api/featured; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://api-service:3000${endpoint}")
echo "Warmed ${endpoint}: HTTP ${STATUS}"
done
1 file · yaml
Explain with highlit
Run one-off tasks and scheduled batch processing in Kubernetes with Job and CronJob resources. Configure parallelism, backoff limits, completion counts, and cron schedules. Handle cleanup policies and monitor job history for reliable batch operations.