Kubernetes cookbook · Intermediate
Run scheduled jobs reliably with CronJobs
Nightly jobs sometimes run twice, overlap, or silently stop running.
Approach
Forbid overlapping runs, set a time zone and a starting deadline, keep history for debugging, bound retries and run time, and make the job idempotent.
Solution
apiVersion: batch/v1
kind: CronJob
metadata: {name: nightly-report}
spec:
schedule: "0 2 * * *"
timeZone: Europe/Berlin
concurrencyPolicy: Forbid
startingDeadlineSeconds: 600
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 3600
ttlSecondsAfterFinished: 86400
template:
spec:
restartPolicy: Never
containers:
- name: report
image: ghcr.io/acme/report:2.1.0
args: ["--date", "yesterday"]
Pitfalls
- Jobs that aren't idempotent: retries and rare double runs corrupt data.
- No alert when a CronJob stops succeeding (monitor last successful run time).
Variations
- Use a lock (database advisory lock) if even rare concurrent runs are unacceptable.
- Workflow engines (Argo Workflows) for multi-step pipelines.
Further reading: CronJob
Reference: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
More Kubernetes recipes
- Autoscale a Deployment on CPU and memory
- Debug a distroless pod with an ephemeral container
- Default-deny network policies that keep DNS working
- Enforce the restricted Pod Security Standard
- Expose a service over HTTPS with automatic certificates
- Give a CI pipeline least-privilege deploy access
- Handle SIGTERM in your application for Kubernetes
- Manage dev, staging and prod with Kustomize overlays