CKA — Mock Exam Part 2
Mock Exam Instructions
Welcome to Mock Exam Part 2. This is your second set of CKA-style questions.
Rules:
- 8 questions — try to complete all of them in 60 minutes
- Use only kubernetes.io/docs as a reference
- Set up your aliases first
- Switch to the specified context before starting each question
- Verify your work after each question
Combined with Part 1, these two mock exams cover a full 100% exam worth of questions.
Total points: 50%
Setup:
alias k=kubectl
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
Start your timer now.
Question 1 (7%) — etcd Restore
Context: kubectl config use-context cluster2
An etcd snapshot has been previously saved at /opt/etcd-backup.db on the controlplane node.
Restore the etcd cluster from this snapshot:
- Restore the snapshot to a new data directory
/var/lib/etcd-restored - Update the etcd static Pod manifest to use the new data directory
- Verify etcd is running with the restored data
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster2
Step 2: Restore the snapshot
ETCDCTL_API=3 etcdctl snapshot restore /opt/etcd-backup.db \
--data-dir=/var/lib/etcd-restored
Note: The restore command does NOT require certificates — it works on the snapshot file directly.
Step 3: Update the etcd static Pod manifest
vi /etc/kubernetes/manifests/etcd.yaml
Find the volumes section and locate the etcd data volume:
volumes:
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
Change the path:
volumes:
- hostPath:
path: /var/lib/etcd-restored
type: DirectoryOrCreate
name: etcd-data
Save and exit (:wq).
Step 4: Wait for etcd to restart
The kubelet will detect the manifest change and restart the etcd Pod. This may take 30–60 seconds.
# Watch until the Pod is back
watch "k get pods -n kube-system | grep etcd"
or:
# Wait and then check
sleep 30
k get pods -n kube-system | grep etcd
Step 5: Verify etcd is healthy
k get pods -n kube-system
k get nodes
k get all -A
If everything returns data, etcd is working.
Key points:
snapshot restorecreates a NEW data directory — never restore into the original directory- Only the
hostPath.pathfor the etcd-data volume needs to change in the manifest - Don’t change the
--data-dirflag in the etcd command if it maps to a volume — change the volume’shostPathinstead - Be patient — etcd restart can take up to a minute
- If etcd doesn’t come back, check
crictl psandcrictl logson the controlplane
Question 2 (4%) — Static Pod
Context: kubectl config use-context cluster1
Create a static Pod on the controlplane node with the following specifications:
- Pod name:
static-nginx - Image:
nginx:1.27 - Port: 80
The static Pod manifest path on the controlplane is /etc/kubernetes/manifests/.
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster1
Step 2: Generate the Pod YAML
k run static-nginx --image=nginx:1.27 --port=80 $do > /etc/kubernetes/manifests/static-nginx.yaml
Or create it manually:
cat <<EOF > /etc/kubernetes/manifests/static-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-nginx
labels:
run: static-nginx
spec:
containers:
- name: static-nginx
image: nginx:1.27
ports:
- containerPort: 80
EOF
Step 3: Verify
The kubelet will automatically detect the manifest and create the Pod. Wait a few seconds, then:
k get pods -A | grep static-nginx
You should see static-nginx-controlplane running. Static Pods have the node name appended.
Key points:
- Static Pods are managed by the kubelet, not the API server
- Place the manifest in the
staticPodPathdirectory (check/var/lib/kubelet/config.yamlif unsure) - Static Pod names get the node name appended as a suffix
- You don’t need
kubectl apply— the kubelet picks up the manifest automatically - To delete a static Pod, remove the manifest file
Question 3 (7%) — Troubleshoot DNS
Context: kubectl config use-context cluster3
Pods in the cluster cannot resolve Service names. DNS resolution is failing.
Diagnose and fix the DNS issue so that Pods can resolve Services again.
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster3
Step 2: Confirm the DNS issue
k run dns-test --image=busybox:1.36 --rm -it --restart=Never \
-- nslookup kubernetes.default
If this times out or returns SERVFAIL, DNS is indeed broken.
Step 3: Check CoreDNS Pods
k get pods -n kube-system -l k8s-app=kube-dns
Common findings:
- Pods in CrashLoopBackOff: Configuration error
- Pods not running (0 replicas): Deployment scaled down
- Pods in Pending: Resource issues or scheduling issues
Step 4: Check CoreDNS Deployment
k get deployment coredns -n kube-system
k describe deployment coredns -n kube-system
Step 5: Check CoreDNS logs
k logs -n kube-system -l k8s-app=kube-dns --tail=50
Step 6: Common fixes
If CoreDNS Pods are in CrashLoopBackOff — check the Corefile ConfigMap:
k get configmap coredns -n kube-system -o yaml
Look for typos in the Corefile. Common errors:
- Typo in
kubernetes cluster.localline - Missing or extra braces
- Wrong plugin names
Fix the ConfigMap:
k edit configmap coredns -n kube-system
Then restart the Pods:
k rollout restart deployment coredns -n kube-system
If CoreDNS Deployment has 0 replicas:
k scale deployment coredns -n kube-system --replicas=2
If CoreDNS Pods are Pending (scheduling issue):
k describe pod <coredns-pod-name> -n kube-system
Check events for scheduling errors (taints, resource constraints).
Step 7: Verify the fix
k run dns-test2 --image=busybox:1.36 --rm -it --restart=Never \
-- nslookup kubernetes.default
Should return the Service IP for kubernetes.default.
Key points:
- CoreDNS Pods have the label
k8s-app=kube-dns - Check Pods → Deployment → ConfigMap → Logs, in that order
- The Corefile is stored in the
corednsConfigMap inkube-system - After fixing the ConfigMap, restart the Deployment to pick up changes
Question 4 (7%) — Ingress with TLS
Context: kubectl config use-context cluster2
An Ingress controller is already running in the cluster. Create an Ingress resource named app-ingress in namespace web with the following rules:
- Host:
app.example.com - Path
/shop(Prefix) → Serviceshop-svcon port 80 - Path
/api(Prefix) → Serviceapi-svcon port 80 - TLS enabled using Secret
app-tlsfor hostapp.example.com
Assume the Services shop-svc and api-svc already exist in namespace web.
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster2
Step 2: Create the Ingress YAML
cat <<EOF | k apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /shop
pathType: Prefix
backend:
service:
name: shop-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
EOF
Step 3: Verify
k get ingress app-ingress -n web
k describe ingress app-ingress -n web
Check that:
- Both paths are listed with correct backends
- TLS section shows the host and secret name
- No errors in the events
Key points:
- API version is
networking.k8s.io/v1(notv1beta1) pathTypeis required — usePrefixorExact- TLS secret must contain
tls.crtandtls.keykeys - The
tls.hostsmust match therules.host - You can find a complete Ingress YAML example in the kubernetes.io docs by searching “ingress”
Question 5 (4%) — DaemonSet with Toleration
Context: kubectl config use-context cluster1
Create a DaemonSet named log-collector in namespace kube-system with:
- Image:
fluentd:v1.16 - The DaemonSet must run on ALL nodes, including the control plane node
- Add the necessary toleration for control plane nodes
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster1
Step 2: Create the DaemonSet YAML
There’s no imperative command to create a DaemonSet, so create it from YAML:
cat <<EOF | k apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
namespace: kube-system
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: fluentd
image: fluentd:v1.16
EOF
Alternative: Tolerate everything (runs on any tainted node):
tolerations:
- operator: Exists
Step 3: Verify
k get daemonset log-collector -n kube-system
k get pods -n kube-system -l app=log-collector -o wide
Verify that Pods are running on ALL nodes, including the control plane.
Key points:
- Control plane nodes typically have the taint
node-role.kubernetes.io/control-plane:NoSchedule - Without the toleration, DaemonSet Pods won’t schedule on the control plane
operator: Existswithout avaluematches any value for that taint key- You can use
k describe node controlplane | grep Taintto find exact taint keys
Question 6 (7%) — Troubleshoot Broken Scheduler
Context: kubectl config use-context cluster3
New Pods are being created but remain in Pending state. All nodes are Ready. Investigate and fix the issue.
Hint: A control plane component may not be running.
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster3
Step 2: Confirm the issue
k get pods -A
Look for Pending Pods. Also check if all control plane components are running:
k get pods -n kube-system
If kube-scheduler Pod is not running or in CrashLoopBackOff, the scheduler is broken.
Step 3: Check the scheduler Pod
k describe pod kube-scheduler-controlplane -n kube-system
Look at events for error messages.
Step 4: Check the static Pod manifest
The scheduler is a static Pod. Its manifest is at:
cat /etc/kubernetes/manifests/kube-scheduler.yaml
Step 5: Find the error
Common issues:
- Typo in the binary name (e.g.,
kube-schedulerrinstead ofkube-scheduler) - Wrong
--kubeconfigpath - Wrong port or bind address
Look at the command or spec.containers[0].command section:
grep -A5 "command" /etc/kubernetes/manifests/kube-scheduler.yaml
Step 6: Fix the manifest
vi /etc/kubernetes/manifests/kube-scheduler.yaml
Fix the typo or misconfiguration. For example, if the command says:
command:
- kube-schedulerr # typo — extra 'r'
Fix it to:
command:
- kube-scheduler
Save and exit (:wq).
Step 7: Wait for the scheduler to restart
# The kubelet will restart the static Pod automatically
sleep 20
k get pods -n kube-system | grep scheduler
Step 8: Verify Pending Pods are now scheduled
k get pods -A
Previously Pending Pods should now be Running or at least scheduled to a node.
Key points:
- Pending Pods + all nodes Ready = likely a scheduler issue
- kube-scheduler is a static Pod in
/etc/kubernetes/manifests/ - Check the manifest for typos — this is a common CKA trick
- After fixing the manifest, the kubelet automatically restarts the Pod
- Use
crictl psandcrictl logsifkubectlcan’t show the Pod
Question 7 (7%) — ServiceAccount & ClusterRole
Context: kubectl config use-context cluster2
Create the following RBAC setup:
- Create a ServiceAccount named
monitoring-sain namespacemonitoring(create the namespace if needed) - Create a ClusterRole named
pod-readerthat allowsget,list, andwatchon Pods cluster-wide - Create a ClusterRoleBinding named
monitoring-pod-readerthat binds the ClusterRole to the ServiceAccount - Verify the ServiceAccount can list Pods in any namespace
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster2
Step 2: Create the namespace
k create namespace monitoring
Step 3: Create the ServiceAccount
k create serviceaccount monitoring-sa -n monitoring
Step 4: Create the ClusterRole
k create clusterrole pod-reader \
--verb=get,list,watch \
--resource=pods
Step 5: Create the ClusterRoleBinding
k create clusterrolebinding monitoring-pod-reader \
--clusterrole=pod-reader \
--serviceaccount=monitoring:monitoring-sa
Note the ServiceAccount format: namespace:name → monitoring:monitoring-sa
Step 6: Verify
# Can list Pods in default namespace
k auth can-i list pods --as=system:serviceaccount:monitoring:monitoring-sa
# Can list Pods in kube-system namespace
k auth can-i list pods --as=system:serviceaccount:monitoring:monitoring-sa -n kube-system
# Can watch Pods cluster-wide
k auth can-i watch pods --as=system:serviceaccount:monitoring:monitoring-sa -A
# Should NOT be able to delete Pods
k auth can-i delete pods --as=system:serviceaccount:monitoring:monitoring-sa
All list/get/watch checks should return yes. The delete check should return no.
Key points:
- ClusterRole + ClusterRoleBinding = cluster-wide access
- ClusterRole + RoleBinding = namespaced access (reusable ClusterRole, limited by RoleBinding namespace)
- ServiceAccount format in
--serviceaccountflag:namespace:name - ServiceAccount format in
--asflag:system:serviceaccount:namespace:name - Don’t confuse
RolewithClusterRole— Role is namespaced, ClusterRole is cluster-wide
Question 8 (7%) — Resource Sorting with kubectl
Context: kubectl config use-context cluster1
Perform the following tasks:
- List all Pods in the
kube-systemnamespace sorted by CPU usage (highest first). Save the output to/opt/cpu-usage.txt - Find the node with the most allocated memory and save just the node name to
/opt/high-memory-node.txt
Show Answer
Solution
Step 1: Switch context
kubectl config use-context cluster1
Step 2: Sort Pods by CPU usage
k top pods -n kube-system --sort-by=cpu > /opt/cpu-usage.txt
Or with no headers for cleaner output:
k top pods -n kube-system --sort-by=cpu --no-headers > /opt/cpu-usage.txt
Verify:
cat /opt/cpu-usage.txt
Step 3: Find the node with most allocated memory
k top nodes --sort-by=memory
This shows nodes sorted by memory usage. The first row (after the header) is the node using the most memory.
Extract just the node name:
k top nodes --sort-by=memory --no-headers | head -1 | awk '{print $1}' > /opt/high-memory-node.txt
Verify:
cat /opt/high-memory-node.txt
Key points:
kubectl toprequires the Metrics Server to be running in the cluster--sort-by=cpusorts by CPU,--sort-by=memorysorts by memory--no-headersremoves the header row (useful when piping to files)- Use
awk '{print $1}'to extract the first column (name) - The
>operator writes to file (overwrite). Use>>to append. - The exam may ask you to save output in a specific format — read carefully
Scoring
Grade yourself honestly:
| Question | Points | Your Score |
|---|---|---|
| Q1 — etcd Restore | 7% | ___ |
| Q2 — Static Pod | 4% | ___ |
| Q3 — Troubleshoot DNS | 7% | ___ |
| Q4 — Ingress with TLS | 7% | ___ |
| Q5 — DaemonSet + Toleration | 4% | ___ |
| Q6 — Troubleshoot Scheduler | 7% | ___ |
| Q7 — ServiceAccount & ClusterRole | 7% | ___ |
| Q8 — Resource Sorting | 7% | ___ |
| Total | 50% | ___ |
Combined Score (Part 1 + Part 2)
| Mock Exam | Score |
|---|---|
| Part 1 | ___/50% |
| Part 2 | ___/50% |
| Total | ___/100% |
Benchmark:
- 80–100%: Excellent. You’re ready for the exam.
- 66–79%: Good — you’d pass, but review weak areas for a safety margin.
- 50–65%: Close but risky. Practice more and retake the mock exams.
- Below 50%: Keep studying. Review the chapters for your weakest domains.
Remember: The real exam passing score is 66%. Aim for 80%+ in mock exams to build a comfortable margin.