Create a CronJob with History Limits and a Deadline
Create a CronJob named backup-job in namespace default with the following specifications: Schedule: Run every 30 minutes (*/30 * * * *) Image: busybox:latest Container command: echo "Backup…
Live lab access
This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.
Create an account to continue →
On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Task
Create a CronJob named backup-job in namespace default with the following specifications:
- Schedule: Run every 30 minutes (
*/30 * * * *) - Image:
busybox:latest - Container command:
echo "Backup completed" - Set
successfulJobsHistoryLimit: 3 - Set
failedJobsHistoryLimit: 2 - Set
activeDeadlineSeconds: 300 - Use
restartPolicy: Never
Tip: Use kubectl explain cronjob.spec to find the correct field names.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
CronJobs are three objects deep: put each field at the right level
A CronJob does not run containers. It creates a Job on a schedule, and the Job creates Pods. Each layer owns different settings, and most CronJob mistakes on the exam are a correct field placed one level too high or too low. kubectl's default strict validation rejects a field that does not exist at that level, but some names, such as activeDeadlineSeconds, exist at two levels and mean different things.
CronJob .spec schedule, timeZone, concurrencyPolicy, startingDeadlineSeconds,
| successfulJobsHistoryLimit, failedJobsHistoryLimit, suspend
'-- jobTemplate.spec activeDeadlineSeconds, backoffLimit
'-- template.spec containers, restartPolicy (Never or OnFailure)
1. Read the schedule before you write it
The schedule has five fields: minute, hour, day of month, month, day of week (0 is Sunday). 15 2 * * 1-5 means 02:15 on weekdays. A step after an asterisk repeats through the whole range, so */20 in the minute field fires at :00, :20 and :40. Macros such as @hourly and @daily also work. Without .spec.timeZone, the schedule follows the kube-controller-manager's local time zone; putting TZ= or CRON_TZ= inside the schedule string is rejected by validation.
2. A manifest with every layer visible
apiVersion: batch/v1
kind: CronJob
metadata:
name: ledger-report
namespace: prepium-tutorial
spec:
schedule: "15 2 * * 1-5"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 600
failedJobsHistoryLimit: 4
jobTemplate:
spec:
activeDeadlineSeconds: 120
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: busybox:1.36
command: ["sh", "-c", "date; echo ledger totals ready"]
What each choice does:
concurrencyPolicy: Forbidskips a new run if the previous Job is still going. The default,Allow, lets runs overlap;Replacecancels the running Job and starts the new one.startingDeadlineSecondsis about starting late: if the controller could not create the Job within 600 seconds of its slot, that run is skipped and counted as failed. Unset means no deadline.activeDeadlineSecondson the Job is about running long: after 120 seconds, however many Pods were tried, running Pods are terminated and the Job fails with reasonDeadlineExceeded. It beatsbackoffLimitif it is hit first.- History limits default to 3 successful and 1 failed Job. Only the failed one is overridden here, so successful runs still keep 3.
restartPolicymust beNeverorOnFailure. WithOnFailurethe kubelet re-runs the container inside the same Pod; withNeverevery failure leaves a failed Pod behind and the Job controller creates a fresh one, which keeps logs of each attempt.
3. Test it now instead of waiting until 02:15
kubectl create namespace prepium-tutorial
kubectl apply -f ledger-report.yaml
kubectl create job ledger-manual --from=cronjob/ledger-report -n prepium-tutorial
kubectl -n prepium-tutorial wait --for=condition=Complete job/ledger-manual --timeout=90s
kubectl -n prepium-tutorial logs job/ledger-manual
--from=cronjob/ copies the CronJob's job template into a one-off Job, so it proves the Pod spec, command and image without touching the schedule. You can also generate a starting manifest with kubectl create cronjob NAME --image=... --schedule="..." --restart=OnFailure --dry-run=client -o yaml -- COMMAND and add the remaining fields by hand.
4. Confirm the stored values
kubectl -n prepium-tutorial get cronjob ledger-report -o yaml
kubectl explain cronjob.spec.jobTemplate.spec.activeDeadlineSeconds
Read back the YAML and check that defaults were filled in where you left fields out. kubectl explain with the full path settles any doubt about which level a field belongs to.
Common mistakes
activeDeadlineSecondsplaced in the Pod template instead of the Job spec. It is accepted, but it limits each Pod, not the Job.restartPolicyleft out of a hand-written template, or set toAlways. Jobs only accept the two values above, so the object is rejected.- Confusing the two deadlines:
startingDeadlineSecondsnever stops a slow Job, andactiveDeadlineSecondsnever rescues a late start. - A CronJob name over 52 characters. The controller appends 11 characters to build Job names, so longer names are not allowed.
| Example check | Evidence |
|---|---|
| Schedule is what you meant | .spec.schedule, read field by field |
| Job-level limits in the right place | .spec.jobTemplate.spec.activeDeadlineSeconds set |
| History retention | Both history limits present in the stored object |
| Pod spec works | A Job created --from=cronjob/ completes and logs the expected line |
Cleanup: kubectl delete namespace prepium-tutorial. References: CronJob, Jobs, kubectl create job. Next, try choosing the right workload controller.
Video walkthrough: CKAD Exam Question 2 - CronJob on YouTube. It shows the full solution, so try the task first.
What this tests
Define pods and multi-container patterns, build container images, and run jobs and cronjobs. On the CKAD exam, Application Design and Build tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.
Practice it for real
The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.