The Certified Kubernetes Administrator (CKA) certification validates that you have the skills and knowledge to perform the responsibilities of a Kubernetes administrator: cluster setup, workload deployment, networking, storage, troubleshooting, and security. The Certified Kubernetes Application Developer (CKAD) certification focuses on designing, configuring, and exposing cloud-native applications on Kubernetes and using core primitives to build, monitor, and troubleshoot applications.
This post is a practice set of sample CKA-style questions with step-by-step answers. Use it to rehearse RBAC (ServiceAccounts, ClusterRoles, ClusterRoleBindings), deployments and rollouts, etcd backup and restore, PersistentVolumes, taints and tolerations, node draining, NetworkPolicies, security contexts, and similar exam topics. Always run commands against a practice cluster (e.g. Setup Kubernetes Cluster on Ubuntu with kubeadm) and confirm the official CKA curriculum for current exam scope.
Prerequisites
- A Kubernetes cluster and
kubectlconfigured. Set the context used in the tasks (e.g.k8s):
kubectl config use-context k8s
Question 1
Create a new service account with the name pvviewer. Grant this Service account access to list all PersistentVolumes in the cluster by creating an appropriate cluster role called pvviewer-role and ClusterRoleBinding called pvviewer-role-binding.
Next, create a pod called pvviewer with the image: redis and serviceaccount: pvviewer in the default namespace.
Answer to question 1
Create Service account
kubectl create service-account pvviewer
Create cluster role
kubectl create clusterrole pvviewer-role \
--verb=list \
--resource=PersistentVolumes
Create cluster role binding
kubectl create clusterrolebinding pvviewer-role-binding \
--clusterrole=pvviewer-role \
--serviceaccount=default:pvviewer
Verify
kubectl auth can-i list PersistentVolumes \
--as system:serviceaccount:default:pvviewer
Generate yaml for the pod
kubectl run pvviewer --image=redis --dry-run=client -o yaml
this
apiVersion: v1
kind: Pod
metadata:
labels:
run: pvviewer
name: pvviewer
namespace: default
spec:
serviceAccount: pvviewer
containers:
- image: redis
name: redis
dnsPolicy: ClusterFirst
restartPolicy: Always
Question 2
Create a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica. Record the version. Next upgrade the deployment to version 1.17 using rolling update. Make sure that the version upgrade is recorded in the resource annotation.
Answer to question 2
To generate manifest
kubectl create deployment nginx-deploy \
--image=nginx:1.16 --dry-run=client -o yaml
This is the generated yml file
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.16
name: nginx
ports:
- containerPort: 80
Apply
kubectl apply -f nginx-deploy.yaml --record
kubectl get deployment
kubectl rollout history deployment nginx-deploy
kubectl set image deployment/nginx-deploy nginx=nginx:1.17 --record
kubectl rollout history deployment nginx-deploy
kubectl describe deployment nginx-deploy
Question 3
Create snapshot of the etcd running at https://127.0.0.1:2379. Save snapshot into /opt/etcd-snapshot.db.
Use these certificates for the snapshot
Ca certificate: /etc/kubernetes/pki/etcd/ca.crt
Client certicate: /etc/kubernetes/pki/etcd/server.crt
client key: /etc/kubernetes/pki/etcd/server.key
and then restore from the previous ETCD backup.
Answer to question 3
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /opt/etcd-snapshot.db
Verify
Note: Do not perform this step in exam otherwise it may create an issue in the restoration process.
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot status /opt/etcd-snapshot.db
ETCDCTL_API=3 etcdctl --write-out=table snapshot status /opt/etcd-snapshot.db
Restore
No need to remember all the flags in the restore command:
You can do
sudo systemctl stop etcd
ETCDCTL_API=3 etcdctl snapshot restore -h
ETCDCTL_API=3 etcdctl snapshot restore /opt/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--data-dir=/var/lib/etcd \
--initial-advertise-peer-urls=http://10.0.0.4:2380 \
--initial-cluster=<master-name>=http://10.0.0.4:2380 \
--initial-cluster-token=etcd-cluster --name=<master-name>
sudo systemctl restart etcd
Question 4
Create a Persistent Volume with the given specification.
Volume Name: pv-analytics, Storage: 100Mi, Access modes: ReadWriteMany, Host Path: /pv/data-analytics
Answer to question 4
vim pv.yaml
pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-analytics
spec:
capacity:
storage: 100Mi
accessModes:
- ReadWriteMany
hostPath:
path: /pv/data-analytics
Then apply
kubectl create -f pv.yaml
kubectl get pv
Note: Research on persistent volumes kubernetes
Question 5
Taint the worker node to be Unschedulable. Once done, create a pod called dev-redis, image redis:alpine to ensure workloads are not scheduled to this worker node. Finally, create a new pod called prod-redis and image redis:alpine with toleration to be scheduled on node01.
key:env_type, value:production, operator: Equal and effect:NoSchedule
kubectl get nodes
kubectl taint node node01 env_type=production:NoSchedule
kubectl describe nodes node01 | grep -i taint
kubectl run dev-redis --image=redis:alpine --dry-run=client -o yaml > pod-redis.yaml
vim prod-redis.yaml
file
apiVersion: v1
kind: Pod
metadata:
name: prod-redis
spec:
containers:
- name: prod-redis
image: redis:alpine
tolerations:
- effect: NoSchedule
key: env_type
operator: Equal
value: production
apply
kubectl create -f prod-redis.yaml
Read More: Scheduling in K8s
Question 6
Set the node named worker node as unavailable and reschedule all the pods running on it. (Drain node)
Answer for question 6
kubectl get nodes
kubectl drain node <worker-node> --ignore-daemonsets
kubectl get nodes
Question 7
Create a Pod called non-root-pod , image: redis:alpine
runAsUser: 1000
fsGroup: 2000
Answer to question 7
file non-root-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: non-root-pod
spec:
securityContext:
runAsUser: 1000
fsGroup: 2000
containers:
- name: non-root-pod
image: redis:alpine
Create
kubectl create -f non-root-pod.yaml
Question 8
Create a NetworkPolicy which denies all ingress traffic
Answer to question 8
File policy.yaml:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
Apply
kubectl create -f policy.yaml
Read More: K8s Network Policy
Question 9
Context -
You have been asked to create a new ClusterRole for a deployment pipeline and bind it to a specific ServiceAccount scoped to a specific namespace.
Task -
Create a new ClusterRole named deployment-clusterrole, which only allows to create the following resource types:
✑ Deployment
✑ Stateful Set
✑ DaemonSet
Create a new ServiceAccount named cicd-token in the existing namespace app-team1.
Bind the new ClusterRole deployment-clusterrole to the new ServiceAccount cicd-token, limited to the namespace app-team1.
Answer to question 9
kubectl config use-context k8s
kubectl create namespace app-team1 # if it does not exist
kubectl create serviceaccount cicd-token -n app-team1
kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
kubectl create clusterrolebinding deploy-b --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token
Question 10
Task -
Given an existing Kubernetes cluster running version 1.22.1, upgrade all of the Kubernetes control plane and node components on the master node only to version 1.22.2.
Be sure to drain the master node before upgrading it and uncordon it after the upgrade.
You are also expected to upgrade kubelet and kubectl on the master node.
Do not upgrade the worker nodes, etcd, the container runtime, the CNI plugin, the DNS service, or other add-ons.
Answer to Question 10
kubectl config use-context k8s
k get nodes
kubectl drain mk8s-master-0 --ignore-daemonsets
k get nodes
ssh mk8s-master-0
sudo -i
apt install kubeadm=1.22.2-00 kubelet=1.22.2-00 kubectl=1.22.2-00
kubeadm upgrade plan
kubeadm upgrade apply 1.22.2
systemctl restart kubelet
exit
kubectl uncordon mk8s-master-0
k get nodes
Question 11
Task -
Create a new NetworkPolicy named allow-port-from-namespace in the existing namespace fubar.
Ensure that the new NetworkPolicy allows Pods in namespace internal to connect to port 9000 of Pods in namespace fubar.
Further ensure that the new NetworkPolicy:
✑ does not allow access to Pods, which don’t listen on port 9000
✑ does not allow access from Pods, which are not in namespace internal
Answer to Question 11
kubectl config use-context k8s
vi policy.yml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace
namespace: fubar
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: internal
ports:
- protocol: TCP
port: 9000
# Label namespace internal so the policy can select it
kubectl label namespace internal name=internal --overwrite
kubectl create -f policy.yml -n fubar
Question 12
Task -
Reconfigure the existing deployment front-end and add a port specification named http exposing port 80/tcp of the existing container nginx.
Create a new service named front-end-svc exposing the container port http.
Configure the new service to also expose the individual Pods via a NodePort on the nodes on which they are scheduled.
Answer to question 12
kubectl config use-context k8s
k get deploy
# Edit deployment front-end and add container port name "http" and port 80
kubectl edit deploy front-end
# Add to the nginx container: ports: - name: http containerPort: 80
kubectl expose deploy front-end --name=front-end-svc --port=80 --type=NodePort --target-port=80
kubectl describe svc front-end-svc
Question 13
Scale the deployment presentation to 3 pods.
Answer to question 13
kubectl config use-context k8s
k scale deploy presentation --replicas=3
k get deploy
k get po
Question 14
Schedule a pod as follows:
- Name:
nginx-kusc00401 - Image:
nginx - Node selector:
disk=ssd
Answer to question 14
kubectl config use-context k8s
kubectl run nginx-kusc00401 --image=nginx --dry-run=client -o yaml
pod
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx-kusc00401
name: nginx-kusc00401
spec:
containers:
- image: nginx
name: nginx-kusc00401
dnsPolicy: ClusterFirst
restartPolicy: Always
nodeSelector:
disk: ssd
kubectl apply -f pod.yml
Question 15
Check to see how many nodes are ready (not including nodes tainted NoSchedule) and write the number to /opt/KUSC00402/kusc00402.txt.
Answer to question 15
kubectl get nodes
echo 2 > /opt/KUSC00402/kusc00402.txt
cat /opt/KUSC00402/kusc00402.txt
Question 16
Schedule a Pod as follows:
- Name:
kucc8 - App
Containers: 2 - Container Name/Images:
- nginx
- consul
Answer to question 16
kubectl run kucc8 --image=nginx --dry-run=client -o yaml > app2.yml
vi app2.yml
apiVersion: v1
kind: Pod
metadata:
labels:
run: kucc8
name: kucc8
spec:
containers:
- image: nginx
name: nginx
- image: consul
name: consul
Watch till they run
k get po
Question 17
Create a persistent volume with name app-data, of capacity 2Gi and access mode ReadOnlyMany. The type of volume is hostPath and its location is /srv/app-data.
Answer to question 17
kubectl config use-context k8s
vi pv1.yml
pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: app-data
spec:
capacity:
storage: 2Gi
accessModes:
- ReadOnlyMany
hostPath:
path: /srv/app-data
k apply -f pv1.yml
k get pv
Question 18
Monitor the logs of pod foo and:
- Extract log lines corresponding to error
file-not-found - Write them to
/opt/KUTR00101/foo
Answer to question 18
kubectl config use-context k8s
kubectl get pods
kubectl logs foo | grep file-not-found > /opt/KUTR00101/foo
Question 19
Context -
An existing Pod needs to be integrated into the Kubernetes built-in logging architecture (e.g. kubectl logs). Adding a streaming sidecar container is a good and common way to accomplish this requirement.
Task -
Add a sidecar container named sidecar, using the busybox image, to the existing Pod big-corp-app. The new sidecar container has to run the following command:
/bin/sh -c "tail -n+1 -f /var/log/big-corp-app.log"
Use a Volume, mounted at /var/log, to make the log file big-corp-app.log available to the sidecar container.
Don’t modify the specification of the existing container other than adding the required volume mount
Answer to question 19
k get po big-corp-app -o yaml > big-corp-app.yml
vim big-corp-app.yml
big-corp-app.yml diff
apiVersion: v1
kind: Pod
metadata:
labels:
run: big-corp-app
name: big-corp-app
spec:
containers:
- image: busybox
name: sidecar
command: ["/bin/sh"]
args: ["-c", "tail -n+1 -f /var/log/big-corp-app.log"]
volumeMounts:
- mountPath: /var/log
name: logs
- image: lfcert/monitor:latest
name: monitor
imagePullPolicy: Always
env:
- name: LOG_FILENAME
value: /var/log/big-corp-app.log
volumeMounts:
- mountPath: /var/log
name: logs
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
Update then
kubectl apply -f big-corp-app.yml
kubectl get pods
Question 20
From the pod label name=overloaded-cpu, find pods running high CPU workloads and write the name of the pod consuming most CPU to the file /opt/KUTR00401/KUTR00401.txt (which already exists).
Answer to question 20
kubectl config use-context k8s
k top po -l name=overloaded-cpu --sort-by=cpu
echo "<pod name>" > /opt/KUTR00401/KUTR00401.txt
cat /opt/KUTR00401/KUTR00401.txt
Question 21
A Kubernetes worker node, named wk8s-node-0 is in state NotReady.
Investigate why this is the case, and perform any appropriate steps to bring the node to a Ready state, ensuring that any changes are made permanent.
Answer to question 21
kubectl config use-context k8s
kubectl get nodes
kubectl describe node wk8s-node-0
ssh wk8s-node-0
sudo -i
systemctl enable --now kubelet
systemctl restart kubelet
systemctl status kubelet
exit
kubectl get nodes
Summary
This practice set covered sample CKA-style tasks and answers:
- RBAC: ServiceAccounts, ClusterRoles, ClusterRoleBindings (Q1, Q9)
- Workloads: Pods, Deployments, rolling updates, scaling (Q2, Q7, Q12, Q13, Q14, Q16)
- Storage: PersistentVolumes, hostPath (Q4, Q17)
- Scheduling: Taints, tolerations, nodeSelector, drain, uncordon (Q5, Q6, Q10, Q15)
- etcd: Snapshot save and restore (Q3)
- Networking: NetworkPolicy for deny-all ingress and allow-from-namespace (Q8, Q11)
- Observability: Logs, sidecar,
kubectl top(Q18, Q19, Q20) - Troubleshooting: Node NotReady, kubelet (Q21)
Use a practice cluster and the official CKA curriculum to align with the current exam. For cluster setup, see Setup Kubernetes Cluster on Ubuntu with kubeadm.
Related Posts
- Setup Kubernetes Cluster on Ubuntu 20.04 with kubeadm – Build a cluster to practice on
- How to Setup Prometheus Monitoring on Kubernetes – Monitoring and observability
- Kubernetes TLS Security Hardening (Traefik & Nginx) – Security and TLS