Migrating to Kubernetes CronJobs from Linux
Cron goes back to Version 6 Unix in 1975. It is still the usual way to run a program or script on a fixed schedule.
Cron has also been implemented in Kubernetes following the same principles. However, there are some key differences between using cron jobs in Linux and using cron jobs in Kubernetes. In this tutorial, you will learn more about these distinctions, and explore how to seamlessly migrate your Linux cron jobs to Kubernetes.
Kubernetes Cron Jobs
In Kubernetes, a CronJob is a special kind of pre-scheduled, automated job that runs efficiently at a scheduled cadence. Cron is commonly used for automatic system maintenance or administration. For example, you can easily prepare a backup creation strategy or reap stale resources. Generally, it’s helpful with any application that requires specific tasks to run periodically.

As pictured above, a job runs at the time specified in the cron job and creates a pod that executes and completes the designed task in the container.
The difference is the container. A Linux cron job runs on the host, so it can see the host's services, files, and memory. A Kubernetes CronJob runs in a Pod. That Pod only has the resources you give it, and it can run more than one container.
Containers make the resource limits explicit. Each run gets the memory and CPU you set, and cluster autoscaling can add capacity when the job is due. Kubernetes will also retry a failed Pod, which covers a blip such as a network error, up to the Job's backoffLimit.
The container filesystem starts fresh from the image on every run. Anything you do not put on a persistent volume is gone when the Pod exits, so one run cannot trip over files left by the last one.
The pods created by jobs are fundamentally the same as those created by Deployment objects in Kubernetes, meaning that the same advantages of pods also apply. Horizontal scaling and monitoring are done basically the same way as your other resources. Kubernetes can just replicate and multiply the configuration to create more of similar executions on all available nodes. The structure of new pods could be precisely the same or can easily be provisioned with different specifications to run with a large amount of RAM or on nodes with GPU.
Sample Cron Job in Kubernetes
Here’s an example of what a cron job in Kubernetes looks like:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cronjob
spec:
schedule: "*/10 * * * *"
concurrencyPolicy: Allow
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date;
restartPolicy: OnFailure
An analysis of this straightforward cronjob.yaml file shows the following:
- The cron job specification is under
batch/v1of the Kubernetes API. - The
kindisCronJob(note that this was previously calledScheduledJobin Kubernetes v1.5). - The name of the cron job is
hello-cronjob. - The job has been scheduled to execute every ten minutes.
- The
concurrencyPolicyhas three options:Allow: multiple jobs can run at the same timeForbid: stops multiple cron jobs from running at the same timeReplace: will replace a currently running job with the new job
- The example uses the busybox container image taken from Docker Hub by default.
- The
IfNotPresentpolicy is set by default and informs kubelet to pull a container image if it is not already present on the node. - The
commandorargssections are the place in the manifest where you define what needs to happen. In this case, it will print the date. - The restart policy is set to rerun on failure.
How to Migrate from Linux to Kubernetes Cron Jobs
The rest of this tutorial will show you the steps needed to migrate your cron jobs from Linux to Kubernetes.
Step 1: Containerization
The first step is to containerize the task, including the libraries it needs. Here is an example Dockerfile:
# choose the base image
FROM alpine
# install required dependencies
RUN apk --no-cache add curl bash
# copy your cronjob into a container
COPY my-cronjob.sh /app/my-cronjob.sh
# execute cronjob on startup
ENTRYPOINT [ "/app/my-cronjob.sh" ]
Basically, there are only two possible outcomes from your cron job: success or failure. To inform Kubernetes how your scheduled task behaved, the cron task needs to return the appropriate exit code. The exit 0 code means success; everything else will be considered as failure.
If you need to pass any sensitive data inside a container, such as passwords or tokens, according to the Twelve-Factor App methodology, it is recommended to use environment variables. For security reasons, you never want to store your credentials in containers or git repositories as plain text.
Push the image to a registry. Docker Hub is the common default. Quay.io, Amazon ECR, Google Artifact Registry, and Azure Container Registry are the other registries teams usually already have.
Finally, it’s convenient to use CI/CD tools to help you automate building and publishing containers. For example, see the GitHub Actions build-container workflow.
Step 2: Manifests
After containerizing, you need to declare a Kubernetes manifest for the CronJob in order to deploy it. To see an example manifest, refer to the "Sample Cron Job in Kubernetes" section above.
For scheduling, the most important part is the cron schedule expressions. If you are not experienced with this, you can use a free cron generator to prepare the desired schedule. However, the syntax follows these basic rules:
# ┌───────────── 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
# │ │ │ │ │
# * * * * *
Set the container image and the command the container should run. Pass configuration with a ConfigMap or a Secret, scope the Pod with a ServiceAccount, and add a PersistentVolumeClaim if the task has to keep files. The field reference is in the Kubernetes CronJob docs.
Step 3: Monitoring
Kubernetes will retry a Pod, but it will not tell you that a CronJob missed its schedule. The Jobs and Pods it creates look like any other Job and Pod, so a missed run is easy to lose in the cluster.
Cronitor watches the CronJob itself. The Hacker plan is free and includes five monitors, email and chat alerts (Slack, Discord, Microsoft Teams, and webhooks), and one basic status page. Branded and private status pages are paid.
The Kubernetes agent is a Helm chart. It creates a monitor for each CronJob it is allowed to see and reports successes and failures. By default it watches the whole cluster. Install commands, where to copy the API key, and how to narrow the first rollout are in Monitoring Kubernetes Cron Jobs. Annotations for including or excluding a single CronJob, and for pinning a monitor key, are in the agent README.
Conclusion
Moving a crontab line into Kubernetes is a container image plus a CronJob manifest. The schedule string can stay the same. What changes is the process: the task runs in a Pod, and nothing on the node remembers the last run unless you give it a volume. Once the CronJob is applied, install the Cronitor agent from the monitoring guide if you want an alert when a run fails or never starts.