Acing the Kubernetes CKAD exam

Acing the Kubernetes CKAD exam

Learning materials, exam tips, and repeatedly used commands.

Kubernetes CKAD exam is a hands-on exam, unlike other certifications, which are mostly theoretical. In the exam, we have to create and debug Kubernetes resources like pods, deployments, services, ingress, jobs, cronjobs, secrets e.t.c in the given lab environment. So, we need to be quick to set up and verify things.

I am sharing things that worked for me to pass the exam on the first attempt.

Prep Materials

The following 3 courses are more than enough to prepare for CKAD.

  1. Udemy — CKAD prep with Tests by Mumshad: Learn Kubernetes concepts and try everything on a playground. Great course!

  2. killer.shmock exam sessions: You get two sessions when you purchase the certification. Try the first session a bit earlier than the exam to get a feel of the real exam, and save the second session when the exam is near because it expires after 36 hours.

  3. CKAD Mock Exams by Kodecloud: The first two labs will be enough for the majority. But if you want to get quick and 100% confident, you can try these 10 full-length mock exams with a timer. I only managed time to complete 6 of them.

In this blog, I will refer kubectl command with the alias k which is pre-configured in all environments.

Terminal / Env Setup

Aliases

Set these up in your terminal before you start solving the problems.

export do="--dry-run=client -o yaml"
# example: k run nginx --image=nginx $do > pod.yaml

# if not forced, you may have to wait for a long time
export now="--force --grace-period 0"
# example: k delete pod test $now

alias kn="k config set-context --current --namespace "
# now set namespace for the whole question without specifying namespace in each command
# example: kn default
# example: kn ckad-ns

# to print current namespace, just to verify
alias gn="k config view | grep namespace"

# by default helm autocompletion is not enabled in the lab environment
# we can do this to enable autocompletion
source <(helm completion bash)

Get familiar with VIM

Indentation in yaml can be time-consuming to carry out tasks like copy/pasting and editing, if Vim is new for you.

Check Vim basic commands needed for CKADHERE.

I memorized these Vim configs while practicing mock exams and the first step I did was save these in ~/.vimrc .

# tabstop and shiftwidth
set ts=2 sw=2
set expandtab
set autoindent
filetype plugin indent on

Useful Kubectl Commands

CPU and Memory usage of pods:

➜ k top pods --sort-by memory
NAME CPU(cores) MEMORY(bytes)
fury 119m 253Mi
flash 16m 5Mi

Label and Annotations:

# search pods by a label
➜ k get pods -l type=api

# multiple labels, type=api or type=cron
➜ k get pods -l "type in (api, cron)"

# add a new label private=true in selected pods
➜ k get pods -l "type in (api, cron)" private="true"

# add annotation e.g. owner=team-x in the selected pods
➜ k annonate pods -l "type in (api, cron)" owner="team-x"

Container Commands

Begin any container command with ['sh','-c']. The third parameter in the list should be the actual command we run, for example, sleep or something else. e.g. ['sh', '-c', '<command>']
This prevents common mistakes like passing commands and arguments in the same item e.g. ['cowsay Hi ckad!'] . It will throw an error as the stringcowsay Hi ckad! is considered a single command that does not exist.

Searching Pod/Container Logs

# View logs of a specific container
k logs -c

# Search pod logs
# --context flag displays more lines above and below the matched string
k logs nginx | grep OS --context=5

Cronjob/Job

Trigger a cron job by running a test job with the given name:

# do this instead of modifying cron job to run in a minute just for testing
k create job --from=cronjob/my-cron-job test-job

Custom Resource Definition (CRD)

You will be asked to create a custom resource from an existing CRD.

# Get JSON schema of CRD:

# search for openAPIV3Schema
➜ k get crd crontabs.stable.example.com -o json

API Resources

# display group, api version of a resource
➜. k api-resources | grep deployment
deployments deploy apps/v1 true Deployment

# find api resources with particular group/version
➜ k api-resources | grep storage.k8s.io/v1
csidrivers storage.k8s.io/v1   false   CSIDriver
csinodes storage.k8s.io/v1     false   CSINode

Kubectl output to custom columns:

➜ k get pod --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase"
NAME STATUS
app1 Running
app2 Running

Secrets
Secrets store data in base64 encoded format. To get the base64 decoded format, you can describe the secret: k describe secret my-secret

If you perform get k get secret my-secret -o yaml , it will return encoded values.

Testing the Connectivity of a Service:

  1. Get the service name or IP first.

     ~ k get endpoints
     NAME ENDPOINTS AGE
     test-service 10.244.0.101:80 38m
     # use above servicename.namespace or IP to test.
    

    IP is the simplest way to test.
    If we use a service name, we need to attach a namespace e.g. <service-name>.namespace in the DNS to test it from a pod in a different namespace.

    If curl is not present in the Alpine image, install using apk add curl .

  2. Create a temporary pod to test the service

     # using ip, simplest way to test
     ➜ k run test --restart Never \
     --rm -i --image nginx:alpine -- curl 10.244.0.101:80
    
     # using service name to test, but the testpod is in another namespace
     # service is in ckad namespace so. it's dns will be test-service.ckad
     ➜ k -n default run test --restart Never \
     --rm -i --image nginx:alpine -- curl http://test-service.ckad:80
    
     # using service name in same namespace. not need to append namespace in service name
     ➜ k run test --restart Never --rm -i \
     --image nginx:alpine -- curl http://test-service:80
    

Testing the Connectivity of an Ingress:

  1. Get the ingress hostname or IP.

     ➜ k get ingress
     NAME CLASS HOSTS ADDRESS PORTS AGE
     ingress-test nginx example.com 192.168.49.2 80 2m38s
    
  2. Test the connection from a pod

     ➜ k run test --image nginx:alpine --rm -i \
         --restart Never -- curl http://example.com/app1
    

Helm

Following helm commands to manage releases, charts, and repositories is more than enough for the exam.

Working with repositories

# list repositories
helm repo ls

# add a repository
helm repo add bitnami https://charts.bitnami.com/bitnami

# fetch latest versions of charts eg. if apache has version 15.4.2 available
helm repo update

# search a chart 'nginx' in all repositories
helm search repo nginx

# search in a specific repo e.g. bitnami
helm search repo bitnami/nginx

# install a chart in a namespaace 'dev'
helm -n dev install my-nginx-release bitnami/nginx

# delete a release and all it's resources
helm uninstall my-nginx-release

Charts

Install a chart modifying a value e.g. replicaCount

➜ helm show values bitnami/apache | grep replica
## @param replicaCount Number of replicas of the Apache deployment
replicaCount: 1

# now we can overwrite default value of replicaCount
➜ helm install apacher-server-release bitnami/apache --set replicaCount=2

# we can also see values of a local chart which is inside /mychart folder
➜ helm show values ./mychart | grep image --context=3
image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""

# now we can overwrite values while creating a release
➜ helm install my-local-release-v1 ./mychart --set image.tag=1.14
# install local chart template
➜ helm install my-local-release ./mychart

# display image version in currently deployed release
➜ helm get manifest my-local-release | grep image

# show values of a local or remote chart
➜ helm show values ./mychart | grep image --context=3
image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""

# now we can overwrite values while creating a release
➜ helm install my-local-release ./mychart --set image.tag=1.14

Releases

# list running releases
helm ls

# list all releases, include pending (useful for exam)
helm ls -a

Namespaces in Helm

Passing namespace in helm command is the same as kubectl .

# list releases from specific namespace
helm -n ls

helm -n ckad install nginx-release bitnami/nginx

Docker

Save docker image as a tar file (this appeared in the exam)

# docker save image:tag > .tar
➜ docker save nginx:1.18 > nginx_img.tar

Kubernetes Doc is your biggest friend

kubernetes.io/docs is the most important asset for the exam. When you try out every lab and mock question, first search in the docs. It has answers and examples for 99% of things.

Even common things like using bash loops(inside Pods/Sidecar containers) and cron expressions(inside CronJob) can be found here which we can easily make mistakes.

Also, memorize the helm doc link: helm.sh/docs.

Exam Environment

The Firefox browser in the real exam environment was a little bit sluggish while scrolling and navigating to the right content on the Kubernetes docs page. The browser window is also small and you will have to zoom out quite a bit. Even then, the right-most section of doc with links to subtopics was not visible.

So, when you are doing a mock exam in killer.sh simulator, practice searching texts with Cmd/Ctrl+F and navigating through the text in the Kubernetes docs. It will save some time in the real exam.

Remember keywords for Kubernetes object names and attributes like Job, command:, image:, env:, secretRef e.t.c. to search quickly.


Buy me a coffee

Buy me a coffee :)

Did you find this article valuable?

Support Nirdosh Gautam by becoming a sponsor. Any amount is appreciated!