Jobs and CronJobs are tested on most CKAD exams — usually one direct question plus one buried inside a multi-step task. They’re easy points if you’ve practiced the imperative commands and understand the four critical fields: completions, parallelism, backoffLimit, and restartPolicy. Get one of those wrong and the question fails silently.
This guide covers every Job and CronJob pattern the CKAD tests, with copy-paste kubectl commands, YAML templates, and the timing fields that trip people up.
What a Job Does (and Why Pods Aren’t Enough)
A Pod runs containers; a Job runs Pods to completion. When the Pod’s containers exit successfully, the Job is done. If a container exits with a non-zero code, the Job retries based on its policies.
Jobs are the right resource when you want:
- A one-time data migration
- A batch processing task
- A scheduled report (via CronJob)
- A backup or maintenance task
If you don’t need “exit successfully and stop,” use a Deployment instead.
Creating a Job: Imperative First
# Simple Job
k create job pi --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'
# Generate Job YAML for editing
k create job pi --image=perl --dry-run=client -o yaml -- perl -Mbignum=bpi -wle 'print bpi(2000)' > job.yaml
# Job from a CronJob template (manual run)
k create job manual-backup --from=cronjob/nightly-backup
The -- separator marks where the command begins. Anything after -- is treated as the container’s command and args.
The Four Fields That Define Job Behavior
apiVersion: batch/v1
kind: Job
metadata:
name: my-job
spec:
completions: 5 # how many Pods must complete successfully
parallelism: 2 # how many Pods can run at once
backoffLimit: 3 # max retries before Job is marked Failed
activeDeadlineSeconds: 600 # max wall-clock seconds for the whole Job
template:
spec:
restartPolicy: OnFailure # or Never; Always is invalid
containers:
- name: worker
image: busybox
command: ['sh', '-c', 'echo Hello && sleep 3']
Memorize the difference between each field — the exam tests them by varying values:
completions
How many Pods must finish successfully. With completions: 5, the Job creates Pods until 5 of them have run to completion (exit code 0).
parallelism
How many Pods can run at once. With parallelism: 2 and completions: 5, two Pods run concurrently until five have completed.
backoffLimit
How many failed Pod attempts before the Job is marked Failed. Default is 6.
restartPolicy
Inside a Job’s pod template, restartPolicy must be OnFailure or Never. Always (the default for regular Pods) is invalid — kubectl will reject it.
OnFailure: a failed container restarts in the same Pod (counts toward backoffLimit per container restart).Never: a failed Pod is replaced by a new Pod (counts toward backoffLimit per Pod).
The exam often asks you to set restartPolicy: Never explicitly.
Job Patterns
Pattern 1: Single Run
spec:
completions: 1
parallelism: 1
template:
spec:
restartPolicy: Never
containers:
- name: task
image: busybox
command: ['echo', 'hello']
The default if you don’t set completions and parallelism. Run once, done.
Pattern 2: Fixed Completion Count (sequential)
spec:
completions: 5
parallelism: 1
template:
spec:
restartPolicy: Never
# ...
Five Pods run sequentially. Useful for “process this batch of work” patterns.
Pattern 3: Parallel with Fixed Completion Count
spec:
completions: 10
parallelism: 3
template:
spec:
restartPolicy: Never
# ...
Three Pods run at once until ten have completed.
Pattern 4: Parallel with Work Queue
spec:
parallelism: 3
# NO completions — Pods coordinate via an external queue
template:
spec:
restartPolicy: Never
# ...
When completions is omitted, the Job runs Pods in parallel and considers itself done when one Pod exits successfully. Used with external queues like Redis or RabbitMQ. Less common on the exam.
Inspecting and Cleaning Up Jobs
# List Jobs
k get jobs
# Detailed Job status
k describe job <name>
# View Pod logs (Job creates Pods named <job-name>-xxx)
k logs job/<name>
k logs job/<name> --tail=100
# Delete a Job (also deletes its Pods)
k delete job <name>
kubectl logs job/<name> automatically picks the most recent Pod from the Job. If the Job has multiple Pods, you may need to list them first:
k get pods -l job-name=<name>
k logs <pod-name>
ttlSecondsAfterFinished: Auto-Delete Completed Jobs
Production Jobs accumulate over time. Set this field to auto-clean:
spec:
ttlSecondsAfterFinished: 100 # delete the Job 100 seconds after completion
The CKAD occasionally tests this. Recognize the trigger phrase: “the Job and its Pods should be cleaned up automatically.”
activeDeadlineSeconds: Hard Time Limit
spec:
activeDeadlineSeconds: 600 # Job and its Pods are killed after 10 minutes total
This applies to the entire Job, not individual Pods. If the Job hasn’t finished within 600 seconds, all Pods are terminated and the Job is marked Failed.
Note: there’s also spec.template.spec.activeDeadlineSeconds for individual Pods. They’re different fields.
CronJobs: Jobs on a Schedule
A CronJob creates a Job at scheduled intervals.
# Imperative
k create cj backup --image=busybox --schedule="*/5 * * * *" -- /bin/sh -c 'date'
# Generate YAML
k create cj backup --image=busybox --schedule="*/5 * * * *" \
--dry-run=client -o yaml > cj.yaml -- /bin/sh -c 'date'
The --schedule flag uses standard cron syntax: minute hour day month day-of-week.
CronJob YAML Template
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup
spec:
schedule: "*/5 * * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
concurrencyPolicy: Allow
startingDeadlineSeconds: 60
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: busybox
command: ['sh', '-c', 'echo backup at $(date)']
The jobTemplate wraps a Job spec, which itself contains a Pod template. Three levels of nesting — make sure your indentation is correct.
Cron Schedule Quick Reference
| Schedule | Meaning |
|---|---|
*/5 * * * * | Every 5 minutes |
0 */1 * * * | Every hour at minute 0 |
0 2 * * * | Daily at 2:00 AM |
0 2 * * 0 | Weekly on Sunday at 2:00 AM |
0 0 1 * * | Monthly on the 1st at midnight |
*/10 9-17 * * 1-5 | Every 10 minutes, 9 AM-5 PM, weekdays |
The CKAD usually uses simple schedules. If you see anything complex, it’s testing your reading of cron syntax.
Concurrency Policy: How CronJobs Handle Overlap
spec:
concurrencyPolicy: Allow # default
Three options:
- Allow (default): a new Job starts even if the previous one is still running. Both run concurrently.
- Forbid: skip the new Job if the previous one is still running.
- Replace: kill the running Job and start a new one.
The exam tests recognizing which policy fits a scenario:
- “Skip the next run if the current one is still going” → Forbid
- “Always replace with the latest schedule” → Replace
- “Default” → Allow
Suspending and Resuming a CronJob
# Suspend (stop creating new Jobs but keep running ones)
k patch cj backup -p '{"spec":{"suspend":true}}'
# Resume
k patch cj backup -p '{"spec":{"suspend":false}}'
# Verify
k get cj backup
# SUSPEND column shows True/False
Useful when a question says “temporarily disable this CronJob without deleting it.”
startingDeadlineSeconds: Skip Missed Runs
spec:
startingDeadlineSeconds: 60
If the controller can’t start a Job within 60 seconds of the scheduled time (e.g., because the cluster was busy), the Job is skipped instead of running late.
Job and CronJob History Limits
spec:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
Keep the last 3 successful Jobs and 1 failed Job. Older ones are auto-deleted. Without this, completed Jobs pile up indefinitely.
Common Job/CronJob Question Variants
Variant 1: Create a Simple Job That Prints a Message
“Create a Job named
hellothat runsbusyboxand prints ‘hello world’ once.”
k create job hello --image=busybox -- echo hello world
k logs job/hello
Variant 2: Job That Runs Five Times Sequentially
“Create a Job named
countthat runs five Pods sequentially, each printing the date.”
apiVersion: batch/v1
kind: Job
metadata:
name: count
spec:
completions: 5
parallelism: 1
template:
spec:
restartPolicy: Never
containers:
- name: count
image: busybox
command: ['sh', '-c', 'date']
Variant 3: Job with Backoff and Deadline
“Job
flakyshould retry up to 3 times and be killed after 120 seconds total.”
spec:
backoffLimit: 3
activeDeadlineSeconds: 120
template:
spec:
restartPolicy: Never
# ...
Variant 4: CronJob Every Hour, Forbid Overlap
“Create a CronJob
reportthat runs every hour, skipping if the previous run is still in progress.”
k create cj report --image=busybox --schedule="0 * * * *" \
--dry-run=client -o yaml -- /bin/sh -c 'echo report' > cj.yaml
Then edit cj.yaml to add concurrencyPolicy: Forbid:
spec:
schedule: "0 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
# ...
Variant 5: Manually Trigger a CronJob
“Trigger a manual run of CronJob
nightly-reportimmediately.”
k create job manual-run --from=cronjob/nightly-report
Variant 6: Suspend a CronJob
“Suspend CronJob
cleanupwithout deleting it.”
k patch cj cleanup -p '{"spec":{"suspend":true}}'
k get cj cleanup
Common Mistakes (and How to Avoid Them)
- Setting
restartPolicy: Alwaysin a Job’s pod template. It’s invalid. UseOnFailureorNever. - Confusing
completionsandparallelism. Completions = total runs needed. Parallelism = concurrent runs allowed. - Forgetting to set
restartPolicyat all. kubectl create job sets it automatically when using imperative form, but YAML-edited Jobs need it explicit. - Using
--schedulewithout quoting on shells that interpret*. Always quote:--schedule="*/5 * * * *". - Editing the Job created by a CronJob. Edits are lost on the next scheduled run. Edit the CronJob’s
jobTemplateinstead. - Wrong indentation in
jobTemplate.spec.template.spec. Three nested levels — count carefully.
How to Practice
Drill these on a kind cluster, each under a 4-minute timer:
- Create a one-off Job that runs a script and prints output.
- Create a Job with completions=5, parallelism=2.
- Create a Job with backoffLimit=2 and a command that always fails; observe the Failed status.
- Create a CronJob that runs every minute, then suspend it.
- Create a CronJob with concurrencyPolicy=Forbid, then trigger a manual run.
- Set ttlSecondsAfterFinished on a Job and watch it auto-clean.
Validate Your Speed Under Exam Conditions
The CKAD tests Jobs and CronJobs in chained scenarios — create a Job, verify its output, modify a CronJob, suspend, restart. Take a full-length scored simulator with our CKAD Mock Exam Bundle — every simulator includes Job and CronJob questions in realistic context.
Frequently Asked Questions
Q: How many Job/CronJob questions are on the CKAD? A: Typically 1-2 direct questions plus occasional appearances inside other tasks. Total weight: ~5-10%.
Q: What’s the default restartPolicy for Pods inside a Job?
A: There is no default — you must set OnFailure or Never. Always is invalid.
Q: Can a Job run forever?
A: Without completions, a Job runs Pods until one succeeds. To run forever, use a Deployment, not a Job.
Q: How do I view logs from a completed Job?
A: kubectl logs job/<name> for the most recent Pod, or list Pods with kubectl get pods -l job-name=<name> and view individual Pod logs.
Q: What’s the difference between activeDeadlineSeconds on a Job vs on a Pod template?
A: Job-level applies to the whole Job (across retries). Pod-level applies to each individual Pod.
Q: Can a CronJob trigger a Job that already completed?
A: No. Each scheduled execution creates a new Job. Use kubectl create job --from=cronjob/<name> to trigger a manual run.
Q: Why don’t I see logs after my Job finishes?
A: The Pod still exists (until garbage collection or ttlSecondsAfterFinished). If you’ve already deleted it, the logs are gone. Add ttlSecondsAfterFinished carefully.
Ready to make Jobs and CronJobs automatic points on your CKAD? Run a scored full-length simulator with our CKAD Mock Exam Bundle and find out exactly where you stand.