Dominik Andruszak

Preparing for CKAD

With the rising popularity of Kubernetes, a lot of engineers decide to take the Kubernetes certification exams. The CKAD exam itself (which I’ll be focusing on) is said to be a quite challenging one, so in this article, I want to share my story of how I ended up taking this exam and how I prepared for it. This is of course by no means an “exam guide”, just a couple of loose tips that are a result of exchanging info about the preparations and the exam with a couple of friends.

A bit of history - my adventure with OCJP

A couple of years ago, when I was still a Java developer, I decided to take the OCJP certification. The exam was a theoretical one, so — armed with some hefty Java tomes and the documentation — I spent a couple of weeks studying and making sure that I’m prepared for even the most intricate questions.


Even though I felt that I haven’t really learned anything new per se (I’ve been working in Java for quite some time beforehand), my preparations helped me sort out the stuff that I already knew. Still, after passing the exam — apart from satisfaction, of course — I felt quite a lot of fatigue. To the point in which I was pretty sure that I didn’t want to take any other tech certifications ever again. Obviously — until I started working with Kubernetes, that is.

So how's CKAD different?

A couple of years have passed since my OCJP exam — I’ve switched projects and companies and about two years ago started working on a Kubernetes-based project as a Python developer. The application wasn’t just hosted on Kubernetes, it actually utilized its API quite heavily, creating and deleting objects in the cluster left and right from within the application code. As I had absolutely no experience with Kubernetes before, debugging the more infrastructure-based issues was challenging for quite a while. I started armed with just the simple commands, like kubectl get pods and kubectl logs, and - to be perfectly honest - in most cases, it didn't help me all that much, since I didn't know much about how Kubernetes actually worked. However, the more I've worked with our application, the more I've learned Kubernetes, and slowly, but surely, I started to become quite efficient with debugging. I also became interested in the Kubernetes certification - in opposite to most exams that I knew, CKAD (as well as CKA) was fully practical. No multiple choice tests here, just a terminal and a list of tasks to perform within a limited time. That sounded mighty interesting, so I figured I'll give it a shot.

How does the exam look like?

As mentioned — the CKAD exam is quite different from many other certifications. Not only there’s no documentation-based multiple choice test — the official documentation is available to you at all times during the exam! There’s no need to memorize commands or any YAML snippets — after almost two years working with Kubernetes, I still double-check those pesky volume and volume mount YAML params in the documentation, just to be sure.

You can take the exam online from the comfort of your home — that means that you will need to have your webcam and microphone turned on, so the supervisor is able to verify that everything’s going as it should be. That also means that you might have to do some cleaning around your work desk — but we’ll get to that in a second. Last, but not least — the exam takes 2 hours. It should be just long enough to let you finish all the tasks (and also do a quick check that everything’s actually done right), but short enough to keep you on your toes all throughout the exam.

To pass the exam you’ll need to get a score of at least 66% — and hopefully — with these tips attaining this score will be ever so slightly easier.


Knowing where to find information

First things first — get to know the exam curriculum. It’s actually a very short document listing all the knowledge and skills you’ll need to pass. It might not seem like much, but it’s quite helpful and also a great jump-off point to start building your study plan.

What you’ll want to get to know quite well, on the other hand, is the official documentation. As I mentioned before, it’s available to you at all times during the exam — there’s a catch though. The browser you’re using to take the exam can only have two tabs open — one with the actual exam, and the other one with the documentation. Since you won’t be able to open multiple tabs with the docs to speed up your search, it’s a good idea to get to know its layout. A good idea is to use the documentation as often as possible during your preparation — you’ll learn how to browse and search through the docs in a natural way. Speaking of searching — that search box in the top right corner of the docs works wonders and — most probably — you’ll be able to find most stuff you’ll need by simply searching by object names.

Last, but not least — kubectl comes equipped with some documentation as well. You can use kubectl explain to get information regarding specific fields from an object's manifest. This is a quick way to check for the type or parameter list for a specific field.

$ kubectl explain pod.spec.containers.image
KIND:     Pod

FIELD:    image <string>

     Docker image name. More info:
     https://kubernetes.io/docs/concepts/containers/images This field is
     optional to allow higher level config management to default or override
     container images in workload controllers like Deployments and StatefulSets.

kubectl help, on the other hand, provides information about specific kubectl commands. You can use it as a reference to quickly check the syntax and parameters. I've truncated the output in this example because it's quite lengthy.

$ kubectl help run | head
Create and run a particular image in a pod.

  # Start a nginx pod.
  kubectl run nginx --image=nginx

  # Start a hazelcast pod and let the container expose port 5701.
  kubectl run hazelcast --image=hazelcast/hazelcast --port=5701

  # Start a hazelcast pod and set environment variables "DNS_DOMAIN=cluster" and "POD_NAMESPACE=default" in the container.

Both kubectl explain and kubectl help let you consult the documentation (or at least - parts of it) from the exam terminal, without having to switch browser tabs to the documentation itself. If I'm being perfectly honest, during my exam I didn't really use either of those commands. I think that there's actually enough time to use the online documentation. Also - if you're not well acquainted with those commands, you might actually spend more time trying to figure out how to find the info you need.

Mastering the :wq

There’s this age-old tweet from Lady Gaga’s account, in which she apparently tries to exit Vim for the very first time. I got some good news — you only need to know Vim a little bit more to efficiently use it during the exam.


One of the vim’s settings that might become helpful during the exam is :set paste. It'll preserve the formatting while copying text from outside the editor, so it might save you some YAML-reformatting while copy-pasting snippets from the documentation. And while we're on the subject of copying and pasting - you can use both right-click-paste and ctrl-shift-v to paste the content into the exam terminal. Fun fact - on Linux, the ctrl-shift-c key combination opens the browser developer tools in both Firefox and Chrome, it's worth keeping in mind.

Oh, and by the way, you can also change the default editor to a different one by exporting an environment variable

export KUBE_EDITOR="nano"

But then again — why not take this opportunity to learn Vim? I can guarantee that it’ll become useful sooner than later. You can check out the excellent Vim Adventures browser game to have a little fun while you’re getting acquainted with the editor - https://vim-adventures.com/

Creating objects with kubectl

kubectl allows for creating some of the objects (like pods, deployments, or config maps) in two ways - declarative and imperative. The declarative way is your standard, manifest-based way of creating objects whereas the imperative way allows you to create them using kubectl oneliners. While the declarative way is perfectly fine for day-to-day work, it takes quite a bit of time to prepare those four-part YAML manifests. During the exam, you'll be working under a time constraint, so the imperative oneliners might just give you those extra couple of minutes to triple-check that one task that you weren't so sure about.

Here’s how to create a simple pod using the imperative way and the manifest that you’d have to write to create it declaratively

kubectl run nginx --image nginx --restart Never
apiVersion: v1
kind: Pod
  creationTimestamp: null
    run: nginx
  name: nginx
  - image: nginx
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}

As you can see, we were able to create the pod without having to write the whole manifest, which saved quite a bit of writing. Let’s take a quick look at the curious --restart parameter at the end. It determines what kind of object is created by kubectl run

  • --restart Always creates a deployment, this is also the default behaviour when the parameter isn't specified
  • --restart Never creates a pod
  • --restart OnFailure creates a job

The same mechanism can be applied to config maps (again — the imperative command along with the YAML manifest)...

kubectl create configmap myconfig --from-literal VALUE1=first_value --from-literal VALUE2=another_value
apiVersion: v1
  VALUE1: first_value
  VALUE2: another_value
kind: ConfigMap
  creationTimestamp: null
  name: myconfig

...as well as secrets! Please keep in mind that you need to specify the kind because Kubernetes differentiates a couple of kinds of secrets.

kubectl create secret generic mysecret --from-literal SECRET_VALUE=totally_secret

Okay, but what if I want to adjust the object before it’s created in the cluster? Those kubectl creation commands have a dry-run parameter that allows for printing the object manifest to stdout or a file.

$ kubectl run mypod --image busybox --restart Never --dry-run -o yaml > mypod.yaml
$ kubectl get pod mypod
Error from server (NotFound): pods "mypod" not found
$ cat mypod.yaml
apiVersion: v1
kind: Pod
  creationTimestamp: null
    run: mypod
  name: mypod
  - image: busybox
    name: mypod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}

The object hasn’t been created in the cluster, but the whole manifest has been saved to a file. As you probably noticed, we also used the -o yaml parameter in our command. It sets the command output to the YAML format and works with the creation commands, but you can fetch a manifest of an existing object as well. Again - the output is truncated for readability.

$ kubectl get pod nginx -o yaml | head
apiVersion: v1
kind: Pod
  creationTimestamp: "2020-04-13T23:09:34Z"
    run: nginx
  - apiVersion: v1
    fieldsType: FieldsV1

Another type of object that we can create in this handy, imperative way is the service. Creating it in this way also takes care of the selectors in the manifest for us. We just have to specify the object we want to expose in the command and kubectl will take care of preparing the selectors. The example creates a service for a pod, but this method also works for deployments. Here’s an imperative command along with the YAML used to create the exact same service.

kubectl expose pod nginx --port 80 --target-port 80 --name nginx_service --type ClusterIP
apiVersion: v1
kind: Service
  creationTimestamp: null
    run: nginx
  name: nginx_service
  - port: 80
    protocol: TCP
    targetPort: 80
    run: nginx
  type: ClusterIP
  loadBalancer: {}

As you can see, you can provide the ports and service type with command parameters. One thing I’d like to point out — contrary to previous commands, the name of the created service is not passed as a positional parameter after the command name. In the case of the expose command, the service name is passed with a --name command and the positional parameter is the name of the pod or deployment that you want to expose.

Some other handy kubectl commands

Photo by Maksym Kaharlytskyi on Unsplash Photo by Maksym Kaharlytskyi on Unsplash

There are a couple of kubectl commands that can help you filter and find objects that you need. For example, you can list all the labels that are assigned to objects of a specific type - and then filter them by specific labels.

$ kubectl get pod --show-labels
mypod   0/1     Completed   0          14s     run=mypod
nginx   1/1     Running     0          6m40s   run=nginx
$ kubectl get pod -l run=nginx
nginx   1/1     Running   0          7m4s

You can also list all pods from all namespaces — or just one namespace. Keep in mind that you can’t get resources by name across all namespaces, so kubectl get po nginx -A won't work

$ kubectl get pod -A
NAMESPACE              NAME                                         READY   STATUS      RESTARTS   AGE
ckad                   mypod                                        0/1     Completed   0          53s
ckad                   nginx                                        1/1     Running     0          7m19s
kube-system            coredns-66bff467f8-p4btx                     1/1     Running     5          13d
kube-system            coredns-66bff467f8-r6fwm                     1/1     Running     5          13d
kube-system            etcd-minikube                                1/1     Running     4          13d
kube-system            kindnet-ck2jc                                1/1     Running     5          13d
kube-system            kube-apiserver-minikube                      1/1     Running     4          13d
kube-system            kube-controller-manager-minikube             1/1     Running     4          13d
kube-system            kube-proxy-snfhd                             1/1     Running     4          13d
kube-system            kube-scheduler-minikube                      1/1     Running     4          13d
kube-system            nginx-ingress-controller-6d57c87cb9-g4gd9    1/1     Running     4          13d
kube-system            storage-provisioner                          1/1     Running     7          13d
kubernetes-dashboard   dashboard-metrics-scraper-84bfdf55ff-9nqps   1/1     Running     4          13d
kubernetes-dashboard   kubernetes-dashboard-bc446cc64-xfjf6         1/1     Running     6          13d
$ kubectl get pod -n kube-system
NAME                                        READY   STATUS    RESTARTS   AGE
coredns-66bff467f8-p4btx                    1/1     Running   5          13d
coredns-66bff467f8-r6fwm                    1/1     Running   5          13d
etcd-minikube                               1/1     Running   4          13d
kindnet-ck2jc                               1/1     Running   5          13d
kube-apiserver-minikube                     1/1     Running   4          13d
kube-controller-manager-minikube            1/1     Running   4          13d
kube-proxy-snfhd                            1/1     Running   4          13d
kube-scheduler-minikube                     1/1     Running   4          13d
nginx-ingress-controller-6d57c87cb9-g4gd9   1/1     Running   4          13d

Speaking of namespaces, the command switching your current kubectl context to a different namespace might become handy during the exam, though it's a bit unintuitive at first glance (actually, maybe at second and third glances as well).

kubectl config set-context --current --namespace kube-system

Finally, for all you optimization fans — you can use shortened names in kubectl commands for many of the resource types.

  • kubectl get po for pods
  • kubectl get cm for config maps
  • kubectl get deploy for deployments
  • kubectl get svc for services
  • kubectl get ns for namespaces

Also — tab-based completion should work for both resource names, as well as resource types.

During the exam - last notes

A couple of paragraphs above, I mentioned that the ability to take this exam online from your home might mean that you’ll need to do some cleaning on your desk. You can find the specifics on how to prepare your room in the CKAD information, but the two things that seem the most important — you must be alone in the room and the only thing on your desk should be your computer. Be aware of that, as the exam supervisor will probably ask you to pan your webcam across the room.

Photo by Alexandar Todov on Unsplash Photo by Alexandar Todov on Unsplash

Time management during the exam is quite important — and while I realize it’s probably the most repeated advice when it comes to time-constrained exams, I think that it’s one worth repeating. If you get stuck on a task, move on — there are still probably a couple of tasks that you’ll solve right away and be able to give that hard one another shot later. Solve the tasks that seem easy to you first — and then start taking care of the “thinkers”.

Something you might not be preparing for all that much (but you probably should) are connection problems. And I’m not even talking about being prepared “technologically” — your ISP connection can drop, the exam server might have a hiccup — and there’s not much you can really do to prevent that. What you can do, however, is be mindful that this kind of occurrence might... well... occur. It will probably take you right out of your “zone” and even though you don’t lose the minutes you were offline (your supervisor extends your exam time) it can take a moment before you’ll get back to business. This will always be surprising, but if you’re aware that it might happen, it might have a lesser impact on your final performance during the exam.

Final words

I hope that this article will help you in your preparations and during the exam. Remember to prepare well and practice your kubectl kata, as the exam will test your real-life Kubernetes skills (or at least - as close to real life as you can get in a laboratory test environment). Good luck!


Official resources

Tools for local Kubernetes development

Other resources