How to become a Certified Kubernetes Administrator


Feeling uncertain about things? Go through my How to become a CKAD guide as it will provide you with all the little details necessary for managing Pods, Deployments, etc.

Also, if you are in need of a PSI bridge (the browser you will use during the CKA exam) simulator, feel free to use this one: https://github.com/42eleven/cncf-psi-k8s-linux-simulator.

Grow an understanding of how to roll out a cluster

And by rolling out I mean from scratch with kubeadm. Still that’s considered “the easy way”, but at least it’s a more hands-on experience that clicking on the AWS UI to bootstrap an EKS cluster control plane.

Understand the components and the steps this process entails.

Some components useful here or later on in general:

  1. containerd: your container runtime. Needs to be installed on all your nodes, control-plane and workers.
  2. kubeadm: a tool to help you provision k8s clusters.
  3. kubelet: the kubernetes agent running on each of your nodes.
  4. kubectl: the kubernetes cli management tool.
  5. etcdctl: the etcd database cli management tool.
  6. journalctl and systemctl for managing and inspecting system processes, logs, etc.
  7. crictl for managing containers inside nodes

At this point, I can say this: you are in luck, because the official documentation has a guide for this exact process: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

Network Policies

Honestly, the best advice I can give you for NetworkPolicy objects is to go through the official docs and run a couple of examples on your own. This was the part which I had worked the least with and I found it pretty hard, but once I understood (and remembered) the conditions logic in their spec, everything made sense.

Link to official docs: https://kubernetes.io/docs/concepts/services-networking/network-policies/

Upgrading control-plane and worker nodes with Kubeadm

Control plane

  1. Install new version of kubeadm, eg. 1.22.2
sudo apt-get update && \
sudo apt-get install -y --allow-change-held-packages kubeadm=1.22.2-00
  1. Drain node
kubectl drain <node-name> --ignore-daemonsets
  1. Plan the upgrade
sudo kubeadm upgrade plan v1.22.2
  1. Apply the upgrade
sudo kubeadm upgrade apply v1.22.2
  1. Upgrade kubelet and kubectl
sudo apt-get install -y --allow-change-held-packages kubelet=1.22.2-00 kubectl=1.22.2-00
  1. Reload
sudo systemctl daemon-reload
  1. Restart kubelet for the changes to take effect
sudo systemctl restart kubelet
  1. Uncordon node
kubectl uncordon <node name>

Worker

  1. Drain the node
kubectl drain <node-name> --ignore-daemonsets
  1. Install new version of kubeadm
sudo apt-get install -y --allow-change-held-packages kubeadm=1.22.2-00
  1. Upgrade the node
sudo kubeadm upgrade node
  1. Upgrade kubelet and kubeadm
sudo apt-get install -y --allow-change-held-packages kubelet=1.22.2-00 kubectl=1.22.2-00
  1. Reload system
sudo systemctl daemon-reload
  1. Restart kubelet
sudo systemctl restart kubelet
  1. Uncordon node
kubectl uncordon <node name>

etcd backup and restore

Backup

After SSHing into the node, pin the eksctl api version via an env variable:

export ETCDCTL_API=3

Then backup the etcd data:

etcdctl snapshot save /home/user/etcd_backup.db \
--endpoints=https://etcd1:2379 \
--cacert=/home/user/etcd-certs/etcd-ca.pem \
--cert=/home/user/etcd-certs/etcd-server.crt \
--key=/home/user/etcd-certs/etcd-server.key

Restore

In order to restore etcd data from the backup, follow this process:

  1. Stop the etcd service
sudo systemctl stop etcd
  1. Delete existing data
sudo rm -rf /var/lib/etcd
  1. Restore data from the snapshot
etcdctl snapshot restore /home/user/etcd_backup.db \
--initial-cluster etcd-restore=https://etcd1:2380 \
--initial-advertise-peer-urls https://etcd1:2380 \
--name etcd-restore \   # change
--data-dir /var/lib/etcd
  1. Set the database ownership to the etcd user
sudo chown -R etcd:etcd /var/lib/etcd
  1. Start the etcd service again
sudo systemctl start etcd

This process might need to be adjusted depending on how etcd has been set up. Eg. if it’s set up as a static pod, you might need to go into /etc/kubernetes/manifests/etcd-config-file.yaml and edit the path or something similar.

Docs ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/

RBAC

Creating Service Accounts, Roles and RoleBindings

Be smart as always and create your SA easy and fast by using imperative kubectl commands.

No worries if you don’t remember the arguments for each one. Just use the --help flag to get you started, eg. kubectl create sa --help and you’ll see all the flags supported as well as common examples.

Example:

kubectl -n <namespace> create sa <name of SA> --dry-run=client -o yaml > sa.yaml

The same things, in an analogy, apply for Role, RoleBinding, ClusterRole and ClusterRoleBinding objects.

Figuring out control plane node information

You should be comfortable navigating into a Linux machine/cluster node and be able to figure out various ways a component can be set up and configured.

Some ideas to get you started:

  • Look into /etc/kubernetes/manifests for static pods
  • ps awx | grep kube to get any processes running in the system with kube in their name, eg. kubelet
  • Look into the kube-system namespace pods with kubectl -n kube-system get pods | grep kube

Understand static pods

Pods are managed by the kube api server. However, static pods are bound and managed by kubelet on a node. A static pod is specifically bound on a node. Kubelet creates a mirror pod and if it fails it’s restarted (again, by kubelet).

Manifests for static pods are stored in /etc/kubernetes/manifests. Therefore, for whatever components you find *.yaml laying out there, these are static pods.

Static pods contain their node’s name with a leading hyphen as a suffix. Eg. in a node named cluster2-node5 a static pod named test will have this name: test-cluster2-node5.

Advanced scheduling

Remember to use kubernetes.io/hostname as a topology key when implementing a podAntiAffinity. (Docs ref)

The topologyspreadconstraint is another very valid method to spread pods across nodes if you need to simulate DaemonSet’s functionality with a Deployment. (Docs ref)

Environment variables

You can add simple key-value objects in the env, or you can dynamically fetch eg. node-specific info. The following example does both.

In the pod spec:

...
spec:
    env:
    - name: foo
      value: bar
    - name: MY_NODE
      valueFrom:
        fieldRef:
            fieldPath: spec.nodeName
...

DaemonSets

DaemonSets will make sure a pod of this daemonset will run on each node of the cluster.

You might be asked to create a DaemonSet object, but fear not! You can imperatively create a Deployment object, get rid of the spec.replicas and replace Deployment with DaemonSet.

Read more in the official docs: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/

Services and Ingresses

Services

Understand the differences between the different service types:

  • NodePort: each node will have a specific port assigned to bind and listen to for that service.
  • ClusterIP: exposes the service on a cluster-internal IP.
  • LoadBalancer: creates a load balancer on your cloud provider.

Bonus:

  • ExternalName (external DNS managing this service)

Exam tip: NodePort and ClusterIP will be the ones mostly used during the exam, so make sure you know really well how to imperatively create them.

Ingresses

An ingress essentially lets services interact with the internet.

The basic info to remember is this:

  • you can configure hosts which will correspond to this ingress
  • you can back a Service (or multiple) as a backend on that ingress. The key here is to remember an ingress’ service is named backend
  • optional tls config

Ingresses are managed by Ingress Controllers. I don’t know if this type of controller is CKA material, but it doesn’t hurt to get a good understanding of how they work and what they do.

Exam tip: you will save up a lot of time if you know how to imperatively create them. Always remember to append -o yaml > ingress.yaml so that you can easily edit it if needed or if you don’t feel comfortable adding fancier path rules in the terminal.

More info:

General things to remember

  • Don’t get spooked by the time pressure. It took me about 45mins to complete the exam (passed with 92/100) and then spent another 15mins just checking around my answers in order to kill some more time. If you’re working with K8s on your day job, you won’t have to blink twice.
  • It’s easier than advertised. Caveat: you need to have a good understanding of what you do and try not to memorize a process/multi-step method just for the exam.
  • Yes, ctrl+shift+c and ctrl+shift+v work out of the box.
  • alias k=kubectl already exists in your exam machine
  • Remember to ALWAYS set the correct context. They provide you at the beginning of each question the command to set the correct context. Don’t think about it, just copy and paste it in your terminal.
  • Look up the docs! You can use k8s.io/docs, take advantage of the search function!
  • People say they use VSCode and it’s allowed. I find this cumbersome to use a UI editor when managing K8s objects, especially in a simulator. Do what’s most comfortable for you, but would probably be a good idea to stay in your terminal and potentially make vim your best friend.

Good luck!


See also