Job
A Job makes sure pods run and finish successfully: it retries until completions is reached, runs at most parallelism pods at once, and fails after backoffLimit errors. restartPolicy may only be Never or OnFailure (not Always). Finished pods stay so you can read their logs until you delete the Job (or set ttlSecondsAfterFinished).
CronJob
apiVersion: batch/v1 # batch/v1beta1 was removed in 1.25
kind: CronJob
metadata: { name: backup }
spec:
schedule: "0 2 * * *"
timeZone: "Asia/Ho_Chi_Minh" # without it, the kube-controller-manager time zone is used (usually UTC)
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
completions: 4
parallelism: 2
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
containers:
- { name: backup, image: busybox:1.36, command: ["date"] }
flowchart LR CJ["CronJob backup<br/>0 2 * * *"] -- "every day" --> J["Job backup-29001234"] J --> P1["pod (run 1)"] J --> P2["pod (run 2)"]
Operators
When no workload fits (for example running a database cluster: backups, failover), you define a CRD (Custom Resource Definition) and write your own controller that watches it — an Operator, usually written in Go, needing a ServiceAccount and RBAC to manage workloads.
| Command | Meaning |
|---|---|
kubectl create cronjob backup --image=busybox:1.36 --schedule="0 2 * * *" -- date |
Create a CronJob |
kubectl create job manual-backup --from=cronjob/backup |
Run a Job from the CronJob right now |
kubectl get jobs,cronjobs |
List Jobs and CronJobs |
More Job controls
| Field | Effect |
|---|---|
activeDeadlineSeconds |
Fail the Job if it runs longer than this |
ttlSecondsAfterFinished |
Delete the finished Job and its pods automatically |
completionMode: Indexed |
Give each pod an index (JOB_COMPLETION_INDEX) to split work into parts |
podFailurePolicy |
Fail fast on some exit codes, ignore others such as node disruptions |
suspend: true |
Create the Job without starting it yet |
Indexed Jobs suit "process shard 0 to 9" style batch work without an external queue.
CronJob behaviour to know
concurrencyPolicy:Allow(default) lets runs overlap,Forbidskips a run while the previous one is still going, andReplacestops the old run.startingDeadlineSecondsdecides how late a missed run may still start, for example after the controller was down.- Schedules use standard five-field cron syntax, so the cron knowledge from the Linux track applies directly.
- Make jobs idempotent: a CronJob can occasionally create two Jobs for one schedule, or a Job can retry after partly finishing.
Debugging batch work
kubectl get jobs shows completions such as 3/4; kubectl describe job lists pod failures and the backoff reason. kubectl logs job/manual-backup reads the logs of one of its pods. Failed pods are kept up to backoffLimit, which helps debugging but can clutter a namespace without a TTL.
Operators in practice
You rarely write an operator yourself at first; you install one. Popular examples: cert-manager (TLS certificates as Certificate resources), CloudNativePG or the Zalando operator for PostgreSQL clusters, Prometheus Operator (ServiceMonitor, PrometheusRule), and Strimzi for Kafka. Each adds CRDs and a controller that encodes the operations knowledge of experts: provisioning, backups, failover, and upgrades. OperatorHub.io lists many of them, and frameworks such as Kubebuilder and Operator SDK help when you do write one.