Back to Blog

CKAD Jobs and CronJobs: Complete Guide (2026)

Master Kubernetes Jobs and CronJobs for the CKAD exam. Hands-on with parallelism, completions, backoff limits, restart policies, and concurrency policies — with kubectl recipes and exam-style scenarios.

By Sailor Team , April 27, 2026

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

ScheduleMeaning
*/5 * * * *Every 5 minutes
0 */1 * * *Every hour at minute 0
0 2 * * *Daily at 2:00 AM
0 2 * * 0Weekly on Sunday at 2:00 AM
0 0 1 * *Monthly on the 1st at midnight
*/10 9-17 * * 1-5Every 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 hello that runs busybox and 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 count that 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 flaky should 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 report that 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-report immediately.”

k create job manual-run --from=cronjob/nightly-report

Variant 6: Suspend a CronJob

“Suspend CronJob cleanup without deleting it.”

k patch cj cleanup -p '{"spec":{"suspend":true}}'
k get cj cleanup

Common Mistakes (and How to Avoid Them)

  1. Setting restartPolicy: Always in a Job’s pod template. It’s invalid. Use OnFailure or Never.
  2. Confusing completions and parallelism. Completions = total runs needed. Parallelism = concurrent runs allowed.
  3. Forgetting to set restartPolicy at all. kubectl create job sets it automatically when using imperative form, but YAML-edited Jobs need it explicit.
  4. Using --schedule without quoting on shells that interpret *. Always quote: --schedule="*/5 * * * *".
  5. Editing the Job created by a CronJob. Edits are lost on the next scheduled run. Edit the CronJob’s jobTemplate instead.
  6. 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:

  1. Create a one-off Job that runs a script and prints output.
  2. Create a Job with completions=5, parallelism=2.
  3. Create a Job with backoffLimit=2 and a command that always fails; observe the Failed status.
  4. Create a CronJob that runs every minute, then suspend it.
  5. Create a CronJob with concurrencyPolicy=Forbid, then trigger a manual run.
  6. 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.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now