CKAD: Certified Kubernetes Application Developer Practice Exam
Validates ability to design, build, configure, and expose cloud-native applications on Kubernetes, and to deploy, observe, and maintain them.
Practice 447 exam-style CKAD questions with full answer explanations, then take timed mock exams that score like the real thing.
What the CKAD exam covers
- Application Design and Build90 questions
- Application Deployment88 questions
- Application Observability and Maintenance78 questions
- Application Environment, Configuration and Security116 questions
- Services and Networking75 questions
Free CKAD sample questions
A sample of 10 questions with answers and explanations. Sign up free to practice all 447.
-
You need to run a one-off batch job that processes a queue and must run to completion exactly 5 times, with up to 2 pods running in parallel. Which command-line flags create the correct Job?
- Akubectl create job q --image=worker && kubectl scale job q --replicas=5
- BCreate a Job manifest with spec.completions: 5 and spec.parallelism: 2Correct
- Ckubectl create job q --image=worker -- --completions=5 --parallelism=2
- Dkubectl run q --image=worker --restart=Always --completions=5
✓ Correct answer: BA Job uses spec.completions to define how many successful pod completions are required before the Job is considered done, and spec.parallelism to cap how many pods may run at the same time. Setting completions: 5 with parallelism: 2 means the Job will run pods until 5 finish successfully, never running more than 2 concurrently. These two fields together give precise control over both total work and concurrency, which is exactly what a queue-processing batch job needs.
Why the other options are wrong- Akubectl create job q --image=worker && kubectl scale job q --replicas=5 is incorrect because Jobs do not have a replicas field and kubectl scale does not operate on Jobs to set completions; parallelism for a Job is adjusted via kubectl scale --replicas, not completions, and this approach never sets completions to 5.
- Ckubectl create job q --image=worker -- --completions=5 --parallelism=2 is incorrect because everything after the -- is passed as arguments to the container's command, not interpreted as Job spec flags, so completions and parallelism remain at their defaults of 1.
- Dkubectl run q --image=worker --restart=Always --completions=5 is incorrect because --restart=Always creates a Deployment (not a Job), and kubectl run has no --completions flag, so this neither creates a Job nor sets completions.
-
You need a container to run a shell pipeline 'grep ERROR /var/log/app.log | wc -l' at startup. Which command form works?
- Acommand: ['grep','ERROR','/var/log/app.log','|','wc','-l']
- Bcommand: ['/bin/sh','-c','grep ERROR /var/log/app.log | wc -l']Correct
- Ccommand: ['grep ERROR /var/log/app.log | wc -l']
- Dargs: ['grep ERROR /var/log/app.log | wc -l']
✓ Correct answer: BShell features like the pipe (|) are interpreted by a shell, not by the container runtime, which executes command as a direct exec of an argument vector with no shell involved. By invoking /bin/sh -c and passing the entire pipeline as a single string argument, the shell parses and runs the pipe correctly. This is the standard pattern for running shell syntax in a container's command.
Why the other options are wrong- Acommand: ['grep','ERROR','/var/log/app.log','|','wc','-l'] is incorrect because without a shell the '|' is passed as a literal argument to grep rather than creating a pipeline, so the command fails or treats | as a filename.
- Ccommand: ['grep ERROR /var/log/app.log | wc -l'] is incorrect because the runtime would try to exec a single binary literally named 'grep ERROR /var/log/app.log | wc -l', which does not exist.
- Dargs: ['grep ERROR /var/log/app.log | wc -l'] is incorrect because args only supplies arguments to the existing ENTRYPOINT; without a shell as the entrypoint the pipeline is not interpreted, and a single string here is still not parsed as shell syntax.
-
A pod (or its Job) must be forcibly terminated if it runs longer than 100 seconds total, regardless of restarts. Which field enforces this wall-clock limit?
- Aspec.terminationGracePeriodSeconds: 100
- Bspec.backoffLimit: 100
- Cspec.activeDeadlineSeconds: 100Correct
- DlivenessProbe.timeoutSeconds: 100
✓ Correct answer: CThe spec.activeDeadlineSeconds field sets a hard wall-clock limit on how long a pod (or a Job's pods) may remain active; once the duration is exceeded, the pod is actively terminated and its status reflects the deadline being hit. Because it measures total elapsed active time, it bounds the run regardless of container restarts within that window. For a Job, this field can be set at the Job spec level to cap the overall runtime across retries.
Why the other options are wrong- Aspec.terminationGracePeriodSeconds: 100 is incorrect because that field only controls how long the kubelet waits after SIGTERM before SIGKILL during shutdown, not the maximum total runtime.
- Bspec.backoffLimit: 100 is incorrect because backoffLimit caps the number of retry attempts for a failing Job, not the elapsed wall-clock time.
- DlivenessProbe.timeoutSeconds: 100 is incorrect because timeoutSeconds only bounds how long a single liveness probe may take to respond, not the pod's total lifetime.
-
To let a load balancer deregister a pod before it stops receiving traffic, a common pattern in preStop is what?
- AScale the Deployment to 0
- BA short 'sleep' so the pod keeps serving while endpoints are removed, then the app shuts down gracefullyCorrect
- CDelete the Service
- DImmediately kill the process with SIGKILL
✓ Correct answer: BWhen a pod is deleted, endpoint removal (via EndpointSlice updates and kube-proxy/load-balancer reconfiguration) happens asynchronously and in parallel with the pod receiving SIGTERM. A preStop hook that runs a brief sleep keeps the container alive and serving in-flight requests during that window, so traffic stops arriving before the process exits, avoiding dropped connections. After the sleep, the container receives SIGTERM and shuts down gracefully within terminationGracePeriodSeconds. This race-mitigation pattern is the standard way to achieve zero-downtime pod termination.
Why the other options are wrong- AScale the Deployment to 0 is incorrect because that is a cluster-wide operation removing all replicas, not a per-pod hook for graceful deregistration during termination.
- CDelete the Service is incorrect because removing the Service would break all clients and is not part of an individual pod's shutdown flow.
- DImmediately kill the process with SIGKILL is incorrect because SIGKILL gives no chance to drain in-flight requests and defeats graceful termination, causing dropped connections.
-
A CronJob must skip a scheduled run if the previous run is still executing. Which setting?
- Aspec.concurrencyPolicy: Allow
- Bspec.suspend: true
- Cspec.concurrencyPolicy: Replace
- Dspec.concurrencyPolicy: ForbidCorrect
✓ Correct answer: DSetting concurrencyPolicy to Forbid tells the CronJob controller to skip a scheduled run entirely if the previous job is still active, preventing overlapping executions. This is exactly the behavior required when a new run must not start while the prior one is still executing. The skipped run is simply not created, and the controller waits for the next schedule. This is the standard guard against concurrent CronJob invocations.
Why the other options are wrong- Aspec.concurrencyPolicy: Allow is incorrect because Allow is the default and permits concurrent jobs to run simultaneously, which is the opposite of skipping.
- Bspec.suspend: true is incorrect because suspend pauses all future scheduling of the CronJob rather than conditionally skipping only when a prior run is active.
- Cspec.concurrencyPolicy: Replace is incorrect because Replace cancels the currently running job and starts a new one, instead of skipping the new run.
-
During rollouts, new pods sometimes flap Ready briefly and then crash, causing churn. You want a new pod to be considered available only after it has been Ready for 30s. Which field expresses this?
- Aspec.strategy.rollingUpdate.readyDelay: 30
- Bspec.minReadySeconds: 30Correct
- CreadinessProbe.initialDelaySeconds: 30
- Dspec.progressDeadlineSeconds: 30
✓ Correct answer: BThe minReadySeconds field specifies how long a newly created pod must be continuously Ready, without any of its containers crashing, before the Deployment counts it as available. Setting it to 30 means a pod that flaps Ready and then crashes within 30 seconds is never treated as available, which prevents the rollout from advancing prematurely and reduces churn. This adds a stabilization buffer on top of the readiness probe itself.
Why the other options are wrong- Aspec.strategy.rollingUpdate.readyDelay: 30 is incorrect because readyDelay is not a field in the rollingUpdate strategy.
- CreadinessProbe.initialDelaySeconds: 30 is incorrect because it only delays the first probe; once the probe passes the pod is immediately Ready, so it does not guarantee 30s of sustained readiness.
- Dspec.progressDeadlineSeconds: 30 is incorrect because it sets the deadline for the whole rollout to make progress before being marked failed, not a per-pod stabilization window.
-
You need to see the user-supplied values currently in effect for Helm release 'web'. Which command shows them?
- Ahelm values get web
- Bhelm inspect web --values
- Chelm get values webCorrect
- Dhelm show values web
✓ Correct answer: Chelm get values returns the user-supplied values currently in effect for a named release, exactly as they were provided via --set or --values at install or upgrade time. This reflects the overrides recorded in the release's stored manifest, not the chart's full default value set.
Why the other options are wrong- Ahelm values get web is incorrect because the subcommand order is wrong; the correct form is 'helm get values', with 'get' first.
- Bhelm inspect web --values is incorrect because 'inspect' (now 'show') operates on a chart, not a deployed release, and would not return the release's effective user values. helm show values web is incorrect because 'helm show values' prints the default values.yaml of a chart, not the user-supplied values of an installed release.
- DAdding -a/--all would additionally show computed defaults, but by default only user-supplied values are shown. It is the correct command to audit what customizations are active on the running release.
-
In CI you want 'helm upgrade --install' to block until the release's resources are Ready. Which flag adds that?
- A--block
- B--ready
- C--wait (optionally with --timeout)Correct
- D--sync
✓ Correct answer: CThe --wait flag instructs Helm to block until the release's resources (such as Deployments, StatefulSets, and Pods) report Ready, rather than returning immediately after the objects are submitted. Pairing it with --timeout bounds how long Helm will wait before declaring failure. This is the standard way in CI to ensure that 'helm upgrade --install' only succeeds once the workload is actually healthy. Without --wait, Helm considers the release successful as soon as the API server accepts the manifests.
Why the other options are wrong- A--block is incorrect because Helm has no --block flag; blocking-until-ready behavior is controlled by --wait.
- B--ready is incorrect because --ready is not a valid Helm flag.
- D--sync is incorrect because Helm provides no --sync flag for this purpose; readiness waiting is done with --wait.
-
A pod is CrashLoopBackOff and you suspect the previous container instance logged the cause before dying. Which command shows the prior instance's logs?
- Akubectl logs <pod> --previousCorrect
- Bkubectl get events --crashed
- Ckubectl describe pod <pod> --logs
- Dkubectl logs <pod> --last
✓ Correct answer: AWhen a container crashes and is restarted, the kubelet retains the log stream of the immediately preceding terminated instance. kubectl logs <pod> --previous (or -p) retrieves those prior-instance logs, which is essential for CrashLoopBackOff debugging because the current restarting container may have produced no useful output. This lets you see the error the container logged just before it died and triggered the back-off.
Why the other options are wrong- Bkubectl get events --crashed is incorrect because kubectl get events has no --crashed flag, and events summarize cluster activity rather than container stdout/stderr logs.
- Ckubectl describe pod <pod> --logs is incorrect because kubectl describe has no --logs flag; it shows status, conditions, and events but never the container log stream.
- Dkubectl logs <pod> --last is incorrect because no --last flag exists on kubectl logs; the flag for the previous instance is --previous/-p.
-
You want to list only pods that are currently in the Running phase. Which command uses a field selector to do this server-side?
- Akubectl get pods --field-selector=status.phase=RunningCorrect
- Bkubectl get pods --where phase=Running
- Ckubectl get pods --selector=status.phase=Running
- Dkubectl get pods --filter status.phase=Running
✓ Correct answer: Akubectl get pods --field-selector=status.phase=Running.
Why the other options are wrong- Bkubectl get pods --where phase=Running is incorrect because kubectl has no --where flag; it is SQL-like syntax that does not exist in the CLI.
- Ckubectl get pods --selector=status.phase=Running is incorrect because --selector (-l) matches label key/value pairs in metadata.labels, not status fields like status.phase. kubectl get pods --filter status.phase=Running is incorrect because there is no --filter flag in kubectl get.
- DThe --field-selector flag filters objects server-side based on resource field values, and status.phase is a supported selectable field for Pods. Passing status.phase=Running instructs the API server to return only Pods currently in the Running phase, reducing data transferred and avoiding client-side filtering. Field selectors are restricted to specific indexed fields per resource, and Pod phase is one of the officially supported ones. This is the idiomatic way to filter by phase without piping through grep.
CKAD practice exam FAQ
How many questions are in the CKAD practice exam on CertGrid?
CertGrid has 447 practice questions for CKAD: Certified Kubernetes Application Developer, covering 5 exam domains. The real CKAD exam has about 19 questions.
What is the passing score for CKAD?
The CKAD exam passing score is 660, and you have about 120 minutes to complete it. CertGrid scores your practice attempts the same way so you know when you are ready.
Are these official CKAD exam questions?
No. CertGrid is an independent practice platform. Questions are written to mirror the style and concepts of CKAD: Certified Kubernetes Application Developer, with full explanations, but they are not official or copied vendor exam items. They are original practice questions designed to help you genuinely learn the material.
Can I practice CKAD for free?
Yes. You can start practicing CKAD: Certified Kubernetes Application Developer for free with daily practice and sample questions. Paid plans unlock full timed exams, complete explanations, and domain analytics.