Certified Kubernetes Administrator (CKA) Study Guide
Issuing body: Cloud Native Computing Foundation (CNCF) / Linux Foundation Jurisdiction: Global (vendor-neutral — not a legal license to practice) Level: Intermediate Prerequisites: None formal. Real comfort with Linux CLI, YAML, and basic networking is assumed. (Source: catalogue record software-cert-007.) Renewal: Valid 2 years; retake the exam to renew.
1. What this exam is
CKA is 100% hands-on: you SSH into live Kubernetes clusters in a browser terminal and fix/build things. No multiple choice. It tests whether you can operate Kubernetes — install it, break it, fix it, secure it, and keep workloads running. Passing requires speed and muscle memory, not just knowledge. The exam is open-book on kubernetes.io documentation (one tab allowed), which means the skill being tested is finding and applying the right manifest/command fast.
2. Pathway and exam format
- Typical path: Docker/container basics → KCNA (optional conceptual warm-up) → CKA. Many candidates skip KCNA; don't skip lab time.
- Format: ~15–20 performance tasks, 2 hours, remote-proctored. Passing score 66%. You get a Linux terminal (bash) with
kubectlpreconfigured against several clusters — you must switch contexts (kubectl config use-context) per task. One browser tab of kubernetes.io allowed; no other tabs, no copy-paste from outside. - Exam version tracks a specific Kubernetes minor version (v1.35 per 2026 guides in the catalogue — confirm the current version when scheduling; flag/version skew matters for deprecated APIs).
- Environment strategy (this is half the exam):
- Set up your shell FIRST:
alias k=kubectl,export KUBECTL_EXTERNAL_DIFF=...not needed, butk completion bash,alias kn='kubectl -n'. The single highest-ROI prep is typing speed withkubectl. - Use
kubectlimperative commands to generate YAML scaffolds fast:k create deploy nginx --image=nginx --dry-run=client -o yaml > d.yaml, then edit. Never hand-write a full Deployment from scratch under time pressure. k explain <resource>.<field>is your in-exam schema reference.k get --helpfor flags.- Bookmark kubernetes.io task pages (docs allow one tab — use it for the tasks you don't have memorized: e.g., NetworkPolicy recipes, Ingress examples).
- Vim fluency:
:set paste,/search,:%sreplace. If you can't edit YAML fast in vim, practice until you can. - Time budget: ~6–7 min/task. If a task eats 10 minutes, flag it and move on — partial credit rewards breadth.
- Set up your shell FIRST:
3. Knowledge domains (with theory)
Public weighting (approximate): Storage 10%, Troubleshooting 30%, Workloads & Scheduling 15%, Cluster Architecture/Installation/Configuration 25%, Services & Networking 20%.
Cluster architecture: the control plane, properly understood
Components and their contracts:
- kube-apiserver: the only component that talks to etcd; all other components talk to the API. Stateless, horizontally scalable behind a load balancer. Every
kubectlcommand is a REST call here. - etcd: the single source of truth — all cluster state. Uses Raft consensus: quorum = floor(n/2)+1. For n=3, quorum=2 (tolerates 1 failure); n=5, quorum=3 (tolerates 2). Key insight: etcd write latency is the control-plane latency floor, and losing quorum = read-only/frozen cluster. Backup with
etcdctl snapshot save; restore requires stopping the API server, restoring data-dir, restarting. - kube-scheduler: assigns unscheduled Pods to Nodes via a two-phase algorithm: filtering (predicates) — NodeResourcesFit, NodeAffinity, TaintsAndTolerations, VolumeBinding — then scoring (priorities) — ImageLocality, NodeResourcesBalancedAllocation, etc. — picks the highest score. Understand this because scheduling failures ("0/3 nodes available: insufficient cpu") are predicate failures, and the fix is at the predicate (resources, tolerations, affinity), not by restarting the scheduler.
- kube-controller-manager: runs controllers (ReplicaSet, Deployment, Node, Job, endpoints...). Each is a control loop: observe actual state → diff vs desired → act. kubelet: the node agent — registers the node, runs Pod lifecycles via the CRI, reports status, enforces probes/resource limits via cgroups.
- kube-proxy: maintains node iptables/IPVS rules implementing Service virtual IPs. Understand: ClusterIP is a virtual IP that only exists as iptables rules on every node — that's why you can't ping it from outside and why DNS (CoreDNS) matters.
HA topology: stacked etcd (etcd on control-plane nodes, simplest) vs external etcd (separate hosts, more resilient, more ops). kubeadm default is stacked. Know kubeadm init --control-plane-endpoint (the LB VIP/DNS all control-plane nodes share) — without it, kubelets/certs bind to one node's IP and HA is broken.
Workloads and scheduling
- Deployments (stateless, rolling updates) vs StatefulSets (stable identity:
web-0, ordered startup, per-pod PVCs via volumeClaimTemplates — databases) vs DaemonSets (one pod per node — log/monitoring agents) vs Jobs/CronJobs (run-to-completion). - Rolling update mechanics:
maxUnavailable(default 25%) andmaxSurge(default 25%) control the update wave. Rollback:kubectl rollout undo. Know how to pause/resume and checkrollout status. - Probes: liveness (restart the container), readiness (remove from Service endpoints), startup (for slow-starting apps — disables liveness/readiness until it succeeds). The classic bug: liveness probe too aggressive on a slow app → crash loop. Fix: startupProbe or higher failureThreshold/initialDelay.
- Resources: requests (scheduling + QoS floor) vs limits (cgroup ceiling). QoS classes: Guaranteed (requests==limits for all containers) → Burstable → BestEffort. Under node pressure, kubelet evicts BestEffort first. CPU is compressible (throttled), memory is not (OOMKilled) — this asymmetry drives every resource-sizing decision.
- Taints/tolerations, node affinity, pod affinity/anti-affinity, topology spread constraints: the placement toolkit. Anti-affinity (
podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution) spreads replicas across zones — the exam's HA pattern.
Services and networking
- Service types: ClusterIP (internal VIP), NodePort (30000–32767 on every node), LoadBalancer (cloud LB → NodePort), ExternalName (DNS CNAME). Endpoints/EndpointSlices are the actual pod IPs behind the VIP.
- Ingress: L7 routing (host/path → Service). Needs an Ingress controller (nginx) actually installed — a bare Ingress object does nothing. Know the
networking.k8s.io/v1spec: rules, tls, ingressClassName. - NetworkPolicy: default-deny is opt-in (you must create the policy). Default deny-all-ingress + explicit allows is the exam's security pattern. Remember: policies select Pods; ingress/egress rules reference podSelectors, namespaceSelectors, or ipBlocks. DNS egress gotcha: a default-deny-egress policy breaks CoreDNS unless you allow UDP/TCP 53.
- CNI basics: the cluster's CNI (Calico, Cilium, Flannel) implements pod networking; know that
kubectlcan't fix CNI misconfig from inside — but the exam usually tests NetworkPolicy and Service/DNS issues, not CNI reinstalls.
Storage
- Volumes vs PV/PVC/StorageClass: Pod volumes are ephemeral (emptyDir dies with the pod); PersistentVolumes are cluster storage; PVCs are claims; StorageClasses enable dynamic provisioning (the provisioner creates the PV). Access modes: RWO/RWX/ROX — know which your storage supports (hostPath/NFS vs cloud disks).
- StatefulSet + volumeClaimTemplates = per-pod PVCs (
data-web-0). The exam's storage tasks: create a PV/PVC, mount it, verify data persists across pod deletion, expand a volume (allowVolumeExpansion + edit PVC).
Security: RBAC, service accounts, contexts
- RBAC: Role/ClusterRole (what verbs on what resources) + RoleBinding/ClusterRoleBinding (who gets it). ServiceAccounts are the "who" for workloads.
kubectl auth can-i --as=system:serviceaccount:ns:nameto test. Know how to create a kubeconfig user with limited access (the classic "create user bob who can only read pods in ns dev" task). - Security contexts: runAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation:false, capabilities drop. Pod Security Standards (privileged/baseline/restricted) via namespace labels — the modern replacement for PSPs (removed in v1.25+).
- Secrets: base64-encoded (not encrypted!) by default; encryption at rest requires configuring the API server's EncryptionConfiguration with a KMS provider. TLS secrets for Ingress.
Troubleshooting (30% — the biggest domain)
The systematic method: kubectl get (what exists?) → describe (what does the API say — Events are gold) → logs (what did the app say?) → exec (what does the inside look like?). Events (kubectl get events --sort-by=.metadata.creationTimestamp) solve ~40% of exam breakage.
Failure signatures to memorize:
ImagePullBackOff→ wrong image name/tag, private registry without imagePullSecrets, or network. Checkdescribe.CrashLoopBackOff→ app crashing: check logs, then probes (over-aggressive liveness), then resources (OOMKilled = raise memory limit).Pending→ scheduler predicate failure:describe podsays why (insufficient cpu/memory, unbound PVC, taints, affinity).0/3 nodes available→ read the parenthetical — it's the failed predicate list.- Node
NotReady→ kubelet down, or CNI issue, or disk pressure (kubectl describe nodeshows conditions + pressure). - DNS fails (
nslookup kubernetes.defaultfails) → CoreDNS pods down or NetworkPolicy blocking port 53. - Service has no endpoints → selector doesn't match pod labels (most common), or pods not ready (readiness probe failing).
- etcd down → API server errors; restore from snapshot.
- kubelet won't start → check config (
/var/lib/kubelet/config.yaml), certs, andjournalctl -u kubelet.
4. Key commands (with when each applies)
k run/get/create/delete/edit/apply/describe/logs/exec— the core verbs.applyfor declarative files;createfor imperative scaffolds.k create deploy web --image=nginx:1.25 --replicas=3 --dry-run=client -o yaml > web.yaml— scaffold-then-edit; the single most important exam technique.k set image deploy/web nginx=nginx:1.26 --record/k rollout status/undo/history deploy/web— update lifecycle.k config use-context/use-namespace/current-context— context switching per task. Set the namespace every task (k config set-context --current --namespace=X) to avoid-nerrors.k auth can-i create deployments --as=system:serviceaccount:dev:bob -n dev— verify RBAC.k top nodes/pods— needs metrics-server; if it errors, that's the diagnosis (install/fix metrics-server).etcdctl --endpoints=https://127.0.0.1:2379 --cacert=... --cert=... --key=... snapshot save /tmp/snap.db— backup (certs in /etc/kubernetes/pki/etcd).kubeadm token create --print-join-command/kubeadm certs check-expiration— cluster ops.crictl ps/logson nodes when kubelet/CRI is suspect (kubectl can't reach a broken node).k drain <node> --ignore-daemonsets --delete-emptydir-data/k cordon/uncordon— node maintenance.k debug/ ephemeral containers for troubleshooting distroless images.
5. Worked examples
Example 1 — etcd restore under pressure.
Scenario: control-plane node lost etcd data; API server down; you have yesterday's snapshot at /backup/etcd.db.
Steps: (1) SSH to the control-plane node. (2) Stop kube-apiserver (mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/ — static pods stop when the manifest moves). (3) etcdctl snapshot restore /backup/etcd.db --data-dir=/var/lib/etcd-restored with the etcd certs. (4) Edit /etc/kubernetes/manifests/etcd.yaml to point --data-dir at the restored dir (or move the restored dir over the old one). (5) Restore the apiserver manifest; wait for static pods; verify k get nodes. Key insight: static-pod manifests are the control plane's init system — moving a manifest is the stop/start mechanism.
Example 2 — Scheduling failure diagnosis.
Scenario: Deployment shows 0/5 pods running; k describe pod → "0/3 nodes are available: 3 Insufficient cpu."
Steps: (1) k top nodes — are nodes actually full, or are requests oversized? (2) k describe node → allocated resources. Often the pod requests 4 CPU on 4-CPU nodes where system pods already reserved 1. (3) Fix: lower requests to realistic values (or add a node). Lesson: the scheduler bins by requests, not usage — oversized requests are the #1 "mystery Pending."
Example 3 — NetworkPolicy default-deny with DNS.
Scenario: "Lock down namespace api so only frontend pods can reach backend pods on 8080, nothing else."
Steps: (1) Default-deny: NetworkPolicy selecting all pods in api with empty ingress (and egress if required). (2) Allow policy: podSelector backend, ingress from podSelector frontend, port 8080. (3) If egress denied: add egress rule for UDP/TCP 53 to namespace kube-system podSelector k8s-app=kube-dns (or ipBlock of the DNS service). (4) Test with a temp pod: k run -it --rm tester --image=busybox -- wget -qO- http://backend:8080. The DNS egress rule is the step everyone forgets.
Example 4 — RBAC least-privilege user.
Scenario: "Developer Kim needs to view pods/logs and exec into pods in namespace dev, nothing else, using a dedicated kubeconfig."
Steps: (1) Create ServiceAccount or client cert for kim. (2) Role in dev: verbs [get,list,watch] on pods + pods/log, verb [create] on pods/exec. (3) RoleBinding kim → role. (4) k auth can-i to verify each verb, including a negative check (can-i delete pods → no). (5) Generate kubeconfig with the SA token. Note: pods/exec is a subresource — granting "pods" doesn't grant exec; the exam tests exactly this.
Example 5 — Storage: expand and persist.
Scenario: "A PVC data (5Gi) backing a StatefulSet is 95% full. Grow it to 10Gi without downtime."
Steps: (1) Check StorageClass has allowVolumeExpansion:true (if not, this is the trap — you can't expand; the answer is to add a new volume or migrate). (2) k edit pvc data → 10Gi. (3) If filesystem expansion needs it, the kubelet expands online for most drivers; verify with df via exec. (4) Confirm no pod restart was needed (expansion is online for ext4/xfs with modern CSI). Lesson: expansion is a property of the StorageClass + driver, not of kubectl.
6. Standards and regulations cross-reference
CKA is vendor-neutral infrastructure; the catalogue's software standards touch it at the edges:
- NIST SP 800-218 (SSDF) — supply-chain: image provenance (signed images, admission controllers like Connaisseur/Kyverno verifying signatures), no
:latestin production. - ISO/IEC 27001:2022 — A.8 controls map to RBAC least privilege, audit logging (API server audit policy → what was enabled, by whom), secrets encryption at rest.
- CIS Kubernetes Benchmark (not in catalogue but the de facto hardening standard — know it exists): kube-bench checks API server flags, etcd permissions, kubelet auth. The exam's "harden the cluster" tasks mirror CIS items.
- PCI DSS v4.0.1 / SOC 2 — appear as scenario constraints: network segmentation (NetworkPolicies), audit trails (API audit logs shipped to SIEM), image vulnerability scanning in the deploy pipeline.
- EU Cyber Resilience Act — vulnerability management for the platform itself: patch cadence for cluster components, SBOM awareness for images.
7. Pitfalls, traps, and exam strategy
Trap patterns:
- The namespace trap: every task names a namespace (or expects default). Set context namespace first, every time.
- The context trap: tasks span multiple clusters.
k config use-contextis step zero of every task — verify withk config current-context. - The version/API trap: deprecated APIs (extensions/v1beta1 Ingress, batch/v1beta1 CronJob) don't exist in v1.35. Use
k explainto confirm the current apiVersion. - The probe trap: fixing CrashLoopBackOff by raising resources when the cause is a bad liveness probe (check logs first, always).
- The "restart the component" trap: kube-scheduler "not scheduling" is usually a predicate failure, not a dead scheduler. Diagnose before restarting.
- The YAML-handwriting trap: scaffold with --dry-run=client -o yaml. Hand-writing a 60-line manifest from memory wastes 10 minutes.
Strategy: do a first pass answering everything you can in <5 min/task; flag the rest. Easy points: create/scale/expose resources, label/annotate, set contexts. Hard points: etcd restore, cluster upgrade (kubeadm upgrade plan/apply, drain, kubelet version skew — control plane first, then nodes, max skew rules). Memorize the skew rules: kube-apiserver to kubelet ≤ 2 minor versions; kubeadm plan first. Practice the full task list under a 2-hour timer at least 3 times before the real exam.
8. Practice problems
P1. A Deployment's pods are CrashLoopBackOff. k logs shows the app exiting with "FATAL: password file not found at /etc/app/pw". The Deployment mounts a Secret as a volume. Give the two most likely causes and the fix for each.
Answer: (1) Secret key name mismatch: the volume mounts keys as filenames; if the app expects pw but the Secret key is password, the file is /etc/app/password. Fix: rename the key or set items: path mapping. (2) The Secret doesn't exist in the pod's namespace (created in default, pod in prod). Fix: recreate in the right namespace. Diagnose with k describe pod (volume mount events) + k get secret.
P2. You must upgrade a kubeadm cluster from v1.33 to v1.34 with zero workload downtime. List the ordered steps.
Answer: (1) kubeadm upgrade plan (check). (2) kubeadm upgrade apply v1.34.x on the first control-plane node (etcd/API/scheduler/controller-manager upgrade; workloads keep running on workers). (3) apt/yum upgrade kubelet kubectl to v1.34 on that node, restart kubelet. (4) Repeat for other control-plane nodes (upgrade node). (5) Per worker: kubectl drain, upgrade kubelet, uncordon. Skew rule: kubelets may be up to 2 minors behind the API — never ahead. Drain one node at a time to preserve capacity.
P3. Nodes report DiskPressure and pods are being evicted. df shows /var/lib/docker (or containerd) at 92%. What's the immediate fix and the durable fix?
Answer: Immediate: crictl rmi --prune / image gc, clear unused images; evict or move the biggest log writers; journalctl --vacuum-size. Durable: kubelet image-gc thresholds (imageGCHighThresholdPercent), log rotation (containerLogMaxSize/Files), bigger disk or separate partition for /var/lib/kubelet, and alerting on disk pressure before eviction. Root lesson: eviction is the kubelet protecting the node — fix the pressure, not the eviction.
P4. Write the NetworkPolicy for: default-deny all ingress in namespace payments; allow ingress to pods labeled app=api on TCP 8443 only from pods labeled app=frontend in the same namespace.
Answer: Two policies. (1) Default deny: podSelector: {} with policyTypes: [Ingress] (no ingress rules). (2) Allow: podSelector app=api, ingress: [{from: [{podSelector: {matchLabels: {app: frontend}}}], ports: [{port: 8443, protocol: TCP}]}]. Verify with a test pod labeled differently (should fail) and one labeled frontend (should succeed).
P5. kubectl top nodes returns "metrics not available". The monitoring team says metrics-server is installed. Diagnose in order.
Answer: (1) k get deploy metrics-server -n kube-system — is it running? Check its logs. (2) Common cause: metrics-server can't reach kubelets (TLS/unknown CA) — check args (--kubelet-insecure-tls in test envs). (3) Check API service registration: k get apiservice v1beta1.metrics.k8s.io — must be Available=True. (4) RBAC for metrics-server's service account. Fix the failing layer; top works once the APIService is Available.
P6. A StatefulSet of 3 database pods must survive a zone outage. The cluster spans 3 zones. Give the scheduling configuration and the storage requirement. Answer: podAntiAffinity requiredDuringScheduling with topologyKey topology.kubernetes.io/zone (forces one pod per zone); plus podTopologySpread as a softer alternative. Storage: the StorageClass must support cross-zone attachment or provision per-zone volumes — each pod's PVC must bind in its own zone (volumeBindingMode: WaitForFirstConsumer so binding follows the pod's zone). Without WaitForFirstConsumer, a PVC can bind in zone-a while the pod lands in zone-b → Pending forever. That's the trap.
Original ETS reference writing, verified against public sources on 2026-09-30. Thin sourcing is flagged inline. Not legal advice — confirm current editions with the issuing body.