Monitoring Kubernetes CronJobs

Updated November 2, 2026

A Kubernetes CronJob can stop doing its work without leaving a single failed pod behind. Pod-level alerts can’t see a job that was never started, so the reliable signal is the other way round: the job reports each successful run, and silence means something is wrong.

How CronJobs fail silently

A CronJob that reports

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "17 3 * * *"
  timeZone: "Europe/Berlin"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 600
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 3600
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: report
              image: registry.example.com/report:1.4.2
              env:
                - name: PING_URL
                  valueFrom:
                    secretKeyRef:
                      name: heartcron
                      key: nightly-report
              command: ["/bin/sh", "-c"]
              args:
                - |
                  wget -q -T 10 -O /dev/null "$PING_URL/start" || true
                  /app/report
                  code=$?
                  wget -q -T 10 -O /dev/null "$PING_URL/$code"
                  exit $code

What each part does:

Store the ping URL in a secret so it isn’t in the manifest:

kubectl create secret generic heartcron \
  --from-literal=nightly-report=https://ping.heartcron.com/<uuid>

Set up the check

Use the same cron expression and time zone as the CronJob. Make the grace period cover the starting deadline plus a normal run: with a 10-minute deadline and a 15-minute job, 30 to 40 minutes works. If a run is never started, finishes with an error or hangs past the grace period, you get an alert in Telegram, Slack, Discord or email.

When the alert comes

kubectl get cronjob nightly-report          # SUSPEND and LAST SCHEDULE
kubectl get jobs --sort-by=.metadata.creationTimestamp
kubectl describe cronjob nightly-report     # events, including missed starts
kubectl logs job/<job-name>

More guides