/
Container & Orchestration

Kubernetes CronJob Guide

Kubernetes' CronJob resource creates a new Job (and therefore a new Pod) on a schedule, using the exact same standard 5-field cron syntax as Linux — but wrapped in a YAML manifest with its own concurrency, history, and deadline controls that a plain crontab doesn't have to think about.

Syntax Notes

The `schedule` field accepts standard 5-field cron syntax (no seconds field, no @nicknames in older versions — check your cluster's Kubernetes version). Everything else (concurrencyPolicy, successfulJobsHistoryLimit, startingDeadlineSeconds) is Kubernetes-specific YAML, not part of cron itself.

Examples

Basic CronJob manifest
apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-backup
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: backup
              image: my-backup-image:latest
          restartPolicy: OnFailure
Preventing overlapping runs
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 60

Gotchas

  • CronJobs schedule in the Kubernetes controller manager's timezone — historically UTC by default in most managed clusters, though newer Kubernetes versions (1.24+) support a `timeZone` field directly on the CronJob spec.
  • By default, `concurrencyPolicy: Allow` lets overlapping Job runs stack up if a previous run is still going — for anything non-idempotent, set it to `Forbid` (skip a run if the previous is still active) or `Replace` (kill the old one and start fresh).
  • A CronJob that's suspended, or whose controller was down at the scheduled time, can miss a run entirely if it falls outside `startingDeadlineSeconds` — Kubernetes doesn't guarantee catch-up execution the way anacron does on Linux.

Best Practices

  • Always set `concurrencyPolicy` explicitly rather than relying on the `Allow` default, especially for jobs that write to shared state.
  • Set `successfulJobsHistoryLimit` and `failedJobsHistoryLimit` to reasonable small numbers (e.g. 3 and 1) — Kubernetes keeps completed Job objects around by default, and they accumulate indefinitely otherwise.
  • Use `kubectl create job --from=cronjob/<name> manual-run` to trigger an ad-hoc run for testing without waiting for the schedule or editing the CronJob itself.

Frequently Asked Questions

Does Kubernetes CronJob support 6-field (with seconds) cron syntax?
No — the schedule field uses standard 5-field cron with no seconds field, same as Linux. The minimum granularity is one minute.
What timezone does a CronJob run in?
By default, the kube-controller-manager's timezone (commonly UTC on managed clusters). Kubernetes 1.24+ supports an explicit `timeZone` field on the CronJob spec (using IANA timezone names) to avoid this ambiguity.
How do I debug a CronJob that never runs?
Check `kubectl get cronjob` for the schedule and suspend status, `kubectl get jobs` to see if Jobs were even created, and `kubectl describe cronjob <name>` for events — a common cause is the controller being unable to create Jobs due to resource quotas or RBAC permissions.