Kubernetes CronJobs bring the power of Linux cron scheduling to containerized environments. They're the go-to solution for running batch jobs, database backups, report generation, and other periodic tasks in your cluster.
This guide covers everything from basic cron job examples to advanced configuration options for production Kubernetes environments.
What is a Kubernetes CronJob?
A CronJob creates Kubernetes Jobs on a repeating schedule. Each Job spawns one or more Pods to run your task, and Kubernetes handles the lifecycle management including retries, cleanup, and concurrency control.
Think of it as Linux cronjobs, but for containers:
- Uses the same cron expression syntax as Linux crontab
- Runs in isolated containers with defined resources
- Includes built-in history management and failure handling
Basic CronJob Structure
Here's a minimal Kubernetes CronJob example:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cron
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
command:
- /bin/sh
- -c
- echo "Hello from Kubernetes CronJob at $(date)"
restartPolicy: OnFailure
This CronJob runs every 5 minutes, printing a timestamped message.
Cron Expression Syntax
Kubernetes CronJobs use the standard 5-field cron format identical to Linux cronjobs:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * *
Use our Cron Generator to build and validate your schedules before deploying.
Common Cron Job Examples for Kubernetes
| Expression | Schedule |
|---|---|
*/5 * * * * |
Every 5 minutes |
0 * * * * |
Every hour |
0 0 * * * |
Daily at midnight |
0 9 * * 1-5 |
Weekdays at 9 AM |
0 2 * * * |
Daily at 2 AM |
0 0 1 * * |
First day of month |
Real-World Kubernetes CronJob Examples
Daily Database Backup
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:15
command:
- /bin/sh
- -c
- |
pg_dump $DATABASE_URL > /backup/db-$(date +%Y%m%d-%H%M%S).sql
echo "Backup completed at $(date)"
envFrom:
- secretRef:
name: database-credentials
volumeMounts:
- name: backup-storage
mountPath: /backup
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure
This cron job example:
- Runs at 2 AM daily
- Prevents concurrent runs with
concurrencyPolicy: Forbid - Keeps 7 successful and 3 failed job records
- Sets resource limits to prevent runaway containers
Weekly Cleanup Job
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-old-files
spec:
schedule: "0 3 * * 0"
jobTemplate:
spec:
activeDeadlineSeconds: 3600
template:
spec:
containers:
- name: cleanup
image: alpine
command:
- /bin/sh
- -c
- |
echo "Starting cleanup at $(date)"
find /data -type f -mtime +30 -delete
echo "Cleanup completed at $(date)"
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: app-data-pvc
restartPolicy: OnFailure
Runs every Sunday at 3 AM, deleting files older than 30 days.
Hourly Health Check with Notification
apiVersion: batch/v1
kind: CronJob
metadata:
name: health-check
spec:
schedule: "0 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: checker
image: curlimages/curl:latest
command:
- /bin/sh
- -c
- |
if curl -sf https://api.example.com/health; then
echo "Health check passed"
curl -X POST https://hooks.slack.com/services/xxx -d '{"text":"✅ API healthy"}'
else
echo "Health check failed!"
curl -X POST https://hooks.slack.com/services/xxx -d '{"text":"❌ API down!"}'
exit 1
fi
restartPolicy: Never
Important Configuration Options
Concurrency Policy
Control what happens when a new Job is scheduled while the previous one is still running:
spec:
concurrencyPolicy: Forbid # Skip if previous still running
# concurrencyPolicy: Allow # Run concurrent jobs (default)
# concurrencyPolicy: Replace # Stop old job, start new one
Recommendation: Use Forbid for most cron jobs to prevent resource exhaustion and duplicate processing.
History Limits
Control how many completed and failed Jobs to retain:
spec:
successfulJobsHistoryLimit: 3 # Keep last 3 successful jobs
failedJobsHistoryLimit: 1 # Keep last 1 failed job
Lower limits save cluster resources; higher limits aid debugging.
Starting Deadline
If a Job misses its scheduled time (cluster downtime, etc.), how long to wait before giving up:
spec:
startingDeadlineSeconds: 300 # 5 minutes
Without this, Kubernetes may try to "catch up" on all missed runs.
Active Deadline
Maximum time a Job can run before being terminated:
spec:
jobTemplate:
spec:
activeDeadlineSeconds: 3600 # 1 hour max
Essential for preventing runaway containers.
Suspend
Temporarily pause the CronJob without deleting it:
spec:
suspend: true
Useful during maintenance or debugging.
Troubleshooting Kubernetes CronJobs
CronJob Not Running
1. Check if CronJob is suspended:
kubectl get cronjob my-cronjob -o jsonpath='{.spec.suspend}'
2. Verify the cron expression is correct:
Use our Cron Expression Translator to validate your schedule.
3. Check for quota issues:
kubectl describe cronjob my-cronjob
Look for events mentioning quota exceeded or resource limits.
4. Check the kube-controller-manager timezone:
CronJobs use the timezone of the Kubernetes controller manager, not your local timezone. Most clusters run in UTC.
Viewing Job Logs
# List jobs created by a CronJob
kubectl get jobs -l job-name=my-cronjob
# Get logs from the most recent job
kubectl logs job/my-cronjob-1234567890
# Follow logs in real-time
kubectl logs -f job/my-cronjob-1234567890
Checking Job History
# List all jobs sorted by creation time
kubectl get jobs --sort-by=.metadata.creationTimestamp
# Get details on failed jobs
kubectl describe job my-cronjob-1234567890
Kubernetes CronJob Best Practices
-
Set resource limits - Prevent runaway containers from consuming cluster resources
-
Use appropriate restartPolicy:
OnFailure- Retries in the same Pod (good for transient failures)Never- Creates new Pods for retries (good for debugging)
-
Configure deadlines - Set
activeDeadlineSecondsto prevent infinite loops -
Monitor execution - Use Prometheus metrics or send heartbeats to monitoring services like Healthchecks.io
-
Handle time zones - Remember that CronJobs use the kube-controller-manager's timezone (usually UTC)
-
Use Forbid concurrency - Prevent overlapping job runs for most use cases
-
Keep history limits low - Reduce cluster resource consumption
-
Test expressions before deploying - Use our Cron Generator to validate
Essential kubectl Commands for CronJobs
| Command | Description |
|---|---|
kubectl get cronjobs |
List all CronJobs |
kubectl describe cronjob NAME |
Detailed CronJob info |
kubectl get jobs |
List all Jobs (including from CronJobs) |
kubectl logs job/NAME |
View Job logs |
kubectl delete cronjob NAME |
Delete CronJob |
kubectl create job --from=cronjob/NAME test-job |
Manually trigger a CronJob |
Migrating from Linux Cronjobs
If you're moving from traditional Linux cron to Kubernetes:
| Linux Crontab | Kubernetes CronJob |
|---|---|
crontab -e |
kubectl edit cronjob |
crontab -l |
kubectl get cronjobs |
grep CRON /var/log/syslog |
kubectl logs job/NAME |
| Script on filesystem | Container image |
| Environment in crontab | ConfigMaps/Secrets |
The cron expression syntax is identical any expression that works in Linux crontab works in Kubernetes.
Conclusion
Kubernetes CronJobs provide a robust, containerized way to run scheduled tasks. With proper configuration for concurrency, history limits, and deadlines, they can reliably handle your periodic workloads at scale.
Key takeaways:
- Same cron syntax as Linux cronjobs
- Use
concurrencyPolicy: Forbidto prevent overlaps - Set
activeDeadlineSecondsto limit runtime - Monitor with health check endpoints
- Remember timezones (usually UTC)
Need help creating cron schedules? Use our Cron Generator to build, validate, and test expressions before deploying to your cluster!