← Road to Kubestronaut

KUBESTRONAUT · 2-HOUR PERFORMANCE-BASED · CURRENT CURRICULUM

CKAD — The Certified Kubernetes Application Developer Cheatsheet.

kubernetesckadapplication-deliverykubectlexam-prep

Road to Kubestronaut · Certification 4

CKAD: Applications

Guide 4 of 5

CKAD is a 2-hour, performance-based exam on Kubernetes v1.35. You solve application tasks in a terminal: no cluster installation, but relentless resource creation, editing, validation and debugging. Current domains: Application Design & Build 20% · Deployment 20% · Observability & Maintenance 15% · Environment, Configuration & Security 25% · Services & Networking 20%. Generate YAML, edit only what the task needs, apply, and verify.

0. First-minute setup and the task loop

alias k=kubectl
export do="--dry-run=client -o yaml"
source <(kubectl completion bash)
complete -o default -F __start_kubectl k

# every task: context → namespace → generate/edit → apply → verify
k config use-context <named-context>
k config set-context --current --namespace=<namespace>
k get ns

# useful editor defaults
cat <<'EOF' >> ~/.vimrc
set expandtab tabstop=2 shiftwidth=2 number autoindent
EOF
verify the contractDo not stop when kubectl apply succeeds. Check the exact requested name, namespace, image, labels, ports, rollout, readiness and output file. API acceptance is not task completion.

1. kubectl generation and fast editing

k run app --image=nginx:1.27 $do > pod.yaml
k create deploy web --image=nginx:1.27 --replicas=3 $do > deploy.yaml
k create job report --image=busybox:1.36 $do -- sh -c 'date; echo done' > job.yaml
k create cronjob cleanup --image=busybox:1.36 --schedule='*/5 * * * *' \
  $do -- sh -c 'rm -rf /tmp/cache/*' > cron.yaml
k create cm app-config --from-literal=MODE=prod $do > cm.yaml
k create secret generic db --from-literal=password='change-me' $do > secret.yaml
k create service clusterip web --tcp=80:8080 $do > svc.yaml

k explain pod.spec.containers --recursive
k apply -f deploy.yaml
k get deploy,pods,svc -o wide
k diff -f deploy.yaml

Use imperative generation as a schema-safe starting point. When a field is difficult to generate—probes, affinity, security context, volumes—use kubectl explain or an allowed documentation example, then adapt it.

2. Application Design and Build (20%)

Choose the right workload

RequirementResourceKey behavior
Stateless long-running replicasDeploymentRolling updates and rollback
One Pod on each nodeDaemonSetNode-local agents
Finite batch executionJobCompletion, retries, parallelism
Scheduled batch executionCronJobCreates Jobs on schedule
Stable identity/storageStatefulSetOrdered Pods and volume claims

Container images and commands

FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER 10001
ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8080"]

In a PodSpec, command overrides image ENTRYPOINT and args overrides CMD. Prefer exec-form arrays. Pin a tag or digest required by the task; changing a Deployment's Pod template triggers a rollout.

Multi-container patterns

PatternUseLifecycle
InitPrecondition, migration, file generationRuns to completion before app containers, sequentially
SidecarProxy, log/telemetry helper, file synchronizationRuns alongside the app; shares Pod network/volumes
AdapterNormalizes app output for another consumerCompanion container transforms shared data
AmbassadorLocal proxy to an external dependencyApp calls localhost; proxy owns remote connection logic
spec:
  initContainers:
  - name: prepare
    image: busybox:1.36
    command: ["sh", "-c", "echo ready > /work/status"]
    volumeMounts: [{ name: work, mountPath: /work }]
  containers:
  - name: app
    image: nginx:1.27
    volumeMounts: [{ name: work, mountPath: /usr/share/nginx/html }]
  - name: sidecar
    image: busybox:1.36
    command: ["sh", "-c", "tail -F /work/status"]
    volumeMounts: [{ name: work, mountPath: /work }]
  volumes: [{ name: work, emptyDir: {} }]

Ephemeral and persistent volumes

  • emptyDir: created for the Pod and removed with it; containers in the Pod share it.
  • configMap/secret: project configuration as files.
  • persistentVolumeClaim: attach durable storage through a PVC.
  • projected: combine several sources such as Secret, ConfigMap and service-account token.

3. Application Deployment (20%)

Deployments, rollouts and rollback

k create deploy web --image=nginx:1.26 --replicas=4
k set image deploy/web nginx=nginx:1.27 --record=false
k rollout status deploy/web
k rollout history deploy/web
k rollout undo deploy/web
k scale deploy/web --replicas=6
k patch deploy web -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'

maxSurge allows extra Pods during a rolling update; maxUnavailable limits unavailable desired replicas. A rollout stalls when new Pods never become Ready.

Blue/green and canary with primitives

  • Blue/green: two Deployments with different version labels; switch a Service selector after green is verified.
  • Canary: stable and canary Deployments share the Service's selector; replica ratio approximates traffic percentage.
  • Rolling: one Deployment progressively replaces its ReplicaSet.
# blue/green cutover: Service changes version selector
k patch svc web -p '{"spec":{"selector":{"app":"web","version":"green"}}}'
k get endpointslices -l kubernetes.io/service-name=web

Helm and Kustomize

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo nginx
helm install edge bitnami/nginx -n app --create-namespace --set replicaCount=2
helm list -A
helm upgrade edge bitnami/nginx -n app --set replicaCount=3
helm rollback edge 1 -n app
helm uninstall edge -n app

k kustomize overlays/prod              # render and inspect
k apply -k overlays/prod                # apply the overlay
render before applyWith Helm or Kustomize, inspect the rendered objects and target namespace. A successful package install can still create the wrong replicas, image, labels or Service values.

4. Observability and Maintenance (15%)

Startup, readiness and liveness

ProbeFailure effectQuestion it answers
startupBlocks liveness/readiness until success; restart on repeated failureHas the slow app finished starting?
readinessRemoves Pod from Service endpointsShould this Pod receive traffic now?
livenessRestarts the containerIs the process stuck and unable to recover?
startupProbe:
  httpGet: { path: /health/startup, port: 8080 }
  failureThreshold: 30
  periodSeconds: 2
readinessProbe:
  httpGet: { path: /health/ready, port: 8080 }
  periodSeconds: 5
livenessProbe:
  httpGet: { path: /health/live, port: 8080 }
  periodSeconds: 10
readiness is traffic, liveness is restartDo not use liveness to wait for a slow startup—use a startup probe. An aggressive liveness check creates a restart loop and makes recovery worse.

Logs, events and ephemeral debugging

k describe pod app
k logs app -c api
k logs app -c api --previous
k logs deploy/web --all-containers --tail=100
k get events --sort-by=.lastTimestamp
k exec -it app -c api -- sh
k debug -it app --image=busybox:1.36 --target=api
k top pods -A
k get pod app -o jsonpath='{.status.containerStatuses[*].state}'

Debug from outside in: object status → events → logs → effective spec → in-container checks → Service endpoints and policy. For API removals, use kubectl explain, current documentation and tools such as kubectl convert if installed; do not keep deprecated versions merely because old YAML still looks familiar.

5. Environment, Configuration and Security (25%)

ConfigMaps and Secrets

envFrom:
- configMapRef: { name: app-config }
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef: { name: db, key: password }
volumeMounts:
- { name: settings, mountPath: /etc/app, readOnly: true }
volumes:
- name: settings
  configMap:
    name: app-config
    items: [{ key: config.yaml, path: config.yaml }]

Environment values are captured when the container starts. Mounted ConfigMap/Secret volumes can update eventually, but the application must reload them. A subPath mount does not receive those updates.

Resources, quotas and limits

resources:
  requests: { cpu: 100m, memory: 128Mi }
  limits: { cpu: 500m, memory: 256Mi }
  • Scheduler places using requests. CPU limit causes throttling; memory limit can cause OOM termination.
  • ResourceQuota caps aggregate namespace consumption/object counts.
  • LimitRange supplies or constrains per-object defaults/min/max.

ServiceAccounts, RBAC and admission

k create sa reporter -n team
k create role pod-reader --verb=get,list,watch --resource=pods -n team
k create rolebinding reporter-read --role=pod-reader \
  --serviceaccount=team:reporter -n team
k auth can-i list pods --as=system:serviceaccount:team:reporter -n team

Authentication establishes identity, authorization evaluates permission, and admission validates/mutates the requested object. A ServiceAccount is a workload identity. Set automountServiceAccountToken: false when the Pod does not need API credentials.

Application security context

spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile: { type: RuntimeDefault }
  containers:
  - name: app
    image: example/app:1.4
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities: { drop: ["ALL"] }

Pod-level context supplies defaults; container-level fields can be more specific. Dropping capabilities, disallowing privilege escalation and running as non-root are different controls—apply the exact combination requested.

CRDs and Operators

k get crd
k api-resources | grep -i <kind>
k explain <resource>.spec
k get <custom-resource> -A
k describe <custom-resource> <name>

A CRD extends the API with a new resource kind. An Operator pairs custom resources with a controller that reconciles domain-specific lifecycle. Discover the actual API group and schema before writing a custom resource.

6. Services and Networking (20%)

Services and endpoint troubleshooting

k expose deploy web --port=80 --target-port=8080
k get svc web -o yaml
k get endpointslices -l kubernetes.io/service-name=web
k get pods --show-labels
k run curl --image=curlimages/curl --rm -it --restart=Never -- \
  curl -sS http://web:80/health

port is the Service port; targetPort is the backend Pod port. The Service selector must match Pod labels, and readiness must pass before endpoints receive traffic.

Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: web }
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: { name: web, port: { number: 80 } }

An Ingress resource needs an installed Ingress controller. Check class, host/path, Service name and Service port—not the container port.

NetworkPolicy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: api-from-web, namespace: team }
spec:
  podSelector: { matchLabels: { app: api } }
  policyTypes: [Ingress]
  ingress:
  - from:
    - podSelector: { matchLabels: { app: web } }
    ports: [{ protocol: TCP, port: 8080 }]
namespace scope mattersA podSelector in a peer selects Pods in the policy's namespace unless combined with a namespaceSelector. Policies are additive and require CNI enforcement.

7. High-yield manifest patterns

Jobs and CronJobs

apiVersion: batch/v1
kind: Job
metadata: { name: report }
spec:
  completions: 6
  parallelism: 2
  backoffLimit: 3
  activeDeadlineSeconds: 300
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: report
        image: example/report:1.2

completions is successful work items; parallelism is concurrent Pods; backoffLimit bounds retries. CronJobs add schedule, concurrencyPolicy, history limits and startingDeadlineSeconds. To test a CronJob immediately, create a one-off Job from it.

k create job test-run --from=cronjob/cleanup
k get jobs,pods
k logs job/test-run

Availability, autoscaling and disruption

k autoscale deploy web --min=2 --max=10 --cpu-percent=70
k get hpa web
k top pods -l app=web
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata: { name: web-pdb }
spec:
  minAvailable: 2
  selector: { matchLabels: { app: web } }

An HPA changes replica count from metrics; it needs meaningful requests and a metrics source. A PodDisruptionBudget limits voluntary disruptions such as drain, not crashes or node failure. minAvailable and maxUnavailable are alternative ways to express the budget.

PVC consumption

apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: data }
spec:
  accessModes: [ReadWriteOnce]
  resources: { requests: { storage: 2Gi } }
---
spec:
  containers:
  - name: app
    volumeMounts: [{ name: data, mountPath: /var/lib/app }]
  volumes:
  - name: data
    persistentVolumeClaim: { claimName: data }

If a Pod is Pending, inspect the PVC too. StorageClass, access mode, requested size, topology and provisioning events must be satisfiable.

Output, JSONPath and patching

k get pods -o custom-columns='NAME:.metadata.name,NODE:.spec.nodeName,IMAGE:.spec.containers[*].image'
k get pods --sort-by=.metadata.creationTimestamp
k get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
k patch deploy web --type=merge -p '{"spec":{"replicas":4}}'
k label pod app tier=frontend --overwrite
k annotate deploy web owner=platform --overwrite

When the task asks you to write output to a file, redirect the exact requested format and inspect the file. JSONPath quoting mistakes are common; test on the terminal before redirecting.

8. Status-to-action playbook

SymptomCheck firstLikely fix
PendingEvents, requests, taints, affinity, PVCMake placement/storage constraints satisfiable
ImagePullBackOffImage spelling/tag and pull secretCorrect image or registry credentials
CrashLoopBackOfflogs --previous, command, config, probesRepair process input or probe
Running but not ReadyReadiness path/port and app healthFix readiness contract or dependency
Service unreachableEndpointSlice, labels, readiness, targetPortRepair selector/port/policy
Rollout stuckNew ReplicaSet Pods and progress eventsFix new template or undo rollout

9. Common mistakes and final study order

  • Working in the wrong context or namespace.
  • Creating a Pod when the task asks for a Deployment, Job or CronJob.
  • Changing labels without updating selectors.
  • Confusing container port, Service port and targetPort.
  • Using liveness where readiness or startup is required.
  • Forgetting the container name for logs/exec in multi-container Pods.
  • Expecting a ConfigMap environment variable to hot-reload.
  • Writing a NetworkPolicy peer in the wrong namespace scope.
  • Applying Helm/Kustomize output without inspecting the render.
  • Leaving the object accepted but functionally broken.

Practice order: imperative generation → workloads and multi-container Pods → rollouts and deployment strategies → probes/logs/debug → configuration/resources/security → Services/Ingress/NetworkPolicy → timed mixed labs. Aim to complete ordinary object tasks in 2–4 minutes so debugging tasks can consume the time they deserve.

Official sources & freshness

This guide was checked against the official Linux Foundation exam page and CNCF curriculum on 19 July 2026. Exam versions and policies can change; re-check the source page before booking.

← prev: CKA next: CKS →
© cvam — written in plaintext, served warm