CKAD — CronJobs

2 minute read

What Is a CronJob?

A CronJob creates Jobs on a schedule. It uses the standard cron format to define when Jobs should run — every minute, every hour, daily, weekly, or any custom interval.

Think of it as a Kubernetes-native replacement for the Linux crontab.

Cron Schedule Format

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sun=0)
│ │ │ │ │
* * * * *
Schedule Meaning
*/5 * * * * Every 5 minutes
0 * * * * Every hour (at minute 0)
0 0 * * * Every day at midnight
0 9 * * 1 Every Monday at 9:00 AM
0 0 1 * * First day of every month
30 2 * * 1-5 Weekdays at 2:30 AM
0 */6 * * * Every 6 hours
0 9,17 * * * At 9:00 AM and 5:00 PM daily

Exam tip: Memorize the field order: minute, hour, day-of-month, month, day-of-week. The exam will test your ability to write correct cron expressions.

Creating a CronJob

Imperative (Fast for Exams)

kubectl create cronjob db-backup --image=busybox:1.36 \
  --schedule="0 2 * * *" \
  -- /bin/sh -c "echo 'Backup at $(date)'"

Declarative (YAML)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-backup
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: busybox:1.36
            command: ["/bin/sh", "-c"]
            args: ["echo 'Database backup started at $(date)' && sleep 10 && echo 'Backup completed'"]
          restartPolicy: OnFailure
kubectl apply -f db-backup.yaml

# Check the CronJob
kubectl get cronjobs
# Expected:
# NAME        SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
# db-backup   0 2 * * *   False     0        <none>          10s

# Manually trigger a CronJob run (useful for testing)
kubectl create job db-backup-test --from=cronjob/db-backup

CronJob YAML Structure

apiVersion: batch/v1
kind: CronJob
metadata:
  name: <cronjob-name>
spec:                                    ← CronJob spec
  schedule: "*/30 * * * *"              ← Cron expression
  concurrencyPolicy: Forbid             ← How to handle overlaps
  startingDeadlineSeconds: 60           ← Max late start
  successfulJobsHistoryLimit: 3         ← Keep N successful Jobs
  failedJobsHistoryLimit: 1             ← Keep N failed Jobs
  suspend: false                        ← Pause scheduling
  jobTemplate:                          ← Job template
    spec:                               ← Job spec
      backoffLimit: 2
      activeDeadlineSeconds: 300
      template:                         ← Pod template
        spec:
          containers:
          - name: <container>
            image: <image>
            command: [...]
          restartPolicy: OnFailure

CronJob Configuration Options

Field Description Default
schedule Cron expression (required) —
concurrencyPolicy How to handle overlapping Jobs Allow
startingDeadlineSeconds Max seconds late a Job can start None
successfulJobsHistoryLimit How many successful Jobs to keep 3
failedJobsHistoryLimit How many failed Jobs to keep 1
suspend Pause the CronJob false

Concurrency Policy

What happens when a new scheduled run starts while the previous one is still running?

Policy Behavior
Allow Multiple Jobs can run at the same time (default)
Forbid Skip the new Job if the previous one is still running
Replace Kill the running Job and start a new one
# Prevent overlapping backups
spec:
  concurrencyPolicy: Forbid

When to Use Each

Policy Use When
Allow Jobs are independent and can safely overlap
Forbid Jobs would conflict (e.g., two database migrations at once)
Replace Only the latest run matters (e.g., cache refresh)

Generating CronJob YAML Quickly

# Generate YAML without creating the CronJob
kubectl create cronjob my-cron --image=busybox:1.36 \
  --schedule="0 * * * *" \
  --dry-run=client -o yaml \
  -- /bin/sh -c "echo hello" > cronjob.yaml

# Edit to add concurrencyPolicy, historyLimits, etc.
vi cronjob.yaml

Next: Learn operational commands with Managing Jobs & CronJobs →

Updated: