[Demo Webinar] How to Orchestrate IaC Workflows with Spacelift

➡️ Register Now

Kubernetes

CronJob in Kubernetes – Automating Tasks on a Schedule

Running Cron Jobs in Kubernetes

🚀 Level Up Your Infrastructure Skills

You focus on building. We’ll keep you updated. Get curated infrastructure insights that help you make smarter decisions.

CronJobs are a fundamental part of Linux/Unix automation, providing a straightforward way to schedule tasks to run automatically at specific times or intervals. In this article, we will explore defining a CronJob in Kubernetes, l implementing CronJobs in K8S manifest files (using an example), and the available options.

What we’ll cover:

  1. What is a CronJob in Kubernetes?
  2. How do CronJobs work?
  3. Kubernetes CronJobs benefits and use cases 
  4. Kubernetes CronJob usage tutorial
  5. Kubernetes CronJob spec options
  6. Example: Automating MySQL backups with a Kubernetes CronJob
  7. How to disable a Kubernetes CronJob
  8. Common Kubernetes CronJobs errors and troubleshooting
  9. Kubernetes Jobs vs CronJobs
  10. Kubernetes pods vs CronJobs
  11. Kubernetes Deployments vs CronJobs

What is a CronJob in Kubernetes?

A CronJob in Kubernetes is a resource used to run scheduled tasks within a Kubernetes cluster. It automates recurring jobs, such as database backups, log rotation, or batch processing, by executing commands or scripts at specified intervals using the cron syntax. CronJobs are a long-standing feature of Linux and UNIX systems. 

Unlike a standard Kubernetes Job, which runs once and exits, a CronJob schedules jobs to run at fixed times, dates, or intervals. Kubernetes manages these jobs, ensuring they execute as defined and handling retries if necessary.

Kubernetes also follows job history, concurrency policies, and resource limits, making CronJobs reliable for scheduled automation.

How do CronJobs work?

Traditionally used on Unix-based systems, CronJobs work as follows:

  1. The user creates a cron job by using the crontab command to edit their “crontab” file. This file contains a list of commands or scripts to be executed and the times when they should be executed.
  2. The cron daemon, a background process that runs continuously, reads the crontab files of all users and checks if any jobs are scheduled to run at the current time.
  3. If a job is scheduled to run, the cron daemon executes the command or script associated with the job.

In Kubernetes, CronJobs use the cron syntax to specify the execution time (e.g., "0 2 * * *" for running at 2 a.m. daily). When triggered, Kubernetes creates a Job resource, which in turn spawns a Pod to execute the task. By default, Kubernetes ensures that jobs are completed successfully and can retry failed executions based on its configuration.

For example, a CronJob definition in YAML might include:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: example-cronjob
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: example-task
            image: busybox
            command: ["echo", "Hello, Kubernetes!"]
          restartPolicy: OnFailure

This configuration runs a simple task at 2 a.m. daily, printing a message to the logs.

Kubernetes CronJobs benefits and use cases

The main benefit of using a CronJob in Kubernetes is that it allows you to automate recurring tasks, such as backups, data synchronization, batch processing, and maintenance jobs. To save manual effort, you should use CronJobs everywhere they are the most appropriate option.

When should you use Kubernetes CronJobs?

Some common use cases for CronJobs in K8s include:

  1. Data backup — Schedule periodic backups of application or database data, ensuring important information is regularly saved to persistent storage or an external location.
  2. Database maintenance — Automate tasks such as database cleanup, reindexing, or data migration to maintain performance and integrity.
  3. Log rotation and cleanup — Rotate and manage application log files to prevent excessive growth, which can impact system performance and storage.
  4. Certificate renewal — Automate SSL/TLS certificate renewal to ensure applications always use up-to-date and valid certificates for secure communication.
  5. Data synchronization — Periodically synchronize data between different systems or databases to keep information updated across services.
  6. Scheduled reports — Generate and send periodic reports (daily, weekly, or monthly) to users or stakeholders.
  7. Batch processing — Run batch jobs for processing large data volumes at scheduled intervals, such as nightly ETL (Extract, Transform, Load) processes or data imports/exports.
  8. Scheduled cleanup — Automate the removal of temporary files, outdated data, or unused resources to optimize system performance and reduce costs.
  9. Maintenance tasks — Schedule routine application maintenance tasks, such as database schema updates, software updates, or health checks.
  10. Resource scaling — Adjust application resources based on demand, scaling up during peak hours and down during off-peak times.
  11. Security scanning — Conduct regular security scans and vulnerability assessments to identify and mitigate risks.
  12. Monitoring and alerts — Automate system health checks, collect logs and metrics, and trigger alerts based on collected data.
  13. Content publishing — Schedule content updates or publishing for websites, blogs, or content management systems.
  14. Compliance audits —Automate compliance checks and audits to ensure adherence to regulatory requirements.
  15. Cache invalidation — Schedule cache invalidation or purges to ensure applications serve the latest data to users.

Kubernetes CronJob usage tutorial

Let’s now explore how to use Kubernetes CronJobs in practice.

Kubernetes CronJob schedule syntax

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 five entries separated by spaces.

For example, running a job every day at 11 p.m. 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:

spec.timeZone: "Etc/UTC"

How to create CronJob in Kubernetes

To see a CronJob in action, we first need to specify the CronJob in a manifest file.

Create the file below and name it cronjob.yaml. Note that 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 the maximum length of a Job name can be 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
kubectl get cronjob hello

The LAST SCHEDULE field shows how long ago the job last ran.

The ACTIVE field shows the number of jobs in progress, with 0, meaning they have either already been completed or failed.

Note that the job name is different from the pod name specified in the manifest file.

You can view the running jobs in real time using the --watch argument.

kubectl get jobs --watch
kubectl get jobs --watch

To view the pods that have been created to run the jobs:

kubectl get pods
kubectl get pods

If you have many running pods, you’ll want to filter the selection to the job name in your system using the --selector argument.

By default, only the last three pods will be shown unless a different value has been specified by the optional field spec.successfulJobsHistoryLimit.

kubectl get pods --selector=job-name=hello-27827258
kubectl get pods --selector=job-name

To verify the command ran successfully, view the logs from the pod:

kubectl logs hello-27827258--1-rdf4s
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
kubectl delete cronjob hello

How to create a Job from CronJob in Kubernetes

To create a Job from an existing CronJob in Kubernetes, first, identify the CronJob by listing all available ones using:

kubectl get cronjob

Once you have the name, use the following command to generate a Job from it:

kubectl create job --from=cronjob/<cronjob-name> <new-job-name>

Then, you can verify its status with kubectl get jobs and check the associated pods using:

kubectl get pods --selector=job-name=<new-job-name>

If the Job is no longer needed, remove it using:

kubectl delete job <new-job-name>

Useful commands for managing Kubernetes CronJobs

Here is a cheat sheet of the key commands to manage a Kubernetes CronJob:

  • Create the CronJob: kubectl apply -f cronjob.yaml
  • Check CronJob status:  kubectl get cronjob
  • Check created Jobs: kubectl get jobs
  • View logs: kubectl logs <pod-name>
  • Delete the CronJob: kubectl delete cronjob hello-cronjob

Kubernetes CronJob spec options

Here are optional fields that can be used to further control CronJobs:

1. startingDeadlineSeconds

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.

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.

2. concurrencyPolicy

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.

3. suspend

The Suspend field is optional and can be set to either true or 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
kubectl get cronjob hello

Example: Automating MySQL backups with a Kubernetes CronJob

A common use case is automating database backups. In this example, we will create a Kubernetes CronJob that performs a MySQL database dump every day at 2 a.m. and stores the backup in a Persistent Volume Claim (PVC).

Before we create the CronJob, we need a PersistentVolumeClaim (PVC) to store the MySQL backups. The PVC ensures that backups persist even after the job completes.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-backup-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Apply this PVC before deploying the CronJob:

kubectl apply -f pvc.yaml

Now that we have storage, we define the Kubernetes CronJob that runs every day at 2 a.m., takes a MySQL database dump, and saves it to the PVC.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-backup-cronjob
spec:
  schedule: "0 2 * * *"  # Runs every day at 2 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: mysql-backup
            image: mysql:5.7
            command:
              - "/bin/sh"
              - "-c"
              - "mysqldump -h $MYSQL_HOST -u root -p$MYSQL_ROOT_PASSWORD mydatabase | tee /backup/mysql-backup.sql"
            env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: root-password
            - name: MYSQL_HOST
              value: "mysql-service"  # Change if your MySQL service has a different name
            volumeMounts:
            - name: backup-volume
              mountPath: /backup
          restartPolicy: OnFailure
          volumes:
          - name: backup-volume
            persistentVolumeClaim:
              claimName: mysql-backup-pvc

Apply this CronJob:

kubectl apply -f cronjob.yaml

Once it is deployed, we need to ensure the CronJob runs correctly. 

  • Check if the CronJob is created: kubectl get cronjob

Expected output:

NAME                   SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
mysql-backup-cronjob   0 2 * * *   False     0        12h ago        1d
  • Check if backup jobs are running: kubectl get jobs.
  • Check logs of a specific job: kubectl logs job/<job-name> to verify if the backup process executed correctly.

Instead of hardcoding the MySQL root password, we have to use a Kubernetes Secret. Below is the YAML for creating a secret to store the password securely:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  root-password: cGFzc3dvcmQ=  # Replace with your actual base64-encoded password

Generate a base64-encoded password:

echo -n "your-actual-password" | base64

Apply this secret:

kubectl apply -f secret.yaml

How to disable a Kubernetes CronJob

To disable a Kubernetes CronJob, you can suspend it instead of deleting it, ensuring it remains configured but does not create new jobs.

To suspend a CronJob, update its spec.suspend field to true using the following command:

kubectl patch cronjob <cronjob-name> -p '{"spec": {"suspend": true}}'

Alternatively, you can edit the CronJob manifest:

  1. Run kubectl edit cronjob <cronjob-name>.
  2. Locate the spec.suspend field (if missing, add it under spec).
  3. Set suspend: true and save the changes.

If you want to stop the CronJob permanently, you can delete it with:

kubectl delete cronjob <cronjob-name>

Suspending is useful when you need to disable the job temporarily without losing its configuration.

Common Kubernetes CronJobs errors & troubleshooting

Common errors and problems with CronJobs include:

Kubernetes not scheduling CronJob or CronJob stops scheduling jobs

If you encounter errors when setting up a CronJob, check the following:

  1. Syntax: CronJobs use the same syntax as traditional UNIX cron jobs, which can be complex and difficult to get right. Common errors include specifying the wrong number of fields, using incorrect wildcards, or mistyping the cron schedule. Check the syntax section of the article and copy your expression into crontab.guru to make sure the syntax is correct.
  2. Timezone: CronJobs run in the timezone of the Kubernetes cluster by default, which may not match the timezone of the user or application. This can lead to scheduling conflicts or unexpected behavior.
  3. Image: If a CronJob specifies an unavailable image, the job will fail.
  4. Resources: Setting resource limits on images too high will cause jobs to fail.
  5. Job concurrency: If a CronJob is set to run too frequently or with too many replicas, it might lead to excessive load on the cluster and cause other jobs to fail.
  6. Permissions: Check the CronJob has sufficient permissions to access resources or perform actions that are defined.

When troubleshooting CronJob errors, the Kubernetes logs are the first port of call. You can use the kubectl logs command to interrogate the Kubernetes server API logs, CronJob controller logs, Pod logs, and Container logs.

kubectl logs -n <namespace> <cronjob-controller-pod-name> -c cronjob-controller

If you are using a centralized logging solution such as Elasticsearch, Fluentd, or Kibana (EFK) to collect and analyze logs from multiple nodes and containers in the cluster (as recommended), you should check the logs using those tools for deeper insight.

Monitoring solutions such as Prometheus, Datadog, Grafan, or New Relic can be used to track job execution, such as the number of successful and failed jobs, job duration, and resource usage.

Error status on Kubernetes CronJob with connection refused

If you’re encountering a Connection Refused error status in a Kubernetes CronJob, it typically indicates that the CronJob or the associated pods are unable to establish a network connection to the specified target or endpoint.

You should run through general network troubleshooting steps to resolve this, including:

  1. Verify that the target service, server, or endpoint to which the CronJob is trying to connect is up and running.
  2. Ensure that the target service’s host and port information is correctly configured in your CronJob specification.
  3. If you are using network policies in your Kubernetes cluster, make sure that the CronJob pods have the necessary network policies to allow outgoing connections to the target.
  4. Ensure that DNS resolution is working correctly within your Kubernetes cluster. Pods should be able to resolve the DNS of the target service.
  5. Check if there are any external firewalls, network security groups, or cloud provider security settings that might be blocking the outgoing connections from your Kubernetes cluster to the target. Similarly, check if there are any internal network policies, firewalls, or proxy configurations within the Kubernetes cluster that could be affecting network connections. Don’t forget any egress controls or firewall rules that may be in place at the cluster level.
  6. If the target is a service within your Kubernetes cluster, make sure that the service and endpoints are correctly defined.
  7. Examine logs on the target side to see if there are any errors or issues that may help identify the cause of the “Connection Refused” error.
  8. Review any pod security policies or admission controllers that might be preventing the CronJob pods from making outbound connections.
  9. If you are relying on Kubernetes service discovery, confirm that the service’s DNS name is correct and that it resolves to the expected IP address.
  10. Verify that the container image used in the CronJob’s pods includes the necessary dependencies and configurations for making outbound network connections. It should not have any restrictions or misconfigurations that prevent networking.
  11. Consider implementing timeouts and retry mechanisms in your application to handle transient network issues. Sometimes, connection refused errors can be temporary.

What is the difference between a Kubernetes Job and a CronJob?

A Kubernetes Job is used for one-time or finite tasks, ensuring execution to completion, even if a node fails. It is ideal for batch processing, database migrations, or transient workloads that must succeed at least once. Jobs can run once or multiple times in parallel to process workloads efficiently. 

A Kubernetes CronJob is a scheduled Job that runs at fixed intervals. 

So, to summarize: Jobs execute once or a set number of times, whereas CronJobs run repeatedly on a schedule.

What is the difference between pod and CronJob?

A Pod is the smallest deployable unit in Kubernetes, representing a running instance of one or more containers that share storage and network resources. Pods are typically used for long-running applications or microservices that need to stay active.

A CronJob automatically creates Job objects at specified intervals, which then run short-lived Pods to complete tasks like database backups, log rotation, or periodic report generation.

What is the difference between Kubernetes Deployment and CronJobs?

A Kubernetes Deployment manages the lifecycle of long-running applications, ensuring that a specified number of replicas of a pod are running at all times. It supports scaling, rolling updates, and rollback mechanisms, making it ideal for web applications, APIs, and microservices that need continuous availability.

In contrast, a Kubernetes CronJob is designed for scheduled, one-time, or recurring tasks. It runs jobs at specified intervals using a cron-like syntax, making it useful for periodic tasks like database backups, report generation, or batch processing. Unlike Deployments, CronJobs do not maintain a persistent application state; they execute and then terminate.

Managing Kubernetes with Spacelift

If you need assistance managing your Kubernetes projects, consider Spacelift. It brings with it a GitOps flow, so your Kubernetes Deployments are synced with your Kubernetes Stacks, and pull requests show you a preview of what they’re planning to change. 

With Spacelift, you get:

  • Policies to control what kind of resources engineers can create, what parameters they can have, how many approvals you need for a run, what kind of task you execute, what happens when a pull request is open, and where to send your notifications
  • Stack dependencies to build multi-infrastructure automation workflows with dependencies, having the ability to build a workflow that can combine Terraform with Kubernetes, Ansible, and other infrastructure-as-code (IaC) tools such as OpenTofu, Pulumi, and CloudFormation,
  • Self-service infrastructure via Blueprints, or Spacelift’s Kubernetes operator, enabling your developers to do what matters – developing application code while not sacrificing control
  • Creature comforts such as contexts (reusable containers for your environment variables, files, and hooks), and the ability to run arbitrary code
  • Drift detection and optional remediation
  • Advanced scheduling for implementing cron scheduled jobs for running stacks and tasks, and also for deleting stacks

If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.

Key points

CronJobs are used to schedule recurring tasks in Kubernetes. In this guide, we’ve explored use cases, spec options, troubleshooting tips, and an example of automating MySQL backups with a CronJob.

Don’t forget to check out how Spacelift helps you manage the complexities and compliance challenges of using Kubernetes.

Manage Kubernetes easier and faster

Spacelift allows you to automate, audit, secure, and continuously deliver your infrastructure. It helps overcome common state management issues and adds several must-have features for infrastructure management.

Learn more

Kubernetes Commands Cheat Sheet

Grab our ultimate cheat sheet PDF

for all the kubectl commands you need.

k8s book
Share your data and download the cheat sheet