Kubernetes CronJobs

The time-based scheduler for Kubernetes batch workloads. A CronJob wraps a Job with a cron expression, creating a new Job (and therefore new Pods) on every schedule tick. Synthesized from CKA Day 12 — DaemonSet, Job & CronJob Explained.

What is a CronJob?

A CronJob is a Kubernetes controller that creates Jobs on a recurring schedule. It is the cluster-native equivalent of crontab — but with the full power of Kubernetes resource management, fault tolerance, and observability.

Every time the schedule triggers, the CronJob controller spawns a new Job object. That Job creates Pods, waits for them to complete, and then reports status. Because each scheduled run is an independent Job, a failed run does not block the next scheduled execution.

Key Insight: CronJob → Job → Pod. The CronJob never creates Pods directly. It is a meta-controller that manages Job lifecycles over time.

Why Use a CronJob?

RequirementLinux crontabKubernetes CronJob
Run on a schedule
Cluster-aware resource limits
Automatic retry on failure✅ (via Job backoffLimit)
Run history and logs❌ (manual)✅ (kubectl get jobs)
Concurrency control✅ (concurrencyPolicy)
Suspend without deleting✅ (suspend: true)
History cleanup✅ (successfulJobHistoryLimit)

Canonical Use Cases

  • Scheduled backups: Database dumps, etcd snapshots, volume snapshots
  • Periodic cleanup: Prune old logs, delete temporary files, expire cache entries
  • Recurring reports: Daily sales reports, weekly analytics exports, monthly audits
  • Health checks: Periodic liveness tests, certificate expiration checks, compliance scans
  • Data synchronization: Nightly ETL syncs, batch imports from external APIs

YAML Structure

apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-backup
spec:
  schedule: "0 2 * * *"  # Daily at 2:00 AM
  startingDeadlineSeconds: 3600
  concurrencyPolicy: Forbid
  successfulJobHistoryLimit: 3
  failedJobHistoryLimit: 1
  suspend: false
  jobTemplate:
    spec:
      backoffLimit: 3
      activeDeadlineSeconds: 1800
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: backup
            image: postgres:15
            command:
            - pg_dump
            - -h
            - db-service
            - -U
            - admin
            - -f
            - /backups/daily.sql
            volumeMounts:
            - name: backup-vol
              mountPath: /backups
          volumes:
          - name: backup-vol
            emptyDir: {}

Key fields:

FieldDefaultDescription
scheduleRequiredCron expression (standard 5-field format)
startingDeadlineSecondsunsetMax seconds after scheduled time to still start the Job
concurrencyPolicyAllowAllow (overlap), Forbid (skip if running), Replace (kill old, start new)
successfulJobHistoryLimit3Number of completed Job objects to retain
failedJobHistoryLimit1Number of failed Job objects to retain
suspendfalsePause the schedule without deleting the CronJob
jobTemplateRequiredThe Job spec template for each scheduled run

Cron Expression Format

Kubernetes uses the standard 5-field cron format:

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * *

Common patterns:

ExpressionMeaning
*/5 * * * *Every 5 minutes
0 * * * *Every hour at minute 0
0 2 * * *Daily at 2:00 AM
0 0 * * 0Every Sunday at midnight
0 0 1 * *First day of every month at midnight

Concurrency Policies

PolicyBehaviorWhen to Use
AllowMultiple Jobs from the same CronJob can run simultaneouslyIndependent, idempotent tasks
ForbidIf a Job is still running, the next scheduled start is skippedTasks that must not overlap
ReplaceIf a Job is still running, it is terminated and a new one startsAlways need the latest data

Managing History and Cleanup

By default, Kubernetes keeps 3 successful Jobs and 1 failed Job. Older Jobs are automatically deleted. You can adjust these limits or use a ttlSecondsAfterFinished field inside the jobTemplate to delete individual Jobs (and their Pods) after a set time.

Suspending a CronJob

kubectl patch cronjob db-backup -p '{"spec":{"suspend":true}}'

This stops the schedule without deleting the CronJob definition — useful for maintenance windows or incident response.

Essential Commands

CommandPurpose
kubectl get cronjobsList CronJobs
kubectl get jobsSee Jobs created by the CronJob
kubectl describe cronjob <name>Schedule, history, and last run status
kubectl logs job/<job-name>Read logs from a specific run
kubectl delete cronjob <name>Delete CronJob and stop scheduling
kubectl create cronjob ... --dry-run=client -o yamlGenerate a manifest quickly

CKA Exam Relevance

  • Workloads & Scheduling (~15%): Create a CronJob with a given schedule. Be precise with the cron expression.
  • Troubleshooting (~30%): If a CronJob missed a run, check startingDeadlineSeconds (was the controller down too long?), concurrencyPolicy (was it Forbid and a previous Job still running?), and suspend status.
  • Speed pattern:
    kubectl create cronjob backup --image=busybox --schedule="0 2 * * *" \
      --dry-run=client -o yaml > cronjob.yaml
    # Edit jobTemplate to add volumes, env vars, and restartPolicy: OnFailure

Sources


Tags: kubernetes cronjob batch scheduling cka devops backup cleanup cron