CronJobs are a way to run a task on a time-based schedule and have been around for a long time in Linux and UNIX systems. They can be used in Kubernetes (K8S) to run recurring tasks such as backup jobs, triggering emails, report generation, or automating restarts of containers.
In this article, we will dive into how to define a CronJob, look at how to implement them in K8S manifest files with an example, and the available options.
To define a Cronjob, the schedule is defined using the CronJob syntax below:
# ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) # │ │ ┌───────────── day of the month (1 - 31) # │ │ │ ┌───────────── month (1 - 12) # │ │ │ │ ┌───────────── day of the week (0 - 6) (Sun to Sat; # │ │ │ │ │ 7 is also Sunday on some systems) # │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat # │ │ │ │ │ # * * * * *
The Cronjob schedule is specified using 5 entries separated by spaces.
For example, running a job every day at 11 pm would be defined as:
0 23 * * *
A job running every minute would look like this:
* * * * *
Check out Crontab.guru to experiment with defining CronJobs.
For CronJobs with no time zone specified, the kube-controller-manager interprets schedules relative to its local time zone. As of Kubernetes v1.25 [beta] the
CronJobTimeZone feature gate can be enabled, which enables a specific time zone to be specified should it be required. For example:
To see a CronJob in action, we first need to specify the CronJob in a manifest file.
Create the below file and name it cronjob.yaml. Note the kind is set to CronJob, and the
.spec.schedule is set to run the job every minute. The
.spec.schedule is a required field of the
.spec. It takes a Cron format string, as detailed previously.
The name you provide must be a valid DNS subdomain name no longer than 52 characters. This is because the CronJob controller will automatically append 11 characters to the Job name provided, and there is a constraint that the maximum length of a Job name is no more than 63 characters.
The example itself will output ‘Hello from the Kubernetes cluster’ to the logs.
apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: "* * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox:1.28 imagePullPolicy: IfNotPresent command: - /bin/sh - -c - date; echo Hello from the Kubernetes cluster restartPolicy: OnFailure
Create the deployment:
kubectl create -f .\cronjob.yaml
Verify the CronJob has been created:
kubectl get cronjob hello
The LAST SCHEDULE field shows how long ago the job last ran.
The ACTIVE field shows how many jobs are in progress, 0 meaning it has either already been completed or failed.
Note that the job name is different from the pod name, which is specified in the manifest file.
You can view the running jobs in real-time using the
kubectl get jobs --watch
To view the pods that have been created to run the jobs:
kubectl get pods
If you have lots of running pods you’ll want to filter the selection to the job name in your system using the
--selector argument. Note that only the last three pods will be shown by default unless a different value has been specified by the optional field
kubectl get pods --selector=job-name=hello-27827258
To view the logs from the pod to verify the command ran successfully:
kubectl logs hello-27827258--1-rdf4s
To clean up, delete the CronJob. Deleting the CronJob removes all the jobs and pods it created and stops it from creating additional jobs:
kubectl delete cronjob hello
See how to delete Pods from a Kubernetes Node.
There are a number of optional fields that can be used to further control CronJobs.
The Starting Deadline is an optional field that specifies the deadline in seconds for starting the job if it misses its scheduled time for any reason. After the deadline, CronJob does not start the job. Jobs that do not meet their deadline in this way count as failed jobs.
If this field is not specified, the jobs have no deadline. For example, if it is set to
60, it allows a job to be created for up to 60 seconds after the actual schedule.
Note that if the
startingDeadlineSeconds is set to a value of less than 10 seconds, the CronJob may not be scheduled. This is because the CronJob controller checks things every 10 seconds.
The Concurrency policy is also an optional field that specifies how to handle concurrently running jobs. This may be useful for jobs that need to run independently to avoid unwanted results. By default, if this is not specified, concurrently running jobs are always allowed.
Allow(default): The CronJob allows concurrently running jobs.
Forbid: The CronJob does not allow concurrent runs; if it is time for a new job run and the previous job run hasn’t finished yet, the CronJob skips the new job run.
Replace: If it is time for a new job run and the previous job run hasn’t finished yet, the CronJob replaces the currently running job run with a new job run.
The Suspend field is optional that can be set to either
false . If it is set to true, then all subsequent operations are suspended. The current suspend status can be viewed using the command below:
kubectl get cronjob hello
An optional field to specify the number of successful jobs to keep in the history, which by default is 3.
Similar to the above option, the failed jobs history limit can also be specified. This defaults to 1.
CronJobs are used to schedule recurring tasks in Kubernetes.
For more information on CronJobs check out the official documentation on kubernetes.io.
And take a look at how Spacelift helps you manage the complexities and compliance challenges of using Kubernetes. Anything that can be run via kubectl can be run within a Spacelift stack. Find out more about how Spacelift works with Kubernetes.
The Most Flexible CI/CD Automation Tool
Spacelift is an alternative to using homegrown solutions on top of a generic CI. It helps overcome common state management issues and adds several must-have capabilities s for infrastructure management.