Troubleshooting · Kubernetes

Kubernetes CronJob not running? Diagnose it fast

Why a Kubernetes CronJob doesn't run — suspended, timezone, concurrency policy, failed pods, missed deadlines — and how to fix each.

A Kubernetes CronJob adds its own failure modes on top of plain cron. Walk these in order.

1. Is it suspended?

A suspended CronJob creates no Jobs at all:

kubectl get cronjob my-job -o jsonpath='{.spec.suspend}'   # true = suspended
kubectl patch cronjob my-job -p '{"spec":{"suspend":false}}'

2. Check the schedule and timezone

By default the schedule is evaluated in the kube-controller-manager’s timezone (historically UTC). Since Kubernetes 1.27 you can set it explicitly:

spec:
  schedule: "0 2 * * *"
  timeZone: "Europe/Berlin"

3. Look at recent Jobs and events

kubectl get jobs --selector=job-name --sort-by=.metadata.creationTimestamp
kubectl describe cronjob my-job        # events: "Created job", "Missed schedule"

“Cannot determine if job needs to be started… missed start window” points at problem 4.

4. startingDeadlineSeconds and missed schedules

If the controller is briefly down and more than 100 schedules are missed, the CronJob stops scheduling entirely until you fix it. Set a deadline so a missed slot is skipped cleanly instead:

spec:
  startingDeadlineSeconds: 200
  concurrencyPolicy: Forbid     # don't pile up overlapping runs

5. The pod runs but fails

A created Job whose pod errors won’t always be obvious. Inspect it:

kubectl logs job/<job-name>
kubectl describe pod <pod>      # image pull errors, OOMKilled, config issues

Set backoffLimit and failedJobsHistoryLimit so failures are retained and visible.

The deeper problem: a green CronJob can still be doing nothing

kubectl get cronjob showing your job doesn’t mean work is happening — pods can fail silently, deadlines can be missed, a bad deploy can suspend it. Cluster-level noise often buries these.

Have the job’s container ping a heartbeat on success. If Jobs stop completing — for any reason — the ping is missed and you’re alerted, independent of the cluster’s own monitoring:

# final step of your container command
curl -fsS https://ping.steadycron.com/<your-ping-token>