Kubernetes CronJob Guide: Scheduling Tasks in K8s
Kubernetes CronJob runs scheduled tasks as batch jobs in your cluster. This guide covers the full spec, concurrency control, timezone support, history management, and how to debug jobs that fail silently.
Minimal CronJob Example
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 2 * * *" # 2:00 AM UTC every day
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: my-backup-image:latest
command: ["/scripts/backup.sh"]
restartPolicy: OnFailure# Apply and verify
kubectl apply -f cronjob.yaml kubectl get cronjobs kubectl describe cronjob db-backup
Key Spec Fields
| Field | Req? | Description |
|---|---|---|
| schedule | Required | Standard 5-field cron expression (UTC by default) |
| timeZone | Optional | IANA timezone name (e.g. America/New_York). Kubernetes 1.27+ only. |
| concurrencyPolicy | Optional | Allow, Forbid, or Replace. Controls what happens if the previous job is still running when the next fires. |
| successfulJobsHistoryLimit | Optional | Number of completed job records to keep. Default: 3. Set to 0 to delete immediately. |
| failedJobsHistoryLimit | Optional | Number of failed job records to keep. Default: 1. |
| startingDeadlineSeconds | Optional | If the job misses its schedule by more than this many seconds, skip it. Useful for time-sensitive jobs. |
| suspend | Optional | Set to true to temporarily pause the CronJob without deleting it. |
concurrencyPolicy: Allow vs Forbid vs Replace
Multiple job instances can run simultaneously. Default. OK for idempotent jobs.
If a job is still running when the next fires, skip the new one. Use for jobs that must not overlap.
⚠ Can cause missed runs under high load.
If a job is still running, terminate it and start a fresh one. Use when fresh state is more important than completion.
⚠ Previous job is terminated abruptly.
Production-Ready Example
apiVersion: batch/v1
kind: CronJob
metadata:
name: weekly-report
namespace: production
spec:
schedule: "0 9 * * 1" # Every Monday 9:00 AM
timeZone: "America/New_York" # K8s 1.27+ only
concurrencyPolicy: Forbid # Don't overlap runs
successfulJobsHistoryLimit: 3 # Keep last 3 successful jobs
failedJobsHistoryLimit: 1 # Keep last 1 failed job
startingDeadlineSeconds: 300 # Skip if 5+ min late
jobTemplate:
spec:
backoffLimit: 2 # Retry up to 2 times
activeDeadlineSeconds: 600 # Kill job after 10 min
template:
spec:
restartPolicy: OnFailure
serviceAccountName: report-runner
containers:
- name: report
image: my-report-image:1.2.3
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: urlDebugging CronJob Failures
kubectl get cronjobs
List all CronJobs and their last schedule time
kubectl get jobs --selector=job-name=<name>
Find Jobs created by a specific CronJob
kubectl describe cronjob <name>
Check events — including missed/failed runs
kubectl logs -l job-name=<job-name>
Get logs from the Job's pod(s)
kubectl get pods --selector=job-name=<job-name>
List pods for a specific Job
kubectl describe pod <pod-name>
Debug pod-level issues (image pull, OOM, etc.)
Build your Kubernetes CronJob schedule
Use our platform guide and visual builder to create and validate Kubernetes-compatible cron expressions.