Kubernetes CronJobs: Schedule Tasks Automatically
Schedule recurring tasks with a CronJob, understand the CronJob to Job to Pod chain, write cron expressions, set a time zone, and control history and overlapping runs.
A Job runs a task once until it succeeds. Many tasks are not one-time: back up the database every night, delete temporary files every day, email a sales report every Monday at 9 AM. Nobody wants to run kubectl apply at midnight.
A CronJob creates Jobs automatically on a schedule. It works like cron on Linux, but inside the cluster.
The execution chain
This is the most important thing to remember:
CronJob -> creates a Job (on each schedule tick) -> the Job creates Pod(s) -> the Pod does the task and exitsA CronJob never creates pods directly. It creates a Job from its jobTemplate, and everything you learned about Jobs (completions, parallelism, retries) applies to each run.
Cron expressions in two minutes
A schedule has five fields:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * *| Schedule | Meaning |
|---|---|
*/1 * * * * (same as * * * * *) | Every minute |
*/15 * * * * | Every 15 minutes |
0 2 * * * | Every day at 02:00 |
0 9 * * 1 | Every Monday at 09:00 |
0 0 1 * * | At midnight on the first day of every month |
@daily, @hourly, @weekly | Shortcuts that Kubernetes also accepts |
crontab.guru is handy for checking an expression before you use it.
Step 1: The CronJob
vi cron-job.ymlapiVersion: batch/v1
kind: CronJob
metadata:
name: telusko-cronjob
spec:
schedule: "*/1 * * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: busybox-container
image: busybox
command:
- sh
- -c
- echo "Hello from Telusko CronJob"
restartPolicy: Never| Field | Meaning |
|---|---|
kind: CronJob, apiVersion: batch/v1 | Same API group as Job |
schedule: "*/1 * * * *" | Run every minute. Always quote it, because * has a special meaning in YAML |
successfulJobsHistoryLimit: 3 | Keep only the last 3 successful Jobs (and their pods) for reading logs. Older ones are deleted. The default is 3 |
failedJobsHistoryLimit: 1 | Keep only the most recent failed Job for troubleshooting. The default is 1 |
jobTemplate.spec | A full Job spec. Here a single pod per run |
restartPolicy: Never | As with Jobs: on failure, a new pod is created instead of restarting the container |
kubectl apply -f cron-job.yml
kubectl get cronjobsNAME SCHEDULE TIMEZONE SUSPEND ACTIVE LAST SCHEDULE AGE
telusko-cronjob */1 * * * * <none> False 0 <none> 10skubectl get pods shows nothing yet. The first run happens at the start of the next minute. Wait a minute or two:
kubectl get pods
kubectl get jobsNAME STATUS COMPLETIONS DURATION AGE
telusko-cronjob-29812345 Complete 1/1 4s 2m
telusko-cronjob-29812346 Complete 1/1 4s 61s
telusko-cronjob-29812347 Complete 1/1 3s 1sA new Job every minute, each named telusko-cronjob-<number>. The number is based on the scheduled time (in minutes), so names never collide. After the fourth run you will see only 3 Jobs, because of successfulJobsHistoryLimit: 3.
kubectl logs <one-of-the-pod-names>Hello from Telusko CronJobStep 2: Settings you will want in real CronJobs
spec:
schedule: "0 2 * * *"
timeZone: "Asia/Kolkata"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 300
suspend: false| Field | Meaning |
|---|---|
timeZone | The time zone of the schedule. Without it, the schedule uses the time zone of the kube-controller-manager, which on EKS is UTC. So 0 2 * * * without a time zone runs at 07:30 in India. Stable since Kubernetes 1.27. Setting CRON_TZ= or TZ= inside the schedule is not supported |
concurrencyPolicy | What if the previous run is still going? Allow (default): run both. Forbid: skip the new run. Replace: stop the old run and start the new one |
startingDeadlineSeconds | If a run could not start on time (controller down, cluster busy), still start it if no more than this many seconds late. Otherwise skip it |
suspend: true | Pause the schedule without deleting the CronJob. Running Jobs continue |
For a nightly backup, concurrencyPolicy: Forbid is usually right: two backups writing at the same time help nobody.
Make scheduled tasks safe to run twice
The CronJob controller tries to create exactly one Job per schedule tick, but in rare cases it can create two, or none. Write your task so that running it twice causes no harm (idempotent): for example, a backup file named by date that is simply overwritten.
Useful commands
# run a CronJob right now, for testing, without waiting for the schedule
kubectl create job manual-run-1 --from=cronjob/telusko-cronjob
# pause and resume the schedule
kubectl patch cronjob telusko-cronjob -p '{"spec":{"suspend":true}}'
kubectl patch cronjob telusko-cronjob -p '{"spec":{"suspend":false}}'Clean up
A CronJob with a one-minute schedule keeps creating pods until you remove it:
kubectl delete -f cron-job.yml
kubectl get cronjobs,jobs,podsDeleting the CronJob also deletes the Jobs and pods it created.
Try It Yourself
- Change the schedule to every 2 minutes and add
timeZone: "Asia/Kolkata". Checkkubectl get cronjobfor the time zone column. - Make the task take 90 seconds (
sleep 90) with a one-minute schedule. CompareconcurrencyPolicy: AllowandForbidusingkubectl get jobs -w. - Use
kubectl create job --from=cronjob/...to run it immediately, and find that Job inkubectl get jobs. - Write the schedule for "at 23:30 on weekdays (Monday to Friday)" and check it on crontab.guru.
Official references
Written By: Shramik Masti
How is this guide?
Last updated on
Kubernetes Jobs: Non-Parallel & Parallel Jobs
Run one-off tasks to completion with Kubernetes Jobs, control how many pods run and how many must succeed with completions and parallelism, and handle retries and cleanup.
Helm: Kubernetes Package Manager
Understand why Helm exists, what charts, repositories and releases are, install Helm on the EKS home server, and learn the core commands to install, upgrade, roll back and uninstall applications.
