Cron Jobs
The Ultimate Kubernetes CronJob Guide
It’s common to have a task that needs to run repeatedly with a specific interval. For years engineers have been using cron jobs in Linux to accomplish this. Because of the ubiquitous need for background jobs in all software applications, cron jobs have also been built into Kubernetes.
Kubernetes CronJobs can be used for repeated tasks such as backups and report generation. The tasks can be set to repeat anywhere from hourly to annually.
If you’re looking to optimize your use of Kubernetes, this article will explain how to incorporate CronJobs into your workflow. It will also note problems to look out for, so you can make sure your CronJobs run correctly.
What is a K8s CronJob?
According to the Kubernetes documentation, a CronJob object is like one line of a crontab or cron table file. It runs scheduled Kubernetes jobs in Cron format in the background while you focus on other aspects of software development.
The below diagram demonstrates the CronJob process:

As you can see, a complex mechanism is needed to deliver a simple cron function. Kubernetes will need at least three different objects (CronJob, Job, and Pod) to fulfill the cron task. This implementation is deliberate. The design follows the core Kubernetes principle of responding to changes and performing adaptive actions in the cluster in the loop.
The process, as shown in the diagram, goes as follows:
- The user applies a CronJob manifest that contains two main pieces of information: when to execute and what to do. (You can see a sample configuration below.)
- The main logic is implemented in the CronJob controller as part of
kube-controller-manager. By default, it checks every ten seconds whether it should run a CronJob. - When the controller finds a CronJob to execute (meaning the current time matches the time specified via cron syntax), it will create another object called Job. Each Job tracks a particular invocation and contains inherited information from the CronJob on what to do.
- After Kubernetes detects a new Job object, it will immediately try to execute. It will schedule the creation of a new Pod based on the configuration passed down from CronJob via Job in
jobTemplate. When the Pod runs, it will perform your cron task.
Advantages of Kubernetes CronJobs
In Kubernetes, unlike in Linux, all the cron work is done inside Pods. This means you gain the benefits of containerization.
You get isolation between tasks. Each run starts from the same image with the CPU, memory, and filesystem you assigned, and a finished container does not leave files behind for the next one. That keeps one execution from changing the next. You can run more than one at a time, or place a heavy run on a node with more CPU or memory. Setup steps can go in init containers, and container lifecycle hooks can run at startup and shutdown.
You can also keep the job next to the application. Store the CronJob as a YAML manifest, in a Helm chart, or in Terraform, and deploy it with the rest of the app. The same manifest moves through dev, stage, and production with the pipeline you already have.
Kubernetes’s advanced features also allow you to specify edge cases. For instance, you can ensure that none of the tasks are running simultaneously (if needed), consider a Job as failed after a specified number of retries, or define whether a restart is allowed.
Creating Kubernetes CronJobs
There are some basic rules to keep in mind. The following is a sample Kubernetes CronJob manifest:
apiVersion: batch/v1
kind: CronJob
metadata:
name: helloworld
spec:
schedule: "*/15 * * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: task
image: busybox
command:
- /bin/sh
- -c
- date; echo 'Hello World from Cronitor.io';
Here are some details about the cronjob.yaml file above:
- The object is a
CronJobin thebatch/v1API, namedhelloworld. Keep the name to 52 characters or fewer. The controller appends 11 characters when it creates each Job, and a Job name cannot be longer than 63. schedule: "*/15 * * * *"runs the job every fifteen minutes. With notimeZone, Kubernetes reads that schedule in the kube-controller-manager's local time..spec.timeZonehas been stable since Kubernetes 1.27. The recipes page has a short example.- The
jobTemplateprintsHello World from Cronitor.ioand the current date.
If you are not familiar with the cron syntax, you can use crontab.guru to adjust the syntax. The rules are as follows:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │ 7 is also Sunday on some systems)
# │ │ │ │ │ OR Sun, Mon, Tue, Wed, Thu, Fri, Sat
# │ │ │ │ │
# * * * * *
Next, you’re going to deploy this CronJob. Run the example by using this command:
kubectl apply -f cronjob.yaml
The output should be similar to this:
cronjob.batch/helloworld created
After it’s created, you can check the status using this command:
kubectl get cronjob helloworld
The output should present your CronJob:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
helloworld */15 * * * * False 0 <none> 10s
As you can see, the CronJob has not yet been scheduled. You can watch Jobs and wait for execution with the following command, which also allows you to simply monitor your CronJob:
kubectl get jobs --watch
After fifteen minutes, you should see this output:
NAME COMPLETIONS DURATION AGE
helloworld-4111706356 0/1 0s 0s
helloworld-4111706356 1/1 1s 15min
If you don’t want to wait fifteen minutes, you can run the CronJob manually, creating the Kubernetes Job via command kubectl create job helloworld --from=cronjob/helloworld.
Use the suggestion above and run the command again to see that it scheduled the Job:
kubectl get cronjob helloworld
Now your output should say that the CronJob called helloworld was successfully scheduled at the time specified in the LAST SCHEDULE column:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
helloworld */15 * * * * False 0 10s 5min
The next step is to verify that the CronJob performed correctly. Find the Pod’s logs and check the task’s output. (If the following command fails, check the name of the Job in the selector.)
kubectl logs $(kubectl get pods --selector=job-name=helloworld -o=jsonpath='{.items[0].metadata.name}')
The output should be similar to this:
Fri May 29 11:02:09 UTC 2022
Hello World from Cronitor.io
Finally, either suspend the CronJob or delete it:
kubectl patch cronjobs helloworld -p '{"spec" : {"suspend" : true }}'
kubectl delete cronjob helloworld
Remember that deleting the CronJob will stop and remove all the Jobs and Pods it created, so this will clear out your cron history.
This example used the busybox container image to demonstrate CronJob behavior. In a real-world scenario, the common practice is to prepare your own container image with all the necessary dependencies. You can use the same container as your main application, but run it with different entrypoint parameters. In that way, you don’t repeat yourself (DRY) preparing multiple container images, which speeds up the CI/CD process as well since your image could be cached locally.
Be aware that scaling CronJobs can be tricky. You can deploy multiple manifests of CronJobs and it will work like a charm. However, your task needs to be prepared to run multiple times simultaneously without creating the same outcome. For example, if your cron task runs in parallel for the same input parameters, it could lead to a race condition that could lead to overwriting your data or performing downstream tasks twice or more. This scenario shows how important it is to monitor and understand how your cron jobs work if they are retrying or passed successfully.
Sometimes you can encounter problems with your Kubernetes CronJob, which is normal. There are two common places for mistakes: either you prepare your CronJob manifest with an error, or your cron task experiences a logical issue.

The Kubernetes agent creates a job monitor for each CronJob it watches and records successes and failures. The page looks like the one above: schedule, run history, and how long each run took. This screenshot is a Linux cron job. A CronJob monitor uses the same layout. Install steps and a safe rollout are in Monitoring Kubernetes Cron Jobs. Sign up for free if you do not have an account yet.
Kubernetes CronJob Reference
Learn more about creating, monitoring and migrating Kubernetes CronJobs.
Monitoring Kubernetes Cron Jobs
Learn how to quickly monitor your jobs and receive alerts
Migrating to Kubernetes Cron Jobs
A step-by-step guide to migrating from Linux cron jobs to Kubernetes.
Kubernetes Cron Job Recipes
Learn about the most common kubectl commands needed for working with K8s CronJobs.