So I passed the CKA on my first try with 97% about a year and a half ago. Since then, whenever I talk about this cert, people keep asking me for tips and tricks. So here I am, finally writing this down (well, typing it actually). These are all my best tips and what I did to get the CKA, and not just that, I passed all the Kubernetes certs and got kubestronaut. That was quite a journey, I tell you!

We’ll only talk about the practice here, not the certificate itself. I figure if you’re reading this, you already know what you’re getting into. If not, well, check the CNCF website. I’ve been there too, reading tons of articles before actually doing it myself.

What the CKA actually tests

Forget about memorizing trivia etc… the CKA is basically a hands-on admin test. In practice, it tests how you handle real cluster scenarios and Kubernetes tasks under time pressure. The scenarios are pretty much what a Kubernetes admin does in real life. Keep it practical and focus on fixing and configuring stuff, not theoretical knowledge. Do not thing “oh I’ll just memorize everything”, that’s not how it works. You need to actually do things, not just know about them.

Setting up your environment quickly

Fast setup = free points basically. As soon as the exam starts, get your environment ready. In under 2 minutes, you can set up aliases, autocomplete, editor settings, and a tmux session.

Shell aliases & kubectl autocompletion: This saves you keystrokes by shortening common commands. For example: alias k=kubectl, kg='kubectl get', kd='kubectl describe', etc. You get the idea. I saw a lot of people doing this, I personnally typed the whole command and just used “k” alias.

Default namespace context: A lot of exam tasks happen in non-default namespaces (like kube-system or some specific project namespace).

alias kns="kubectl config set-context --current --namespace"

Use this kns alias to switch namespaces quickly. For example, kns foo sets your current context’s namespace to “foo” so all kubectl commands default there (no need for -n foo every time). Trust me this one is a game changer!

Always double-check with kubectl config view –minify | grep namespace or just run kubectl get pods to make sure you’re in the right namespace. This prevents the classic mistake of creating resources in the wrong namespace and losing time. (Yeah, I learned that the hard way during labs)

VIM setup: I read a lot about this before the exam, and honestly I was a bit worried. But in my experience, I never had to change anything in VIM. Just learn the basics (like how to search, keyboard shortcuts, etc.) and you’ll be fine. Don’t overthink it, I spent way too much time worrying about VIM config when I should have been practicing kubectl commands instead!

Tmux for multitasking: The exam terminal allows splitting, and tmux is your friend here. Start a tmux session right away. Inside tmux you can split the screen into panes for different tasks (one pane tailing logs or watching status, another for editing a file etc.). Super useful. I can’t tell you how many times this saved me from switching back and forth. It’s a game changer honestly.

Double-check context: Before diving into tasks, confirm you’re operating on the correct cluster context. The exam may use multiple contexts. Use kubectl config get-contexts and kubectl config use-context prod if needed to switch.

So to wrap up this first part: by spending just a minute or two upfront on these steps, you’ll gain back many minutes during the exam. It might feel like “lost” time when the clock is ticking (I know, I thought the same thing!), but it’s one of the best “ROI” moves you can make. After setup, you’re free to focus 100% on solving questions instead of fighting your tools. Trust me on this, I almost skipped this step because I was nervous about time, but it paid off big time.

Using the docs efficiently

You have access to Kubernetes documentation during the CKA, but using it effectively is kind of an art. The docs are huge, you can’t read pages end-to-end when you’re under time pressure. I made the mistake of diving too deep into the docs during my first practice run, and it cost me time. Here are some tactics to quickly find what you need:

Use kubectl explain as your first resort: Often you just need to recall a field name or structure (like “what keys go under livenessProbe?”). Instead of opening the browser, use kubectl explain. For example:

kubectl explain pod.spec.containers.livenessProbe --recursive | less

This outputs the full schema of the livenessProbe section, including all fields and descriptions. It’s fast and offline. You can search within this output (press / in less) for keywords. kubectl explain is golden for verifying YAML structure on the fly, without going through external docs.

Know your go-to pages: Some documentation pages are useful for many questions. A few worth quickly accessing:

  • Kubernetes API Reference (for core resource specs) - though kubectl explain often covers this
  • kubectl Cheat Sheet - a handy summary of common commands and options (especially JSONPath and filtering examples)
  • Resource Management sections - like the page on Liveness/Readiness Probes has examples of probe configs; Network Policies page shows sample policy YAMLs; RBAC docs have example Role/RoleBinding
  • Troubleshooting Guides - the official docs have a section on debugging common cluster issues (like DNS). These can help if you blank out on a problem (but if it happens, don’t spend too much time troubleshooting)

Have a mental index of where common info lives. If a task involves, say, taints and tolerations, remember that’s under Scheduling docs.

Use the search within docs site smartly: The Kubernetes docs site has a search bar. It’s decent if you use specific terms (like searching “kube-proxy config” or “certificate API server”). But it can sometimes be slower to filter. Make sure you’ve already looked into the docs before, or you’re going to lose a lot of time.

–dry-run=client -o yaml as documentation: This is a good tip! Generating an object with --dry-run can be faster than reading docs to see an example manifest. For instance, if you forget the syntax for a CronJob (who knows by heart?? I don’t!), just run:

kubectl create cronjob test --image=busybox --schedule="*/5 * * * *" --dry-run=client -o yaml

This prints a sample CronJob YAML that you can adapt. It’s like asking Kubernetes to give you a template. Use this for Deployments, Jobs, ConfigMaps, etc. It’s often quicker than searching the docs for the same snippet.

Know when not to read: If a question describes a scenario you recognize (like “Pods can’t resolve DNS names” or “A deployment is stuck with old replicas”), resist the urge to read long theory sections. Instead, jump into action (check the pods, get events etc…). The docs should be a last resort for when you truly can’t recall a detail or syntax. Every minute spent reading is a minute not fixing the cluster. Use documentation tactically, look up just the specific flag or field you need.

Converting imperative to declarative

One of the best techniques for CKA (and real-world Kubernetes) is converting imperative commands into YAML manifests on the fly. This lets you create resources quickly and correctly, then modify as needed and apply. It’s a fast-path from nothing to a working config without memorizing YAML schemas. Here’s the recipe I use:

The idea is: use kubectl create or kubectl run with --dry-run=client -o yaml to generate a YAML skeleton, redirect it to a file, edit the fields you need, then kubectl apply -f that file.

By doing this, you let Kubernetes build the template for you. You only fill in the gaps.

So let me give you a few examples I really like and that saved me a lot of time. These are the ones I use all the time, even now.

Deployment: 2 replicas of nginx.

kubectl create deployment web --image=nginx:1.25 --replicas=2 \
    --dry-run=client -o yaml | tee web-deploy.yaml

Service (ClusterIP): Expose the “web” Deployment on port 80.

kubectl expose deployment web --port=80 --target-port=80 \
    --dry-run=client -o yaml | tee web-svc.yaml

Job: Single-run pod performing a simple task.

kubectl create job batch-job --image=busybox \
    --dry-run=client -o yaml -- date | tee job.yaml

CronJob: Scheduled job running every 5 minutes. (If you don’t remember the schedule format, you can find it easily in the docs)

kubectl create cronjob frequent-task --image=busybox --schedule="*/5 * * * *" \
    --dry-run=client -o yaml -- date | tee cronjob.yaml

ConfigMap (from file): Let’s say you have a config file /etc/app/config.ini to load.

kubectl create configmap app-config --from-file=/etc/app/config.ini \
    --dry-run=client -o yaml | tee configmap.yaml

Secret (generic, from literal): Create a secret with a password. (you can also create it from a file, like for certs etc…)

kubectl create secret generic db-secret --from-literal=password=S3cr3tPW \
    --dry-run=client -o yaml | tee secret.yaml

PersistentVolumeClaim (PVC): Request 1Gi of storage.

kubectl create pvc data-vol --capacity=1Gi --access-modes=ReadWriteOnce \
    --dry-run=client -o yaml | tee pvc.yaml

One thing I remember struggling with was network policy. Oh man, this one gave me headaches during practice! Once you get the logic, it’s really easy and fast, but at first it can be confusing. You can’t create a network policy using kubectl create… so you have to go to the doc and copy paste it. I know, it’s a bit annoying, but once you understand the pattern, you’ll be able to write them from memory.

For example, to allow traffic from pods with label app=frontend to pods with label app=database in the same namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-db
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: database       # target pods
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend   # allowed source pods

This policy says “pods with label app=database will accept incoming traffic from pods with app=frontend (and nothing else).”

Important: After using imperative commands to get YAML, don’t forget to apply! The --dry-run=client means nothing actually was created. So once you’ve edited the manifest, run kubectl apply -f <file>.yaml to create or update the resources. The advantage of this approach is you keep the manifest files, which can be reused or referenced if another question builds on previous work.

How I used to troubleshoot fast

When something in the cluster isn’t working, a systematic approach and the right commands will save your exam. Here’s a playbook of troubleshooting scenarios. For each common issue, I’ll outline the goal, a fast path with key commands, why that works, and pitfalls to avoid. These are basically the debug patterns I wish I had memorized before my CKA.

Pods won’t schedule

A Pod is stuck in Pending (no node assigned). We need to find out why the scheduler can’t place it.

# 1. Check if the Pod is indeed unscheduled (no nodeName).
kubectl get pod mypod -o wide

# 2. Inspect the Pod's events for scheduler errors.
kubectl describe pod mypod

# 3. Look at node conditions and resource availability:
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints,FREECPU:.status.allocatable.cpu
# Yeap I copy/pasted this one from my notes and Yes I never used it in exam lol

# 4. Check if any node fits the Pod's nodeSelector or affinity (if defined):
# (List nodes with labels to match any nodeSelector on the Pod)
kubectl describe pod mypod | grep -A5 -i "Node-Selectors"

# 5. Examine taints on nodes and tolerations on Pod.
kubectl describe node node01 | grep -A5 Taints
kubectl describe pod mypod | grep -A5 Tolerations

# 6. Look at recent scheduler events cluster-wide (ex insufficient resources):
kubectl get events --sort-by=.lastTimestamp | grep -m1 FailedScheduling

CrashLoopBackOff debugging

A container is in a CrashLoopBackOff. We need to find the root cause of the crash and resolve it.

# 1. Get logs of the failing container's last crash
kubectl logs -p mypod

# 2. If multiple containers, specify the container name (or check init containers too)
kubectl logs -p mypod -c mycontainer

# 3. Describe the pod to see events (esp. if liveness probe causing restarts)
kubectl describe pod mypod | tail -20    # see last events quickly

# 4. If the pod fails super fast, use previous log (above) or try ephemeral debug:
kubectl debug -it mypod --image=busybox:1.28 -c debugger --target=mycontainer

# 5. Once inside the ephemeral container (if above worked), investigate:
# e.g., check environment variables, config files, connectivity, etc. within the pod's namespace.

Networking issues

Pods are running but can’t communicate as expected. This could be DNS lookups failing, or one service unable to reach another, or something being blocked by NetworkPolicies. We need to verify cluster DNS and network connectivity between pods.

# 1. Launch a temporary pod with networking tools (and clean it up after).
kubectl run -it --rm debug --image=busybox:latest --restart=Never -- sh

# 2. Inside the pod's shell (step 1):
# Test DNS resolution
nslookup kubernetes.default.svc.cluster.local
nslookup myservice.default.svc.cluster.local

# Try connecting to a service IP or pod IP
wget -O- http://myservice:80   # if wget is available, busybox has it

# Exit the pod shell when done (it will delete itself because of the --rm).

# 3. Check service endpoints from the outside:
kubectl get svc myservice -o wide
kubectl get endpoints myservice -o yaml

# 4. If using NetworkPolicies, list them and see what's allowed:
kubectl get networkpolicy -A
kubectl describe networkpolicy allow-frontend-to-db

# 5. Validate CoreDNS is running well (if DNS issues):
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns

Storage issues

A PersistentVolumeClaim (PVC) is not binding, or a Pod using a PVC can’t start/mount volume. We need to figure out what’s wrong in the storage setup and get the volume attached.

# 1. Check PVC status (Bound/Pending) and details
kubectl get pvc myclaim -o wide
kubectl describe pvc myclaim

# 2. If PVC is Pending, see if a PV exists or if dynamic provisioning is failing:
kubectl get pv   # list PersistentVolumes, check if any Available matches
kubectl describe sc   # check default StorageClass and provisioner status

# 3. If Pod is failing to mount, describe the Pod to get events:
kubectl describe pod mypod | grep -A5 -i volume

# Look for events like "Unable to attach or mount volumes" or "FailedMount".

#### Failed rollouts

A Deployment rollout is not proceeding (or a new version is failing). We need to identify stuck deployments or roll back to a stable version.

```bash
# 1. See the status of all deployments (check for unavailable or stuck pods)
kubectl rollout status deployment myapp

# 2. If pods in the deployment are failing, get details:
kubectl get pods -l app=myapp -o wide
kubectl describe deployment myapp | tail -n20   # recent events, like failed scheduling or probe failures

# 3. Identify the bad ReplicaSet (if a rollout created a new RS):
kubectl rollout history deployment myapp

# 4. Roll back to previous revision if needed:
kubectl rollout undo deployment myapp   # rolls back to last successful revision

# 5. Alternatively, fix the image or config and apply:
kubectl set image deploy/myapp myapp-container=myimage:good-tag
kubectl rollout status deploy/myapp    # watch until it's successful

# 6. To view pod history (e.g., if multiple revisions):
kubectl rollout history deployment myapp --revision=2

Node problems

Manage node availability - draining a node for maintenance or troubleshooting a node in NotReady state.

# 1. Safely cordon and drain a node
kubectl cordon node01
kubectl drain node01 --ignore-daemonsets --force

# (The flags: ignore DaemonSet pods since they won't be evicted)

# 2. Perform maintenance or troubleshoot:
# e.g., SSH into node01 if needed or check kubelet
ssh node01 "sudo journalctl -u kubelet -n 50"

# 3. After maintenance, bring the node back:
kubectl uncordon node01

# 4. Verify node readiness and pods distribution:
kubectl get nodes -o wide
kubectl get pods -o wide -A | grep node01   # any pods still there or all evicted properly?

# 5. If a node is NotReady, check node conditions and kubelet:
kubectl describe node node01 | grep -A5 Conditions

# On the node (via SSH or debug):
sudo systemctl status kubelet -l   # check if kubelet is running or crashed
sudo journalctl -u kubelet -r      # kubelet logs in reverse time (newest first)

Those were the main troubleshooting scenarios. In the exam, any of these can pop up as a task: “Why is Pod X not running?” or “Application Y is failing after update, fix it.” Following these paths will lead you to the answer quickly. As you practice, try to internalize the sequence: check describe output, check logs, use one-liners to narrow things down. It’s like a reflex, and with it, you’ll resolve issues with confidence. After a while, these commands become second nature, you’ll just know what to run when something goes wrong.

Etcd snapshot and restore

Etcd is the brain of Kubernetes, and the CKA often tests your ability to back it up and restore it. This typically involves a single-node etcd (in a kubeadm setup) and using etcdctl. Precision is key here, as using the wrong flags or paths could waste time. Let me outline an exam-safe way to snapshot and restore etcd:

Let’s say you need to take a snapshot of etcd, then restore it (perhaps simulating disaster recovery). Assume you’re on the control plane node with access to etcd’s certs.

** I strongly recommend to use the doc for this one **

1. Set environment and endpoint:

Always set the API version and endpoint for etcdctl. In kubeadm default, etcd listens on https://127.0.0.1:2379 for client requests.

export ETCDCTL_API=3
ETCD_ENDPOINT="https://127.0.0.1:2379"

Note: This ensures etcdctl uses the v3 API and points to localhost. In most cases, etcdctl defaults to localhost if not specified, but being explicit is fine I guess. You can also be asked to access a remote etcd so it’s good to know.

2. Snapshot save:

Run the snapshot command with the proper certs (CA, cert, key). On a kubeadm cluster, these are in /etc/kubernetes/pki/etcd/.

etcdctl --endpoints=${ETCD_ENDPOINT} \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /tmp/etcd_snapshot.db

After this, you can quickly verify the snapshot file:

etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot status /tmp/etcd_snapshot.db

3. Restore snapshot:

Typically, you restore into a new data directory so as not to overwrite the existing one. Choose a path (maybe /var/lib/etcd-backup).

etcdctl snapshot restore /tmp/etcd_snapshot.db --data-dir /var/lib/etcd-backup

This command creates a fresh etcd member data in /var/lib/etcd-backup containing the snapshot’s state. It will output information about the new member being added.

4. Update etcd manifest:

Now the critical step: point Kubernetes to use the restored data. In kubeadm, etcd is a static Pod defined at /etc/kubernetes/manifests/etcd.yaml. Open that file (with vim or nano) and find the hostPath that mounts the etcd data directory:

...
volumeMounts:
- mountPath: /var/lib/etcd
  name: etcd-data
...
volumes:
- name: etcd-data
  hostPath:
    path: /var/lib/etcd
    type: DirectoryOrCreate
...

Change the hostPath path from /var/lib/etcd to /var/lib/etcd-backup (or whatever directory you used in restore). Save the file.

The kubelet watches this manifests directory. Within a few seconds, it will notice the file changed and restart the etcd container using the new data dir. Run:

watch -n1 kubectl get pods -n kube-system -o wide

to observe etcd (and possibly other control-plane pods). You’ll likely see the etcd-controlplane pod terminate and a new one come up. Wait until it’s Running. (You have to check locally with podman)

5. Verify cluster health:

Once etcd is up with the restored data, the API server (which talks to etcd) should start serving the old state. Verify:

kubectl get nodes
kubectl get pods -A

Do you see the resources that were present at snapshot time? If the exam says the cluster had certain deployments or pods, check that they are back. Also, make sure no core components are crashing. kubectl get cs (componentstatus) is deprecated, but it might show etcd health. Better is:

etcdctl --endpoints=${ETCD_ENDPOINT} \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  endpoint health

It should report the endpoint as healthy. If etcd is healthy and the API server is connected (check kubectl get pods -n kube-system and see kube-apiserver is Running without restart loops), you’re good to go.

RBAC basics

Kubernetes RBAC (Role-Based Access Control) tasks can look scary at first, but they usually boil down to creating a couple of small YAML objects: Roles (or ClusterRoles) and RoleBindings (or ClusterRoleBindings). The exam might ask you to “Create a Role so that a certain user/serviceaccount can read pods in a namespace” or “Limit an account to do X”. Here’s a crash course to nail RBAC creation quickly, I used to find this confusing, but once you understand the pattern, it’s actually quite straightforward:

Role vs ClusterRole:

  • Role: Namespaced. Grants permissions within a specific namespace. Example: a Role that allows “get, list, watch pods” in namespace X.

  • ClusterRole: Cluster-wide. Either grants access to cluster-scoped resources (nodes, etc.) or can be bound cluster-wide. Can also be bound in a namespace if you want to reuse the same perms across many namespaces via a single ClusterRole.

RoleBinding vs ClusterRoleBinding:

  • RoleBinding: Binds a Role to a user/group/serviceaccount within a namespace.

  • ClusterRoleBinding: Binds a ClusterRole to a subject globally (can still target a namespace for service account subjects, but the permissions are cluster or namespace depending on the ClusterRole).

You can easily generate them using these commands:

kubectl create role pod-reader --verb=get --verb=list --verb=watch \
    --resource=pods -n mynamespace --dry-run=client -o yaml > pod-reader-role.yaml
kubectl create rolebinding pod-reader-binding --role=pod-reader \
    --serviceaccount=mynamespace:alice -n mynamespace \
    --dry-run=client -o yaml > pod-reader-bind.yaml

You’ll get a skeleton like this:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: mynamespace
  name: pod-reader
rules:
- apiGroups: [""]        # "" indicates the core API group (for core resources like pods)
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Tip: You won’t remember all API groups and that’s OK! It can be a waste of time to go to the docs every time. You can use the command kubectl api-resources | grep pod.

Example with kubectl api-resources | grep deploy:

bochi@kub:~$ kubectl api-resources | grep deploy
deployments                         deploy       apps/v1                           true         Deployment

You can then check the permissions using:

kubectl auth can-i get pods --as system:serviceaccount:mynamespace:alice -n mynamespace

A useful command when you want to check everything you can do:

kubectl auth can-i --as system:serviceaccount:mynamespace:alice --list -n mynamespace

Scheduling controls

We have several ways to control which nodes your pods land on and how they are spread. In practice (and in the CKA), you should know the main ones, their typical use-cases, and trade-offs. Here’s a quick comparison table and notes:

Node Selector: Pod must run on nodes with a specific label (simple hard requirement). (Easy +++ to use but no flexibility / priority)

Node Affinity: Need more expressive scheduling rules or soft preferences. For ex. try zone A, but if not, zone B.

Taints & Tolerations: To dedicate or repel pods from certain nodes. For ex. taint node as “infra-only” so only specific tolerant pods schedule there.

Pod Affinity / Anti-affinity: Ensure pods are (or are not) co-located on the same node (or same topology domain) as other specific pods. For ex. run frontend pods on the same node as cache pods for performance (affinity) OR ensure two replicas of same service never on same node (anti-affinity).

Topology Spread: Evenly distribute pods across a given topology (zones, nodes, etc.) for high availability. For ex. ensure no node has more than 1 pod of the same Deployment.

Some practical notes:

Use NodeSelector for quick pinning when you absolutely know which node(s) you want (like a special hardware node). It’s straightforward (just ensure the node is labeled).

Use Node Affinity for more flexibility, especially if you want to prefer but not require a location. For example, “try to put pod in zone east-1, but it can run anywhere” can be expressed with preferredDuringScheduling affinity.

Use Taints/Tolerations for dedicated nodes. A common pattern is tainting a node (for ex. kubectl taint nodes nodex dedicated=experimental:NoSchedule) and then adding toleration to pods that should go there. This keeps other pods off those nodes by default. In CKA, they might ask to use a toleration to schedule a pod onto a tainted node (like scheduling something on master node).

Use Pod anti-affinity for HA. Like if you have a Deployment with 3 replicas, adding a simple podAntiAffinity on itself (match by app label on hostname) ensures the scheduler tries to put each replica on a different node (assuming >=3 nodes). This is a common availability practice.

Use Topology Spread Constraints if you need to spread pods across zones evenly. This is a newer approach that can replace some use-cases of anti-affinity. If asked, you might specify that each node or zone should get no more than X pods.

My nightmare, JSONPath & Field-Selector…

Yeah, I hated this part… at first! I mean, really hated it. But then I understood why it’s important and how it can save a lot of time, for example when you need to patch a resource. I still don’t like it (let’s be honest), but now I understand the utility at least. If I can learn to use it, so can you, and trust me, it’s worth it.

So from someone who hated it, let me give you all the tips I got to ace this part and not spend too much time on it.

So the core rules from my notes (you need to remember these):

  1. Use single quotes around the template to avoid shell expansion: -o jsonpath='{...}'.

  2. Iterate cleanly with range … end, print separators with {"\n"}, {"\t"}.

  3. Arrays use [*]; dot keys with special chars using quotes.

  4. Prefer selectors for filtering (-l, --field-selector) and use JSONPath only to print what you selected.

  5. For complex stuff, it’s ok to fall back to -o json | jq; otherwise stick to jsonpath.

An example: list all pod names in a deployment (by label):

kubectl get pods -l app=web -o jsonpath="{.items[*].metadata.name}"

You’ll also need to know how to add a column and stuff like that:

kubectl get pods -A -o custom-columns=\
NAMESPACE:.metadata.namespace,\
NAME:.metadata.name,\
IMAGE:.spec.containers[*].image

Final thoughts

So to wrap up this article, I’d recommend you train, train, and train! CKA is not a tough exam if you take it seriously. Just know your basics and everything will go smoothly. I know it can feel overwhelming at first, but with consistent practice, you’ll get there.

Once you’ve bought the exam, you’ll have access to an exam prep platform. It’s way harder than the real one, trust me! The questions are longer with more stuff asked, and you have fewer questions than the real one. When I took the practice exam, I was like “Ok, I’ll never pass the CKA”, I was genuinely worried! But when I decided to go for it and booked the date, it was way easier. In fact, it’s not that the questions are easier, it’s basically the same questions but asking you to do less stuff, or at least it’s split into 1-2 questions. So don’t let the practice exam discourage you if you find it difficult. It’s designed to be harder!

Always read every question carefully and check you’re on the right cluster, context, and namespace. I can’t stress this enough, I almost lost points because I forgot to check the namespace once. Don’t spend too much time on the same question and move on. Always use a dry-run before applying to check and/or generate. Always check your work and that it’s working/named/configured as expected. Keep a notepad/vim/whatever you like open so you can take notes and jump back to old questions to check/correct them. Stay calm and use common sense, if a task seems extremely complex or unclear, it probably has a straightforward solution you’re missing. Take a break and break it into smaller parts. If you’re stuck, take a deep breath and re-read the question. Sometimes the answer is simpler than you think.

Don’t hesitate to send me a message on Discord, LinkedIn, or Twitter if you passed the certification and found this interesting! I’d love to hear about your experience. And if you’re still preparing, feel free to reach out if you have questions, I’m always happy to help!