CKA 개요
25년 2월 18일 변경 이후 시험 범위
- Cluster Architecture, Installation & Configuration 25%
- Manage role based access control (
RBAC) - Prepare underlying infrastructure for installing a Kubernetes cluster
- Create and manage Kubernetes clusters using
kubeadm - Manage the lifecycle of Kubernetes clusters
- Implement and configure a highly-available control plane
- Use
HelmandKustomizeto install cluster components - Understand extension interfaces (
CNI,CSI,CRI, etc.) - Understand
CRDs, install and configure operators
- Manage role based access control (
- Workloads & Scheduling 15%
- Understand application
deploymentsand how to performrolling updateandrollbacks - Use
ConfigMapsandSecretsto configure applications - Configure workload
autoscaling - Understand the primitives used to create robust, self-healing, application deployments
- Configure Pod admission and scheduling (
limits,node affinity, etc.)
- Understand application
- Services & Networking 20%
- Understand connectivity between Pods
- Define and enforce
Network Policies - Use
ClusterIP,NodePort,LoadBalancerservicetypes and endpoints - Use the
Gateway APIto manage Ingress traffic - Know how to use
Ingresscontrollers and Ingress resources - Understand and use
CoreDNS
- Storage 10%
- Implement
storage classesand dynamic volume provisioning - Configure
volume types,access modesandreclaim policies - Manage
persistent volumesandpersistent volume claims
- Implement
- Troubleshooting 30%
- Troubleshoot clusters and
nodes - Troubleshoot
cluster components - Monitor cluster and application resource usage
- Manage and evaluate container output streams
- Troubleshoot services and networking
- Troubleshoot clusters and
CKA Practice Questions
Lightning Lab
- kubeadm upgrade
- kubectl custom column
- kubeconfig 수정
- Deployment
k set image deployment test nginx=nginx:1.17 - PVC 수정
- ETCD 백업
- Pod 에 Secret volumeMounts
Mock Exam 1
- Env var, sidecar pattern, multi container 파드 생성
- bob 으로 node01 ssh 후 dpkg
- crd grep 해서 txt 저장
- 6379 포트로 파드 서비스 생성
- Deployment 생성
- 파드 트러블슈팅
- 30082 노드포트로 서비스 생성
- PV 생성
- HPA 생성
- VPA 생성
- GW 생성
- helm 차트 업그레이드
Mock Exam 2
- SC 생성
- Sidecar pattern, multi container deployment 생성
- Ingress 생성, class 꼭 지정
- Deployment
k set image deployment test nginx=nginx:1.17 - CSR, Role, Role Binding 생성
- 서비스 생성 후
k run test --image=busybox --rm -it --restart=Never -- nslookup - Static Pod 생성
- HPA 생성
- GW TLS 설정
helm get allhelm uninstall- Network Policy 생성
Mock Exam 3
net.ipv4.ip_forward = 1sysctl- ServiceAccount, ClusterRole, ClusterRoleBinding 생성
- StorageClass 생성
- ConfigMap 생성, Pod 에
spec.containers.envFrom[0].configMapRef.name로 환경변수 설정 - PriorityClass 생성, Pod 에
spec.priorityClassName에 연결 - NetworkPolicy 생성, Ingress TCP 80 만 전체허용
- Node Taint, Pod 에
spec.tolerations설정 - PVC 수정
- kubeconfig 수정 후 테스트
- kube-controller-manager 트러블슈팅
- HPA 생성, Pods
requests_per_second기준으로 스케일링 설정 - HTTPRoute 생성
helm install로컬에 있는 차트로 생성kubeadm-configConfigMap 에서podSubnet값 추출
prepium.sh
- prepium.sh Q1. CNI
- prepium.sh Q2. CRDs
- prepium.sh Q3. Network Policy
- prepium.sh Q4. TLS ConfigMap
- prepium.sh Q5. Gateway API
- prepium.sh Q6. Resource Requests and Limits
- prepium.sh Q7. Sidecar
- prepium.sh Q8. Taints & Tolerations
- prepium.sh Q9. StorageClass
- prepium.sh Q10. Priority Class
JayDemy
- prepium.sh Q4. TLS ConfigMap
- prepium.sh Q5. Gateway API
- JayDemy Q3. HPA
- JayDemy Q4. Ingress
- prepium.sh Q1. CNI
- prepium.sh Q1. CNI
- JayDemy Q7. Install ArgoCD
- prepium.sh Q10. Priority Class
- JayDemy Q9. NodePort Service
- prepium.sh Q9. StorageClass
- prepium.sh Q7. Sidecar
- prepium.sh Q2. CRDs
- prepium.sh Q6. Resource Requests and Limits
- JayDemy Q14. Pod PVC
- JayDemy Q15. CRI, systemctl
- JayDemy Q16. Troubleshooting, crictl, journalctl
- prepium.sh Q3. Network Policy
DumbITGuy
- JayDemy Q14. Pod PVC
- JayDemy Q7. Install ArgoCD
- prepium.sh Q7. Sidecar
- prepium.sh Q6. Resource Requests and Limits
- x
- prepium.sh Q2. CRDs
- prepium.sh Q10. Priority Class
- prepium.sh Q1. CNI
- JayDemy Q15. CRI, systemctl
- prepium.sh Q8. Taints & Tolerations
- prepium.sh Q5. Gateway API
- JayDemy Q4. Ingress
- prepium.sh Q3. Network Policy
- prepium.sh Q9. StorageClass
- JayDemy Q16. Troubleshooting, crictl, journalctl
- DumbITGuy Q16. NodePort Service
- prepium.sh Q4. TLS ConfigMap
killer.sh: CKA-A
| Question | 1st attempt | 2nd attempt | 3rd attempt |
|---|---|---|---|
| 1. Contexts | ❌ 0/3 | ✅ 3/3 | ✅ 3/3 |
| 2. CRD, Helm, cert-manager | ✅ 5/5 | ✅ 5/5 | ✅ 5/5 |
| 3. Scale down StatefulSet | ✅ 1/1 | ✅ 1/1 | ✅ 1/1 |
| 4. Find Pods first to be terminated | ❌ 0/1 | ✅ 1/1 | ✅ 1/1 |
| 5. Kustomize configure HPA Autoscaler | ⚠️ 5/6 | ✅ 6/6 | ✅ 6/6 |
| 6. Storage, PV, PVC, Pod volume | ✅ 6/6 | ✅ 6/6 | ✅ 6/6 |
| 7. Node and Pod Resource Usage | ✅ 2/2 | ✅ 2/2 | ✅ 2/2 |
| 8. Update Kubernetes Version and join cluster | ❌ 0/4 | ✅ 4/4 | ✅ 4/4 |
| 9. Contact K8s API from inside Pod | ✅ 2/2 | ✅ 2/2 | ✅ 2/2 |
| 10. RBAC ServiceAccount Role RoleBinding | ✅ 6/6 | ✅ 6/6 | ✅ 6/6 |
| 11. DaemonSet on all Nodes | ✅ 4/4 | ✅ 4/4 | ✅ 4/4 |
| 12. Deployment on all Nodes | ✅ 11/11 | ✅ 11/11 | ✅ 11/11 |
| 13. Gateway API Ingress | ✅ 5/5 | ✅ 5/5 | ✅ 5/5 |
| 14. Check how long certificates are valid | ❌ 0/2 | ✅ 2/2 | ✅ 2/2 |
| 15. NetworkPolicy | ✅ 7/7 | ✅ 7/7 | ✅ 7/7 |
| 16. Update CoreDNS Configuration | ❌ 0/3 | ⚠️ 1/3 | ✅ 3/3 |
| 17. Find Container of Pod and check info | ❌ 0/6 | ✅ 6/6 | ✅ 6/6 |
| Score | ✅ 54/74(73%) | ✅ 72/74(97%) | ✅ 74/74(100%) |
killer.sh: CKA-B
- Headless Service
- Create a Static Pod and Service
- server cert info
- Pod Ready if Service is reachable
- Kubectl sorting
- Fix Kubelet
- Etcd Operations
- Get Controlplane Information
- Kill Scheduler, Manual Scheduling
- PV PVC Dynamic Provisioning
- Create Secret and mount into Pod
- Schedule Pod on Controlplane Nodes
- Multi Containers and Pod shared Volume
- Find out Cluster Information
- Cluster Event Logging
- Namespaces and API Resources
- Operator, CRDs, RBAC, Kustomize
Cluster Architecture, Installation & Configuration 25%
CRI, kernel parameter 설정
Mock Exam 1
This question needs to be solved on node node01. To access the node using SSH, use the credentials below:
username: bob
password: caleston123
As an administrator, you need to prepare node01 to install kubernetes. One of the steps is installing a container runtime. Install the cri-docker_0.3.16.3-0.debian.deb package located in /root and ensure that the cri-docker service is running and enabled to start on boot.
ssh bob@node01
sudo su
cd /root
dpkg -i cri-docker_0.3.16.3-0.debian.deb
systemctl start cri-docker
systemctl enable cri-docker
systemctl status cri-docker
systemctl is-enabled cri-dockerMock Exam 3
You are an administrator preparing your environment to deploy a Kubernetes cluster using kubeadm. Adjust the following network parameters on the system to the following values, and make sure your changes persist reboots: net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-iptables = 1
vi /etc/sysctl.d/k8s.conf
sysctl --system
sysctl net.ipv4.ip_forwardJayDemy Q15. CRI, systemctl
Prepare a Linux system for Kubernetes. Docker is already installed, but you need to configure it for kubeadm. Task Complete these tasks to prepare the system for Kubernetes:
- Set up cri-dockerd:
- Install the Debian package
~/cri-dockerd_0.3.9.3-0.ubuntu-focal_amd64.deb - Debian packages are installed using dpkg
- Enable and start the cri-docker service
- Install the Debian package
- Configure these system parameters:
- Set
net.bridge.bridge-nf-call-iptables = 1 - Set
net.ipv6.conf.all.forwarding = 1 - Set
net.ipv4.ip_forward = 1 - Set
net.netfilter.nf_conntrack_max = 131072
- Set
sudo dpkg -i cri-dockerd_0.3.9.3-0.ubuntu-focal_amd64.deb
sudo systemctl enable --now cri-docker.service
sudo systemctl status cri-docker.servicesudo bash -c 'cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.ip_forward = 1
net.netfilter.nf_conntrack_max = 131072
EOF'
sudo sysctl --system # 적용
sysctl net.bridge.bridge-nf-call-iptables # 검증CNI, podSubnet
Mock Exam 3
While preparing to install a CNI plugin on your Kubernetes cluster, you typically need to confirm the cluster-wide Pod network CIDR. Identify the Pod subnet configured for the cluster (the value specified under podSubnet in the kubeadm configuration). Output this CIDR in the format x.x.x.x/x to a file located at /root/pod-cidr.txt.
Note: Use the cluster-wide podSubnet from the kubeadm-config ConfigMap, not the per-node CIDR from kubectl get node.
k -n kube-system get cm kubeadm-config -o yaml | awk '/podSubnet:/{print $2}' > /root/pod-cidr.txt
# OR cat /etc/kubernetes/manigests/kube-controller-manager.yaml | grep "--cluster-cidr"
cat /root/pod-cidr.txt
172.17.0.0/16prepium.sh Q1. CNI
Install and configure one Container Network Interface (CNI) plugin from the options below. Available options
- Flannel v0.26.1 - manifest
kube-flannel.yml - Calico v3.28.2 - install the Tigera operator manifest, then apply the Calico custom resources manifest
tigera-operator.yamlcustom-resources.yamlRequirements The CNI you install must: - allow pods to communicate with each other
- support Kubernetes NetworkPolicy enforcement
- be installed from manifests
# NetworkPolicy 적용이 가능한 Calico 설치
k apply -f operator.yaml
k -n kube-system get cm kubeadm-config -o yaml | awk '/podSubnet:/{print $2}' # 10.244.0.0/16
curl -O https://.../custom-resources.yaml > custom-resources.yaml
vi custom-resources.yaml # spec.calicoNetwork.ipPools[0].cidr 변경
k apply -f custom-resources.yamlkubeconfig
Lighting Lab
A kubeconfig file called admin.kubeconfig has been created in /root/CKA. There is something wrong with the configuration. Troubleshoot and fix it.
# vi /root/CKA/admin.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: XXX...
server: https://controlplane:6443 # 포트 수정
name: kubernetes
...k get nodes --kubeconfig /root/CKA/admin.kubeconfig # kubeconfig 작동 확인killer.sh: CKA-A Q1. Contexts
Configure Access to Multiple Clusters Cluster Access with kubeconfig
Solve this question on: ssh cka9412
You’re asked to extract the following information from kubeconfig file /course/1/kubeconfig on cka9412:
- Write all kubeconfig context names into
/course/1/contexts, one per line - Write the name of the current context into
/course/1/current-context - Write the client-certificate of user
account-0027base64-decoded into/course/1/cert
ssh cka9412
k --kubeconfig /course/1/kubeconfig config get-contexts -o name > /course/1/contexts
k --kubeconfig /course/1/kubeconfig config current-context > /course/1/current-context
k --kubeconfig /course/1/kubeconfig config view --raw -o jsonpath="{.users[0].user.client-certificate-data}" | base64 -d > /course/1/certkubeadm Cluster Upgrade & Certificates
Lighting Lab
Upgrade the current version of kubernetes from 1.34.0 to 1.35.0 exactly using the kubeadm utility. Make sure that the upgrade is carried out one node at a time starting with the controlplane node. To minimize downtime, the deployment gold-nginx should be rescheduled on an alternate node before upgrading each node.
Upgrade controlplane node first and drain node node01 before upgrading it. Pods for gold-nginx should run on the controlplane node subsequently.
# controlplane
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt-cache madison kubeadm
sudo apt-mark unhold kubeadm && \
sudo apt-get update && sudo apt-get install -y kubeadm='1.35.0-1.1' && \
sudo apt-mark hold kubeadm
sudo kubeadm upgrade plan v1.35.0
sudo kubeadm upgrade apply v1.35.0
kubectl drain controlplane --ignore-daemonsets
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get update && sudo apt-get install -y kubelet='1.35.0-1.1' kubectl='1.35.0-1.1' && \
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
kubectl uncordon controlplane# workernode
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt-cache madison kubeadm
sudo apt-mark unhold kubeadm && \
sudo apt-get update && sudo apt-get install -y kubeadm='1.35.0-1.1' && \
sudo apt-mark hold kubeadm
sudo kubeadm upgrade node
kubectl drain node01 --ignore-daemonsets
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get update && sudo apt-get install -y kubelet='1.35.0-1.1' kubectl='1.35.0-1.1' && \
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
kubectl uncordon node01killer.sh: CKA-A Q8. Update Kubernetes Version and join cluster
Upgrading kubeadm clusters kubeadm join
Solve this question on: ssh cka3962
Your coworker notified you that node cka3962-node1 is running an older Kubernetes version and is not even part of the cluster yet.
- Update the node’s Kubernetes to the exact version of the controlplane
- Add the node to the cluster using kubeadm
ℹ️ You can connect to the worker node using
ssh cka3962-node1fromcka3962
ssh cka3962
k get node
ssh cka3962-node1
sudo -i
kubectl version
kubelet --version
kubeadm version
kubeadm upgrade node
apt-get update
apt-cache show kubectl -a | grep 1.35
apt-get install kubectl=1.35.6-1.1 kubelet=1.35.6-1.1
kubelet --version
systemctl restart kubelet
systemctl status kubelet
exit
exit
sudo -i
kubeadm token create --print-join-command
kubeadm token list
ssh cka3962-node1
kubeadm join 192.168.100.31:6443 --token 0l00rk.sopvq9xkvuasjqij --discovery-token-ca-cert-hash sha256:7a99a324fef6f169ee76e53e0a3d968db49d267b1657a1e68d76db99eff432f4
systemctl status kubelet
exit
k get nodekiller.sh: CKA-A Q14. Check how long certificates are valid
Certificate Management with kubeadm
Solve this question on: ssh cka9412
Perform some tasks on cluster certificates:
- Check how long the kube-apiserver server certificate is valid using openssl or cfssl. Write the expiration date into
/course/14/expiration. Run thekubeadmcommand to list the expiration dates and confirm both methods show the same one - Write the
kubeadmcommand that would renew the kube-apiserver certificate into/course/14/kubeadm-renew-certs.sh
ssh cka9412
sudo -i
find /etc/kubernetes/pki | grep apiserver
openssl x509 -noout -text -in /etc/kubernetes/pki/apiserver.crt | grep Validity -A2
kubeadm certs check-expiration | grep apiserver
echo "Oct 29 14:19:27 2025 GMT" > /course/14/expiration
echo "kubeadm certs renew apiserver" > /course/14/kubeadm-renew-certs.shkiller.sh: CKA-B Q3. Kubelet client/server cert info
TLS bootstrapping Certificates best practices
Solve this question on: ssh cka5248
Node cka5248-node1 has been added to the cluster using kubeadm and TLS bootstrapping.
Find the Issuer and Extended Key Usage values on cka5248-node1 for:
- Kubelet Client Certificate, the one used for outgoing connections to the kube-apiserver
- Kubelet Server Certificate, the one used for incoming connections from the kube-apiserver
Write the information into file
/course/3/certificate-info.txt.
ℹ️ You can connect to the worker node using
ssh cka5248-node1fromcka5248
ssh cka5248
ssh cka5248-node1
openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem | grep Issuer
openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem | grep "Extended Key Usage" -A1
openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet.crt | grep Issuer
openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet.crt | grep "Extended Key Usage" -A1
# cka5248:/course/3/certificate-info.txt
Issuer: CN = kubernetes
X509v3 Extended Key Usage: TLS Web Client Authentication
Issuer: CN = cka5248-node1-ca@1730211854
X509v3 Extended Key Usage: TLS Web Server AuthenticationETCD Backup & Restore
Lighting Lab
Take the backup of ETCD at the location /opt/etcd-backup.db on the controlplane node.
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/apiserver-etcd-client.crt \
--key=/etc/kubernetes/pki/apiserver-etcd-client.key \
snapshot save /opt/etcd-backup.db
ETCDCTL_API=3 etcdctl --write-out=table snapshot status /opt/etcd-backup.dbkiller.sh: CKA-B Q7. Etcd Operations
Operating etcd clusters for Kubernetes
Solve this question on: ssh cka2560
You have been tasked to perform the following etcd operations:
- Run
etcd --versionand store the output at/course/7/etcd-version - Make a snapshot of etcd and save it at
/course/7/etcd-snapshot.db
ssh cka2560
k -n kube-system exec etcd-cka2560 -- etcd --version > /course/7/etcd-version
ETCDCTL_API=3 etcdctl snapshot save /course/7/etcd-snapshot.db \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--cert /etc/kubernetes/pki/etcd/server.crt \
--key /etc/kubernetes/pki/etcd/server.keyRBAC & CSR & SA
Mock Exam 2
Create a new user called john. Grant him access to the cluster using a csr named john-developer. Create a role developer which should grant John the permission to create, list, get, update and delete pods in the development namespace . The private key exists in the location: /root/CKA/john.key and csr at /root/CKA/john.csr.
Important Note: As of kubernetes 1.19, the CertificateSigningRequest object expects a signerName.
Please refer to the documentation to see an example. The documentation tab is available at the top right of the terminal.
# vi csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: john-developer
spec:
request: # cat /root/CKA/john.csr | base64 | tr -d '\n'
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client authk apply -f csr.yaml
k certificate approve john-developer
k create role developer --verb=create,list,get,update,delete --resource=pods -n development
k create rolebinding john --user=john --role=developer -n development
k auth can-i create pods --as=john -n developmentMock Exam 3
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.
k create serviceaccount pvviewer
k create clusterrole pvviewer-role --verb=list --resource=persistentvolumes
k create clusterrolebinding pvviewer-role-binding --clusterrole=pvviewer-role --serviceaccount=default:pvviewer# vi pvviewer.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvviewer
spec:
serviceAccountName: pvviewer
containers:
- image: redis
name: pvviewerkiller.sh: CKA-A Q9. Contact K8s API from inside Pod
Accessing the Kubernetes API from a Pod Configure Service Accounts for Pods
Solve this question on: ssh cka9412
There is ServiceAccount secret-reader in Namespace project-swan. Create a Pod of image nginx:1-alpine named api-contact which uses this ServiceAccount.
Exec into the Pod and use curl to manually query all Secrets from the Kubernetes API.
Write the result into file /course/9/result.json.
ssh cka9412
k -n project-swan run api-contact --image=nginx:1-alpine --dry-run=client -o yaml > 9.yaml# cka9412:/home/candidate/9.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: api-contact
name: api-contact
namespace: project-swan
spec:
serviceAccountName: secret-reader # add
containers:
- image: nginx:1-alpine
name: api-contactk apply -f 9.yaml
k -n project-swan exec api-contact -it -- sh
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k https://kubernetes.default/api/v1/secrets -H "Authorization: Bearer ${TOKEN}" > result.json
k -n project-swan exec api-contact -it -- cat result.json > /course/9/result.jsonkiller.sh: CKA-A Q10. RBAC ServiceAccount Role RoleBinding
Using RBAC Authorization Configure Service Accounts for Pods
Solve this question on: ssh cka3962
Create a new ServiceAccount processor in Namespace project-hamster. Create a Role and RoleBinding, both named processor as well. These should allow the new SA to only create Secrets and ConfigMaps in that Namespace.
➜ ssh cka3962
k -n project-hamster create sa processor
k -n project-hamster create role processor --verb=create --resource=secret --resource=configmap
k -n project-hamster create rolebinding processor --role processor --serviceaccount project-hamster:processor
k -n project-hamster auth can-i create secret --as system:serviceaccount:project-hamster:processorCRD
Mock Exam 1
On controlplane node, identify all CRDs related to VerticalPodAutoscaler and save their names into the file /root/vpa-crds.txt.
k get crd | grep autoscaling > /root/vpa-crds.txtprepium.sh Q2. CRDs
Task
- Create a list of all cert-manager CRDs and save it to
/root/resources.yaml - Using kubectl, extract the documentation for the subject specification field on the Certificate Custom Resource and save it to
/root/documentation.txtYou may use any output format that kubectl supports.
k get crd | grep cert-manager.io > /root/resources.yaml
k explain certificate.spec.subject > /root/documentation.txtkiller.sh: CKA-A Q2. CRD, Helm, cert-manager
Helm Docs Custom Resources
Solve this question on: ssh cka7968
Install cert-manager using Helm in Namespace cert-manager. Then configure and create a ClusterIssuer resource:
- Create Namespace
cert-manager - Install Helm chart
jetstack/cert-manager(withcrds.enabled=true) into the new Namespace. The Helm Release should be calledcert-manager - Update the
ClusterIssuerresource in/course/2/cluster-issuer.yamlto includecrlDistributionPoints: ["http://example.com/crl"]underspec.selfSigned - Create the
ClusterIssuerresource from/course/2/cluster-issuer.yaml
ℹ️ It is not required for cert-manager to issue real certificates. Installing the Helm Chart and the ClusterIssuer resource as requested is enough
ssh cka7968
k create ns cert-manager
helm -n cert-manager install cert-manager jetstack/cert-manager --set crds.enabled=true
vi /course/2/cluster-issuer.yaml# cka7968:/course/2/cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: course-issuer
spec:
selfSigned:
crlDistributionPoints: # ADD
- http://example.com/crl # ADDk apply -f /course/2/cluster-issuer.yamlHelm
Mock Exam 1
One co-worker deployed a podinfo helm chart kk-mock1 in the kk-ns namespace on the cluster. A new update is pushed to the helm chart, and the team wants you to update the helm repository to fetch the new changes.
After updating the helm chart, upgrade the helm chart version to 6.11.2.
helm list -n kk-ns
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
kk-mock1 kk-ns 1 2026-07-29 06:09:26.984079875 +0000 UTC deployed podinfo-6.11.0 6.11.0
helm search repo kk-mock1
NAME CHART VERSION APP VERSION DESCRIPTION
kk-mock1/podinfo 6.14.1 6.14.1 Podinfo Helm chart for Kubernetes
helm upgrade kk-mock1 kk-mock1/podinfo --version=6.11.2 -n kk-ns
helm list -n kk-ns
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
kk-mock1 kk-ns 2 2026-07-29 06:14:33.024776475 +0000 UTC deployed podinfo-6.11.2 6.11.2Mock Exam 2
On the cluster, the team has installed multiple helm charts on a different namespace. By mistake, those deployed resources include one of the vulnerable images called kodekloud/webapp-color:v1. Find out the release name and uninstall it.
helm list -A
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
atlanta-page-apd atlanta-page-04 1 2025-11-08 10:57:43.405721672 +0000 UTC deployed atlanta-page-apd-0.1.0 1.16.0
digi-locker-apd digi-locker-02 1 2025-11-08 10:57:40.988036054 +0000 UTC deployed digi-locker-apd-0.1.0 1.16.0
security-alpha-apd security-alpha-01 1 2025-11-08 10:57:40.109579755 +0000 UTC deployed security-alpha-apd-0.1.0 1.16.0
web-dashboard-apd web-dashboard-03 1 2025-11-08 10:57:41.989424936 +0000 UTC deployed web-dashboard-apd-0.1.0 1.16.0
helm get manifest atlanta-page-apd -n atlanta-page-04 | grep -i webapp-color:v1
image: "kodekloud/webapp-color:v1"
helm uninstall atlanta-page-apd -n atlanta-page-04
release "atlanta-page-apd" uninstalledMock Exam 3
One application, webpage-server-01, is currently deployed on the Kubernetes cluster using Helm. A new version of the application is available in a Helm chart located at /root/new-version.
Validate this new Helm chart, then install it as a new release named webpage-server-02. After confirming the new release is installed, uninstall the old release webpage-server-01.
helm lint new-version
helm install webpage-server-02 new-version
helm uninstall webpage-server-01 -n defaultJayDemy Q7. Install ArgoCD
Install Argo CD in cluster:
Add the official Argo CD Helm repository with the name argo.
The Argo CD CRDs have already been pre-installed in the cluster.
Generate a helm template of the Argo CD Helm chart version 7.7.3 for the argocd namespace and save to /argo-helm.yaml. Configure the chart to not install CRDs.
Install Argo CD using Helm with release name argocd using the same version as above and configuration as used in the template 7.7.3. Instaill it in the argocd namespace and configure it to not install CRDs.
You do not need to configure access to the Argo CD server UI.
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
k create ns argocd
helm -n argocd template argocd argo/argo-cd --version 7.7.3 --set crds.install=false > /argo-helm.yaml
helm -n argocd install argocd argo/argo-cd --version 7.7.3 --set crds.install=falseKustomize
killer.sh: CKA-A Q5. Kustomize configure HPA Autoscaler
Horizontal Pod Autoscaling Kustomize
Solve this question on: ssh cka5774
Previously the application api-gateway used some external autoscaler which should now be replaced with a HorizontalPodAutoscaler (HPA). The application has been deployed to Namespaces api-gateway-staging and api-gateway-prod like this:
kubectl kustomize /course/5/api-gateway/staging | kubectl apply -f -
kubectl kustomize /course/5/api-gateway/prod | kubectl apply -f -
Using the Kustomize config at /course/5/api-gateway do the following:
- Remove the ConfigMap
horizontal-scaling-configcompletely - Add HPA named
api-gatewayfor the Deploymentapi-gatewaywith min2and max4replicas. It should scale at50%average CPU utilisation - In prod the HPA should have max
6replicas - Apply your changes for staging and prod so they’re reflected in the cluster
ssh cka5774# cka5774:/course/5/api-gateway/base/api-gateway.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-gateway
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-gateway
minReplicas: 2
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
---
...# cka5774:/course/5/api-gateway/prod/api-gateway.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-gateway
spec:
maxReplicas: 6
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
labels:
env: prodk apply -k /course/5/api-gateway/staging
k apply -k /course/5/api-gateway/prod
k -n api-gateway-staging delete cm horizontal-scaling-config
k -n api-gateway-prod delete cm horizontal-scaling-configkiller.sh: CKA-B Q17. Operator, CRDs, RBAC, Kustomize
Using RBAC Authorization Kustomize
Solve this question on: ssh cka6016
There is Kustomize config available at /course/17/operator. It installs an operator which works with different CRDs. It has been deployed like this: kubectl kustomize /course/17/operator/prod | kubectl apply -f -
Perform the following changes in the Kustomize base config:
- The operator needs to
listcertain CRDs. Check the logs to find out which ones and adjust the permissions for Roleoperator-role - Add a new Student resource called
student4with any name and description Deploy your Kustomize config changes to prod.
ssh cka6016# cka6016:/course/17/operator/base/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operator-role
namespace: default
rules:
- apiGroups:
- education.killer.sh
resources:
- students
- classes
verbs:
- list
...
# cka6016:/course/17/operator/base/students.yaml
...
apiVersion: education.killer.sh/v1
kind: Student
metadata:
name: student4
spec:
name: Some Name
description: Some Descriptionk apply -k /course/17/operator/prod
k -n operator-prod logs operator-7f4f58d4d9-v6ftw
k -n operator-prod get studentWorkloads & Scheduling 15%
Static Pod
Mock Exam 2
Create a static pod on node01 called nginx-critical with the image nginx. Make sure that it is recreated/restarted automatically in case of a failure.
For example, use /etc/kubernetes/manifests as the static Pod path.
# ssh node01
# vi /etc/kubernetes/manifests/static.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-critical
spec:
containers:
- image: nginx
name: nginx-criticalkiller.sh: CKA-B Q2. Create a Static Pod and Service
Create static Pods Service
Solve this question on: ssh cka2560
Create a Static Pod named my-static-pod in Namespace default on the controlplane node. It should be of image nginx:1-alpine and have resource requests for 10m CPU and 20Mi memory.
Create a NodePort Service named static-pod-service which exposes that static Pod on port 80.
ℹ️ For verification check if the new Service has one Endpoint. It should also be possible to access the Pod via the internal IP address of
cka2560, for example usingcurl 192.168.100.31:NODE_PORT
ssh cka2560# k run my-static-pod --image=nginx:1-alpine -o yaml --dry-run=client > my-static-pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: my-static-pod
name: my-static-pod
spec:
containers:
- image: nginx:1-alpine
name: my-static-pod
resources:
requests:
cpu: 10m
memory: 20Mik expose pod my-static-pod-cka2560 --name static-pod-service --type NodePort --port 80
curl 192.168.100.31:32699ConfigMap, Secrets
Lighting Lab
Create a pod called secret-1401 in the admin1401 namespace using the busybox image. The container within the pod should be called secret-admin and should sleep for 4800 seconds.
The container should mount a read-only secret volume called secret-volume at the path /etc/secret-volume. The secret being mounted has already been created for you and is called dotfile-secret.
k config set-context --current -n admin1401
k run secret-1401 --image busybox --dry-run=client -o yaml > pod.yaml# vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-1401
spec:
containers:
- image: busybox
name: secret-admin
command:
- 'sh'
- '-c'
- 'sleep 4800'
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
volumes:
- name: secret-volume
secret:
secretName: dotfile-secretk apply -f pod.yamlMock Exam 3
Create a ConfigMap named app-config in the namespace cm-namespace with the following key-value pairs:
ENV=production
LOG_LEVEL=info
Then, modify the existing Deployment named cm-webapp in the same namespace to use the app-config ConfigMap by setting the environment variables ENV and LOG_LEVEL in the container from the ConfigMap.
k create cm app-config -n cm-namespace --from-literal=ENV=production --from-literal=LOG_LEVEL=info# k edit deployments.apps cm-webapp -n cm-namespace
...
spec:
...
template:
...
spec:
containers:
...
# ConfigMap 설정 추가
envFrom:
- configMapRef:
name: app-config
...k -n cm-namespace exec cm-webapp-748d87d5dd-7fc22 -- env
prepium.sh Q4. TLS ConfigMap
The secure-web Deployment in namespace secure-space uses a ConfigMap tls-config that currently supports both TLS 1.2 and TLS 1.3.
Task: Modify the configuration so that only TLS 1.3 is supported.
Note: ConfigMaps are immutable - you must delete and recreate it, then restart the Deployment.
k -n secure-space get cm tls-config -o yaml > tls-config.yaml
vi tls-config.yaml # TLSv1.2 제거
k -n secure-space delete cm tls-config
k apply -f tls-config.yaml
k -n secure-space rollout restart deployment secure-web # ConfigMap 적용
k -n secure-space get svc # ClusterIP 확인
echo '${cluster-ip} ${domain-name}' >> /etc/hosts # DNS 등록
curl -vk --tls-max 1.2 https://${domain-name} # 실패해야 정상killer.sh: CKA-B Q11. Create Secret and mount into Pod
Secrets Distribute Credentials Securely
Solve this question on: ssh cka2560
Create Namespace secret and implement the following in it:
- Create Pod
secret-podwith imagebusybox:1. It should be kept running by executingsleep 1dor something similar - Create the existing Secret
/course/11/secret1.yamland mount it read-only into the Pod at/tmp/secret1 - Create a new Secret called
secret2which should containuser=user1andpass=1234. These entries should be available inside the Pod’s container as environment variablesAPP_USERandAPP_PASS
ssh cka2560
k create ns secret# cka2560:/home/candidate/11_secret1.yaml
apiVersion: v1
data:
halt: IyEgL2Jpbi9zaAo...
kind: Secret
metadata:
creationTimestamp: null
name: secret1
namespace: secret # UPDATEk create -f 11_secret1.yaml
k -n secret create secret generic secret2 --from-literal=user=user1 --from-literal=pass=1234# k -n secret run secret-pod --image=busybox:1 --dry-run=client -o yaml -- sh -c "sleep 1d" > 11.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: secret-pod
name: secret-pod
namespace: secret # important if not automatically added
spec:
containers:
- args:
- sh
- -c
- sleep 1d
image: busybox:1
name: secret-pod
resources: {}
env: # add
- name: APP_USER # add
valueFrom: # add
secretKeyRef: # add
name: secret2 # add
key: user # add
- name: APP_PASS # add
valueFrom: # add
secretKeyRef: # add
name: secret2 # add
key: pass # add
volumeMounts: # add
- name: secret1 # add
mountPath: /tmp/secret1 # add
readOnly: true # add
dnsPolicy: ClusterFirst
restartPolicy: Always
volumes: # add
- name: secret1 # add
secret: # add
secretName: secret1 # addDeployment & DS & STS & Job & Probes
Lighting Lab
Create a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica.
Next, upgrade the deployment to version 1.17 using rolling update and add the annotation message
Updated nginx image to 1.17.
k create deployment nginx-deploy --image=nginx:1.16 --replicas=1
k set image deployment nginx-deploy nginx=nginx:1.17Mock Exam 1
Create a deployment named hr-web-app using the image kodekloud/webapp-color with 2 replicas.
k create deployment hr-web-app --image=kodekloud/webapp-color --replicas=2Mock Exam 2
Create a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica. Next, upgrade the deployment to version 1.17 using rolling update.
Note: Use the kubectl apply command to create or update the deployment.
k create deployment nginx-deploy --image=nginx:1.16 --replicas=1
k rollout history deployment nginx-deploy
k set image deployments nginx-deploy nginx=nginx:1.17
k rollout history deployment nginx-deploykiller.sh: CKA-A Q3. Scale down StatefulSet
StatefulSets Scale a StatefulSet
Solve this question on: ssh cka3962
There are two Pods named o3db-* in Namespace project-h800. The Project H800 management asked you to scale these down to one replica to save resources.
ssh cka3962
k -n project-h800 get pod --show-labels | grep o3db
k -n project-h800 scale sts o3db --replicas 1killer.sh: CKA-A Q11. DaemonSet on all Nodes
DaemonSet Taints and Tolerations
Solve this question on: ssh cka2556
Use Namespace project-tiger for the following. Create a DaemonSet named ds-important with image httpd:2-alpine and labels id=ds-important and uuid=18426a0b-5f59-4e10-923f-c0e078e82462. The Pods it creates should request 10 millicore cpu and 10 mebibyte memory. The Pods of that DaemonSet should run on all nodes, also controlplanes.
ssh cka2556
k -n project-tiger create deployment --image=httpd:2-alpine ds-important --dry-run=client -o yaml > 11.yaml# cka2556:/home/candidate/11.yaml
apiVersion: apps/v1
kind: DaemonSet # change from Deployment to DaemonSet
metadata:
creationTimestamp: null
labels: # add
id: ds-important # add
uuid: 18426a0b-5f59-4e10-923f-c0e078e82462 # add
name: ds-important
namespace: project-tiger # important
spec:
selector:
matchLabels:
id: ds-important # add
uuid: 18426a0b-5f59-4e10-923f-c0e078e82462 # add
template:
metadata:
labels:
id: ds-important # add
uuid: 18426a0b-5f59-4e10-923f-c0e078e82462 # add
spec:
containers:
- image: httpd:2-alpine
name: ds-important
resources:
requests: # add
cpu: 10m # add
memory: 10Mi # add
tolerations: # add
- effect: NoSchedule # add
key: node-role.kubernetes.io/control-plane # addk apply -f 11.yamlkiller.sh: CKA-A Q12. Deployment on all Nodes
Deployments Assigning Pods to Nodes
Solve this question on: ssh cka2556
Implement the following in Namespace project-tiger:
- Create a Deployment named
deploy-importantwith3replicas - The Deployment and its Pods should have label
id=very-important - First container named
container1with imagenginx:1-alpine - Second container named
container2with imageregistry.k8s.io/pause:3.10 - There should only ever be one Pod of that Deployment running on one worker node, use
topologyKey: kubernetes.io/hostnamefor this
ℹ️ Because there are two worker nodes and the Deployment has three replicas the result should be that the third Pod won’t be scheduled. In a way this scenario simulates the behaviour of a DaemonSet, but using a Deployment with a fixed number of replicas
ssh cka2556
k -n project-tiger create deployment --image=nginx:1-alpine deploy-important --dry-run=client -o yaml > 12.yaml# cka2556:/home/candidate/12.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
id: very-important # change
name: deploy-important
namespace: project-tiger # important
spec:
replicas: 3 # change
selector:
matchLabels:
id: very-important # change
template:
metadata:
creationTimestamp: null
labels:
id: very-important # change
spec:
containers:
- image: nginx:1-alpine
name: container1 # change
- image: registry.k8s.io/pause:3.10 # add
name: container2 # add
affinity: # add
podAntiAffinity: # add
requiredDuringSchedulingIgnoredDuringExecution: # add
- labelSelector: # add
matchExpressions: # add
- key: id # add
operator: In # add
values: # add
- very-important # add
topologyKey: kubernetes.io/hostname # addkiller.sh: CKA-B Q4. Pod Ready if Service is reachable
Configure Probes
Solve this question on: ssh cka3200
Do the following in Namespace default:
- Create a Pod named
ready-if-service-readyof imagenginx:1-alpine - Configure a LivenessProbe which simply executes command
true - Configure a ReadinessProbe which checks if the url
http://service-am-i-ready:80is reachable. You can usewget -T2 -O- http://service-am-i-ready:80for this - Start the Pod and confirm it isn’t ready because of the ReadinessProbe. Then:
- Create a second Pod named
am-i-readyof imagenginx:1-alpinewith labelid: cross-server-ready - The already existing Service
service-am-i-readyshould now have that second Pod as endpoint - Now the first Pod should be in ready state, check that
ssh cka3200
k run ready-if-service-ready --image=nginx:1-alpine --dry-run=client -o yaml > 4_pod1.yaml# cka3200:/home/candidate/4_pod1.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ready-if-service-ready
name: ready-if-service-ready
spec:
containers:
- image: nginx:1-alpine
name: ready-if-service-ready
resources: {}
livenessProbe: # add from here
exec:
command:
- 'true'
readinessProbe:
exec:
command:
- sh
- -c
- 'wget -T2 -O- http://service-am-i-ready:80' # to herek apply -f 4_pod1.yaml
k run am-i-ready --image nginx:1-alpine --labels id=cross-server-readySidecar Container
Mock Exam 1
Create a Pod mc-pod in the mc-namespace namespace with three containers. The first container should be named mc-pod-1, run the nginx:1-alpine image, and set an environment variable NODE_NAME to the node name. The second container should be named mc-pod-2, run the busybox:1 image, and continuously log the output of the date command to the file /var/log/shared/date.log every second. The third container should have the name mc-pod-3, run the image busybox:1, and print the contents of the date.log file generated by the second container to stdout. Use a shared, non-persistent volume.
# vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mc-pod
namespace: mc-namespace
spec:
containers:
- name: mc-pod-1
image: nginx:1-alpine
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: mc-pod-2
image: busybox:1
command:
- "sh"
- "-c"
- "while true; do date >> /var/log/shared/date.log; sleep 1; done"
volumeMounts:
- name: data
mountPath: /var/log/shared
- name: mc-pod-3
image: busybox:1
command:
- "sh"
- "-c"
- "tail -f /var/log/shared/date.log"
volumeMounts:
- name: data
mountPath: /var/log/shared
volumes:
- name: data
emptyDir: {}k apply -f pod.yaml
k -n mc-namespace logs mc-pod -c mc-pod-3 -fMock Exam 2
Create a deployment named logging-deployment in the namespace logging-ns with 1 replica, with the following specifications:
The main container should be named app-container, use the image busybox, and should run the following command to simulate writing logs:
sh -c "while true; do echo 'Log entry' >> /var/log/app/app.log; sleep 5; done"
Add a sidecar container named log-agent that also uses the busybox image and runs the command:
tail -f /var/log/app/app.log
log-agent logs should display the entries logged by the main app-container
# vi deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: logging-deployment
namespace: logging-ns
spec:
replicas: 1
selector:
matchLabels:
app: logging-deployment
template:
metadata:
labels:
app: logging-deployment
spec:
containers:
- image: busybox
name: app-container
command:
- "sh"
- "-c"
- "while true; do echo 'Log entry' >> /var/log/app/app.log; sleep 5; done"
volumeMounts:
- name: data
mountPath: /var/log/app
initContainers:
- name: log-agent
image: busybox
command:
- "sh"
- "-c"
- "touch /var/log/app/app.log; tail -f /var/log/app/app.log"
volumeMounts:
- name: data
mountPath: /var/log/app
volumes:
- name: data
emptyDir: {}k apply -f deploy.yaml
k -n logging-ns logs logging-deployment-78cdb9bdbf-f5wgf -c log-agent -fprepium.sh Q7. Sidecar
Update the existing wordpress Deployment in the wordpress-ns namespace, adding a sidecar container named sidecar using the busybox:stable image to the existing pod.
The new sidecar container has to run the following command:
/bin/sh -c tail -f /var/log/wordpress.logUse a volume mounted at /var/log to make the log file wordpress.log available to the co-located container.
# k edit deployment -n wordpress-ns wordpress
...
volumeMounts:
- name: logs
mountPath: /var/log
- name: sidecar
image: busybox:stable
command:
- "/bin/sh"
- "-c"
- "tail -f /var/log/wordpress.log"
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
emptyDir: {}
...killer.sh: CKA-B Q13. Multi Containers and Pod shared Volume
Shared Volume Between Containers Pod Info via Env
Solve this question on: ssh cka3200
Create a Pod with multiple containers named multi-container-playground in Namespace default:
- It should have a volume attached and mounted into each container. The volume shouldn’t be persisted or shared with other Pods
- Container
c1with imagenginx:1-alpineshould have the name of the node where its Pod is running, available as environment variableMY_NODE_NAME - Container
c2with imagebusybox:1should write the output of thedatecommand every second in the shared volume into filedate.log. You can usewhile true; do date >> /your/vol/path/date.log; sleep 1; donefor this. - Container
c3with imagebusybox:1should constantly write the content of filedate.logfrom the shared volume to stdout. You can usetail -f /your/vol/path/date.logfor this.
ℹ️ Check the logs of container
c3to confirm correct setup
ssh cka3200# k run multi-container-playground --image=nginx:1-alpine --dry-run=client -o yaml > 13.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: multi-container-playground
name: multi-container-playground
spec:
containers:
- image: nginx:1-alpine
name: c1 # change
env: # add
- name: MY_NODE_NAME # add
valueFrom: # add
fieldRef: # add
fieldPath: spec.nodeName # add
volumeMounts: # add
- name: vol # add
mountPath: /vol # add
- image: busybox:1 # add
name: c2 # add
command: ["sh", "-c", "while true; do date >> /vol/date.log; sleep 1; done"] # add
volumeMounts: # add
- name: vol # add
mountPath: /vol # add
- image: busybox:1 # add
name: c3 # add
command: ["sh", "-c", "tail -f /vol/date.log"] # add
volumeMounts: # add
- name: vol # add
mountPath: /vol # add
volumes: # add
- name: vol # add
emptyDir: {} # addk apply -f 13.yaml
k exec multi-container-playground -c c1 -- env
k logs multi-container-playground -c c3Taint & Toleration, Node Affinity, Node Selector
Mock Exam 3
Taint the worker node node01 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
k taint node node01 env_type=production:NoSchedule
k run dev-redis --image=redis:alpine# vi prod-redis.yaml
apiVersion: v1
kind: Pod
metadata:
name: prod-redis
spec:
containers:
- image: redis:alpine
name: prod-redis
tolerations:
- key: "env_type"
operator: "Equal"
value: "production"
effect: "NoSchedule"prepium.sh Q8. Taints & Tolerations
A worker node has been tainted with dedicated=gpu:NoSchedule and labeled gpu=true.
A Deployment called web-app already exists in namespace cka-taints.
It should not run on the tainted node.
Task: Create a pod named gpu-pod in namespace cka-taints that:
- Uses image
nginx:1.25 - Has a toleration for the taint
dedicated=gpu:NoSchedule - Has a nodeSelector that targets nodes with label
gpu=true - Is in a Running state
# vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
namespace: cka-taints
labels:
run: gpu-pod
spec:
nodeSelector:
gpu: "true"
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- image: nginx:1.25
name: gpu-podk apply -f pod.yamlkiller.sh: CKA-B Q9. Kill Scheduler, Manual Scheduling
Assigning Pods to Nodes Kubernetes Scheduler
Solve this question on: ssh cka5248
Temporarily stop the kube-scheduler in a way that lets you start it again afterwards.
Create a single Pod named manual-schedule of image httpd:2-alpine, confirm it’s created but not scheduled on any node.
Now you’re the scheduler and have all its power, manually schedule that Pod on node cka5248. Make sure it’s running.
Start the kube-scheduler again and confirm it’s running correctly by creating a second Pod named manual-schedule2 of image httpd:2-alpine and check if it’s running on cka5248-node1.
ssh cka5248
cd /etc/kubernetes/manifests/
mv kube-scheduler.yaml ..
k run manual-schedule --image=httpd:2-alpine# k edit manual-schedule
apiVersion: v1
kind: Pod
metadata:
name: manual-schedule
spec:
nodeName: cka5248 # ADD the controlplane node name
containers:
- image: httpd:2-alpine
name: manual-schedulecd /etc/kubernetes/manifests/
mv ../kube-scheduler.yaml .
k run manual-schedule2 --image=httpd:2-alpine
k get pod -o wide | grep schedulekiller.sh: CKA-B Q12. Schedule Pod on Controlplane Nodes
Assigning Pods to Nodes Taints and Tolerations
Solve this question on: ssh cka5248
Create a Pod of image httpd:2-alpine in Namespace default.
The Pod should be named pod1 and the container should be named pod1-container.
This Pod should only be scheduled on controlplane nodes.
Do not add new labels to any nodes.
ssh cka5248# k run pod1 --image=httpd:2-alpine --dry-run=client -o yaml > 12.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
name: pod1
spec:
containers:
- image: httpd:2-alpine
name: pod1-container # change
tolerations: # add
- effect: NoSchedule # add
key: node-role.kubernetes.io/control-plane # add
nodeSelector: # add
node-role.kubernetes.io/control-plane: "" # addk get pod pod1 -o wideResource Requests and Limits
prepium.sh Q6. Resource Requests and Limits
The web-app Deployment in namespace resources-ns has 3 replicas but none of the pods are running.
A ResourceQuota has been applied to the namespace that limits total CPU and memory. The Deployment does not have resource requests or limits configured, so the pods are being blocked by the quota.
Task:
- Investigate why the pods are not being created
- Inspect the ResourceQuota to find the total CPU and memory budget
- Edit the Deployment so that each pod gets an equal share of the quota (requests must equal limits)
- Confirm all 3 pods are Running
k -n resources-ns describe quota# k -n resources-ns edit deployment web-app
...
template:
...
spec:
containers:
...
resources:
requests:
cpu: "10m"
memory: "10Mi"
limits:
cpu: "10m"
memory: "10Mi"
...killer.sh: CKA-A Q4. Find Pods first to be terminated
Pod Quality of Service Classes Node-pressure Eviction
Solve this question on: ssh cka2556
Check all available Pods in the Namespace project-c13 and find the names of those that would probably be terminated first if the nodes run out of resources (cpu or memory).
Write the Pod names into /course/4/pods-terminated-first.txt.
ssh cka2556
k -n project-c13 get pod -o jsonpath="{range .items[*]} {.metadata.name}{.spec.containers[*].resources}{'\n'}"
k get pods -n project-c13 -o jsonpath="{range .items[*]}{.metadata.name} {.status.qosClass}{'\n'}"
# /course/4/pods-terminated-first.txt
c13-3cc-runner-heavy-8687d66dbb-gnxjh
c13-3cc-runner-heavy-8687d66dbb-przdh
c13-3cc-runner-heavy-8687d66dbb-wqwfzPriorityClass
Mock Exam 3
Create a PriorityClass named low-priority with a value of 50000. A pod named lp-pod exists in the namespace low-priority. Modify the pod to use the priority class you created. Recreate the pod if necessary.
k create priorityclass low-priority --value=50000# k -n low-priority edit pod lp-pod
...
spec:
...
priorityClassName: low-priority
...prepium.sh Q10. Priority Class
A Deployment named busybox-logger exists in the priority namespace.
An existing user-defined PriorityClass user-existing has value 10000.
Task:
- Create a new PriorityClass named
high-prioritywith a value one less than the highest existing user-defined value (i.e.9999) - Patch the
busybox-loggerDeployment to usehigh-priority
k create priorityclass high-priority --value=9999# k -n priority edit deployment busybox-logger
...
template:
...
spec:
...
priorityClassName: high-priority
...HPA, VPA
Mock Exam 1
Create a Horizontal Pod Autoscaler (HPA) with name webapp-hpa for the deployment named kkapp-deploy in the default namespace with the webapp-hpa.yaml file located under the root folder.
Ensure that the HPA scales the deployment based on CPU utilization, maintaining an average CPU usage of 50% across all pods.
Configure the HPA to cautiously scale down pods by setting a stabilization window of 300 seconds to prevent rapid fluctuations in pod count.
Note: The kkapp-deploy deployment is created for backend; you can check in the terminal.
# vi webapp-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: kkapp-deploy
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
scaleDown:
stabilizationWindowSeconds: 300Mock Exam 1
Deploy a Vertical Pod Autoscaler (VPA) with name analytics-vpa for the deployment named analytics-deployment in the default namespace.
The VPA should automatically adjust the CPU and memory requests of the pods to optimize resource utilization. Ensure that the VPA operates in Recreate mode, allowing it to evict and recreate pods with updated resource requests as needed.
# vi vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: analytics-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: analytics-deployment
updatePolicy:
updateMode: "Recreate"Mock Exam 2
Create a Horizontal Pod Autoscaler with name backend-hpa for the deployment named backend-deployment in the backend namespace with the webapp-hpa.yaml file located under the root folder.
Ensure that the HPA scales the deployment based on memory utilization, maintaining an average memory usage of 65% across all pods.
Configure the HPA with a minimum of 3 replicas and a maximum of 15.
# vi webapp-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
namespace: backend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: backend-deployment
minReplicas: 3
maxReplicas: 15
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 65Mock Exam 3
Create a Horizontal Pod Autoscaler (HPA) api-hpa for the deployment named api-deployment located in the api namespace.
The HPA should scale the deployment based on a custom metric named requests_per_second, targeting an average value of 1000 requests per second across all pods.
Set the minimum number of replicas to 1 and the maximum to 20.
Note: Deployment named api-deployment is available in api namespace. Ignore errors due to the metric requests_per_second not being tracked in metrics-server
# vi api-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
namespace: api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-deployment
minReplicas: 1
maxReplicas: 20
metrics:
- type: Pods
pods:
metric:
name: requests_per_second
target:
type: AverageValue
averageValue: 1kJayDemy Q3. HPA
Create a new HorizontalPodAutoscaler (HPA) named apache-server in the autoscale namespace. This HPA must target the existing Deployment called apache-server in the autoscale namespace.
- Set the HPA to target for 50% CPU usage per Pod.
- Configure HPA to have at min 1 Pod and no more than 4 Pods.
- Also, we have to set the downscale stabilization window to 30 seconds.
k autoscale deployment apache-server --cpu-percent=50 --min=1 --max=4 -n autoscale --dry-run=client -o yaml > hpa.yaml# vi hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: apache-server
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: apache-server
minReplicas: 1
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
behavior:
scaleDown:
downscaleStabilizationWindow: 30k apply -f hpa.yamlServices & Networking 20%
CoreDNS
killer.sh: CKA-A Q16. Update CoreDNS Configuration
Customizing DNS Service DNS for Services and Pods
Solve this question on: ssh cka5774
The CoreDNS configuration in the cluster needs to be updated:
- Make a backup of the existing configuration YAML and store it at
/course/16/coredns_backup.yaml. You should be able to fast recover from the backup - Update the CoreDNS configuration in the cluster so that
SERVICE.NAMESPACE.custom-domainresolves the same asSERVICE.NAMESPACE.cluster.local(in addition to it) Test your configuration for example from a Pod withbusybox:1image. These commands should result in an IP address:
nslookup kubernetes.default.svc.cluster.local
nslookup kubernetes.default.svc.custom-domain
ssh cka5774
k -n kube-system get cm coredns -o yaml > /course/16/coredns_backup.yaml
k -n kube-system edit cm coredns# k -n kube-system edit cm coredns
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes custom-domain cluster.local in-addr.arpa ip6.arpa { # ADD
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30 {
disable success cluster.local
disable denial cluster.local
}
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
creationTimestamp: "2024-12-26T20:35:11Z"
name: coredns
namespace: kube-system
resourceVersion: "262"
uid: c76d208f-1bc8-4c0f-a8e8-a8bfa440870ek -n kube-system rollout restart deploy coredns
k run test --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default.svc.custom-domain
k run test --image=busybox --rm -it --restart=Never -- nslookup kubernetes.default.svc.cluster.localkiller.sh: CKA-B Q1. DNS / FQDN / Headless Service
DNS for Services and Pods Service
Solve this question on: ssh cka6016
The Deployment controller in Namespace lima-control communicates with various cluster-internal endpoints by using their DNS FQDN values.
Update the ConfigMap used by the Deployment with the correct FQDN values for:
DNS_1: Servicekubernetesin NamespacedefaultDNS_2: Headless Servicedepartmentin Namespacelima-workloadDNS_3: Podsection100in Namespacelima-workload. It should work even if the Pod IP changesDNS_4: A Pod with IP1.2.3.4in Namespacekube-systemEnsure the Deployment works with the updated values.
ℹ️ You can use
nslookupordiginside a Pod of thecontrollerDeployment
ssh cka6016# kubectl -n lima-control edit cm control-config
apiVersion: v1
data:
DNS_1: kubernetes.default.svc.cluster.local # UPDATE
DNS_2: department.lima-workload.svc.cluster.local # UPDATE
DNS_3: section100.section.lima-workload.svc.cluster.local # UPDATE
DNS_4: 1-2-3-4.kube-system.pod.cluster.local # UPDATE
kind: ConfigMap
metadata:
name: control-config
namespace: lima-control
...Service
Mock Exam 1
Create a service named messaging-service to expose the messaging pod within the cluster on port 6379. The messaging pod is running in the default namespace.
Use imperative commands.
k expose pod messaging --name=messaging-service --port=6379Mock Exam 1
Expose the hr-web-app created in the previous task as a service named hr-web-app-service, accessible on port 30082 on the nodes of the cluster.
The web application listens on port 8080.
# k expose deployment hr-web-app --name=hr-web-app-service --port=8080 --type=NodePort --dry-run=client -o yaml > svc.yaml
# vi svc.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: hr-web-app
name: hr-web-app-service
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
nodePort: 30082
selector:
app: hr-web-app
type: NodePortMock Exam 2
Create an nginx pod named nginx-resolver using the nginx image and expose it internally using a ClusterIP service called nginx-resolver-service.
From within the cluster, verify:
- DNS resolution of the service name
- Network reachability of the pod using its IP address
Use the busybox:1.28 image to perform the lookups.
Save the service DNS lookup output to
/root/CKA/nginx.svcand the pod IP lookup output to/root/CKA/nginx.pod.
k run nginx-resolver --image=nginx
k expose pod nginx-resolver --name=nginx-resolver-svc --port=80
k run test --image=busybox:1.28 --rm -it --restart=Never -- nslookup nginx-resolver-service > /root/CKA/nginx.svc
k run test --image=busybox:1.28 --rm -it --restart=Never -- nslookup 172-17-1-15.default.pod > /root/CKA/nginx.podJayDemy Q9. NodePort Service
Reconfigure the existing Deployment front-end in namespace sp-culator to expose port 80/tcp of the existing container nginx.
Create a new Service named front-end-svc exposing the container port 80/tcp. Configure the new Service to also expose the individual pods via & NodePort
k expose deployment front-end --type=NodePort --port=80 --protocol=TCP --name=front-end-svcDumbITGuy Q16. NodePort Service
There is a Deployment named nodeport-deployment in the relative namespace.
Tasks:
- Configure the Deployment so it can be exposed on port 80, name=http, protocol TCP
- Create a new Service named
nodeport-serviceexposing the container port 80, protocol TCP, NodePort 30080 - Configure the new Service to also expose the individual pods using NodePort
# k -n relative edit deploy nodeport-deployment
...
template:
...
spec:
containers:
- image: nginx
...
ports:
- name: http
containerPort: 80
protocol: TCP
...# vi nodeport-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nodeport-service
namespace: relative
spec:
type: NodePort
selector:
app: nodeport-deployment
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30080Ingress
Mock Exam 2
A Deployment named webapp-deploy is running in the ingress-ns namespace and is exposed via a Service named webapp-svc.
Create an Ingress resource called webapp-ingress in the same namespace that will route traffic to the service. The Ingress must:
- Use
pathType: Prefix - Route requests sent to path
/to the backend service - Forward traffic to port
80of the service - Be configured for the host
kodekloud-ingress.appTest app availablility using the following command:
curl -s http://kodekloud-ingress.app/
k create ingress webapp-ingress -n ingress-ns --class=nginx --rule=kodekloud-ingress.app/*=webapp-svc:80
curl -s http://kodekloud-ingress.app/JayDemy Q4. Ingress
Create a new Ingress resource echo in echo-sound namespace exposing Service echoserver-service on http://example.org/echo using Service port 8080.
k -n echo-sound create ingress echo --class=nginx --rule=example.org/*=echoserver-service:8080Gateway API
Mock Exam 1
Create a Kubernetes Gateway resource with the following specifications:
- Name:
web-gateway - Namespace:
nginx-gateway - Gateway Class Name:
nginx - Listeners:
- Protocol:
HTTP - Port:
80 - Name:
http
- Protocol:
# vi gw.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: web-gateway
namespace: nginx-gateway
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80Mock Exam 2
Modify the existing web-gateway on cka5673 namespace to handle HTTPS traffic on port 443 for kodekloud.com, using a TLS certificate stored in a secret named kodekloud-tls.
# k -n cka5673 edit gateway web-gateway
...
spec:
...
listeners:
- name: https
port: 443
protocol: HTTPS
hostname: kodekloud.com
tls:
certificateRefs:
- name: kodekloud-tls
...Mock Exam 3
Configure the web-route to split traffic between web-service and web-service-v2.The configuration should ensure that 80% of the traffic is routed to web-service and 20% is routed to web-service-v2.
Note: web-gateway, web-service, and web-service-v2 have already been created and are available on the cluster.
# vi web-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-route
spec:
parentRefs:
- name: web-gateway
rules:
- backendRefs:
- name: web-service
port: 80
weight: 80
- name: web-service-v2
port: 80
weight: 20prepium.sh Q5. Gateway API
Migrate the existing Ingress web in namespace web-app to the new Gateway API.
A GatewayClass named nginx is already installed. Use API version v1beta1 on this environment.
Task 1: Create a Gateway named web-gateway with:
- hostname:
gateway.web.k8s.local - TLS termination using secret
web-tls - GatewayClass:
nginxTask2: Create anHTTPRoutenameweb-routewith: - hostname:
gateway.web.k8s.local - path prefix
/-> serviceweb-service:80 - parentRef: the
web-gateway
# vi web-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: web-gateway
namespace: web-app
spec:
gatewayClassName: nginx
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "gateway.web.k8s.local"
tls:
mode: Terminate
certificateRefs:
- name: web-tls# vi httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-route
namespace: web-app
spec:
parentRefs:
- name: web-gateway
hostnames:
- "gateway.web.k8s.local"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: web-service
port: 80killer.sh: CKA-A Q13. Gateway API Ingress
Gateway API Gateway API Documentation
Solve this question on: ssh cka7968
The team from Project r500 wants to replace their Ingress (networking.k8s.io) with a Gateway API (gateway.networking.k8s.io) solution. The old Ingress is available at /course/13/ingress.yaml.
Perform the following in Namespace project-r500 and for the already existing Gateway:
- Create a new HTTPRoute named
traffic-directorwhich replicates the routes from the old Ingress - Extend the new HTTPRoute with path
/autowhich forwards to mobile backend if the User-Agent is exactlymobileand to desktop backend otherwise The existing Gateway is reachable athttp://r500.gateway:30080which means your implementation should work for these commands:
curl r500.gateway:30080/desktop
curl r500.gateway:30080/mobile
curl r500.gateway:30080/auto -H "User-Agent: mobile"
curl r500.gateway:30080/autossh cka7968# cka7968:/home/candidate/13.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: traffic-director
namespace: project-r500
spec:
parentRefs:
- name: main
hostnames:
- "r500.gateway"
rules:
- matches:
- path:
type: PathPrefix
value: /desktop
backendRefs:
- name: web-desktop
port: 80
- matches:
- path:
type: PathPrefix
value: /mobile
backendRefs:
- name: web-mobile
port: 80
# NEW FROM HERE ON
- matches:
- path:
type: PathPrefix
value: /auto
headers:
- type: Exact
name: user-agent
value: mobile
backendRefs:
- name: web-mobile
port: 80
- matches:
- path:
type: PathPrefix
value: /auto
backendRefs:
- name: web-desktop
port: 80k apply -f 13.yaml
curl r500.gateway:30080/desktop
curl r500.gateway:30080/mobile
curl r500.gateway:30080/auto -H "User-Agent: mobile"
curl r500.gateway:30080/auto
Web Desktop App
Web Mobile App
Web Mobile App
Web Desktop AppNetworkPolicy
Mock Exam 2
You are requested to create a NetworkPolicy to allow traffic from frontend apps located in the frontend namespace, to backend apps located in the backend namespace, but not from the databases in the databases namespace. There are three policies available in the /root folder. Apply the most restrictive policy from the provided YAML files to achieve the desired result. Do not delete any existing policies.
# cat net-pol-3.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: net-policy-3
namespace: backend
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
ports:
- protocol: TCP
port: 80k apply -f net-pol-3.yamlMock Exam 3
A pod called np-test-1 and a service called np-test-service have been deployed in the default namespace. A default-deny NetworkPolicy is currently blocking all ingress traffic to pods in this namespace, which is why the service is unreachable.
Create a new NetworkPolicy named ingress-to-nptest in the default namespace that allows ingress traffic from all sources to the np-test-1 pod on port 80.
Important: Don’t delete any current objects deployed.
# vi np.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ingress-to-nptest
namespace: default
spec:
podSelector:
matchLabels:
run: np-test-1
policyTypes:
- Ingress
ingress:
- ports:
- protocol: TCP
port: 80prepium.sh Q3. Network Policy
There are two deployments, Frontend and Backend. Frontend is in the frontend namespace. Backend is in the backend namespace.
Task
Look at the Network Policy YAML file in /root/exam_resources.
Decide which of the policies provides the functionality to allow interaction between the frontend and the backend deployments in the least permissive way and deploy that YAML.
# netpol2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: netpol2
namespace: backend-ns
spec:
podSelector:
matchLabels:
role: backend
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend-ns
podSelector:
matchLabels:
role: frontendk apply -f netpol2.yamlkiller.sh: CKA-A Q15. NetworkPolicy
Network Policies Declare Network Policy
Solve this question on: ssh cka7968
There was a security incident where an intruder was able to access the whole cluster from a single hacked backend Pod.
To prevent this create a NetworkPolicy called np-backend in Namespace project-snake. It should allow the backend-* Pods only to:
- Connect to
db1-*Pods on port1111 - Connect to
db2-*Pods on port2222Use theappPod labels in your policy.
ℹ️ All Pods in the Namespace run plain Nginx images. This allows simple connectivity tests like:
k -n project-snake exec POD_NAME -- curl POD_IP:PORTℹ️ For example, connections frombackend-*Pods tovault-*Pods on port3333should no longer work
ssh cka7968
k -n project-snake get pod -L app
k -n project-snake get pod -o wide# cka7968:/home/candidate/15_np.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: np-backend
namespace: project-snake
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress # policy is only about Egress
egress:
- to: # first condition "to"
- podSelector:
matchLabels:
app: db1
ports: # second condition "port"
- protocol: TCP
port: 1111
- to: # first condition "to"
- podSelector:
matchLabels:
app: db2
ports: # second condition "port"
- protocol: TCP
port: 2222k apply -f 15_np.yaml
k -n project-snake exec backend-0 -- curl -s 10.44.0.25:1111
k -n project-snake exec backend-0 -- curl -s 10.44.0.23:2222
k -n project-snake exec backend-0 -- curl -s 10.44.0.22:3333
^CStorage 10%
PersistentVolume, PersistentVolumeClaim, StorageClass
Lighting Lab
A new deployment called alpha-mysql has been deployed in the alpha namespace. However, the pods are not running. Troubleshoot and fix the issue. The deployment should make use of the persistent volume alpha-pv to be mounted at /var/lib/mysql and should use the environment variable MYSQL_ALLOW_EMPTY_PASSWORD=1 to make use of an empty root password.
Important: Do not alter the persistent volume.
k config set-context --current -n alpha
k get pvc alpha-claim -o yaml > pvc.yaml# vi pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-alpha-pvc
namespace: alpha
spec:
accessModes:
- ReadWriteOnce # 수정 ReadWriteMany -> ReadWriteOnce
resources:
requests:
storage: 1Gi # 수정 2Gi -> 1Gi
storageClassName: slow # 수정 slow-storage -> slowk delete pvc alpha-claim
k apply -f pvc.yaml
k edit deployments.apps alpha-mysql # persistentVolumeClaim.claimName 수정Mock Exam 1
Create a Persistent Volume with the given specification:
- Volume name:
pv-analytics - Storage:
100Mi - Access mode:
ReadWriteMany - Host path:
/pv/data-analytics
# vi pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-analytics
spec:
capacity:
storage: 100Mi
accessModes:
- ReadWriteMany
hostPath:
path: "/pv/data-analytics"Mock Exam 2
Create a StorageClass named local-sc with the following specifications and set it as the default storage class:
- The provisioner should be
kubernetes.io/no-provisioner - The volume binding mode should be
WaitForFirstConsumer - Volume expansion should be enabled
# vi sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumerMock Exam 3
Create a StorageClass named rancher-sc with the following specifications:
The provisioner should be rancher.io/local-path.
The volume binding mode should be WaitForFirstConsumer.
Volume expansion should be enabled.
# vi sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rancher-sc
provisioner: rancher.io/local-path
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumerprepium.sh Q9. StorageClass
Create a new StorageClass named local-storage with the provisioner rancher.io/local-path. Set volumeBindingMode to WaitForFirstConsumer. Do not make it the default SC.
Patch the StorageClass to make it the default StorageClass.
Ensure local-storage is the only default class.
Do not modify any existing Deployment or PersistentVolumeClaims.
# vi local-storage.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumerk apply -f local-storage.yaml
k patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
k patch storageclass local-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'JayDemy Q14. Pod PVC
A user accidentally deleted the MariaDB Deployment in the mariadb namespace, which was configured with persistent storage.
Your responsibility is to re-establish the Deployment while ensuring data is preserved by reusing the available PersistentVolume.
Taks:
A PersistentVolume already exists and is retained for reuse. only one PV exist.
Create a PVC named mariadb in the mariadb namespace with the spec:
- Access mode ReadWriteOnce and Storage 250Mi
- Edit the MariaDB Deployment file located at
~/mariadb-deploy.yamlto use PVC created in the previous step. - Apply the updated Deployment file to the cluster.
- Ensure the MariaDB Deployment is Running and Stable.
# vi pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb
namespace: mariadb
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 250Mi
volumeName: mariadb-pv# vi ~/mariadb-deploy.yaml
...
template:
spec:
volumes:
- name: mariadb-storage
persistentVolumeClaim:
claimName: mariadb
...killer.sh: CKA-A Q6. Storage, PV, PVC, Pod volume
Persistent Volumes Configure a Pod to use storage
Solve this question on: ssh cka7968
Create a new PersistentVolume named safari-pv. It should have a capacity of 2Gi, accessMode ReadWriteOnce, hostPath /Volumes/Data and no storageClassName defined.
Next create a new PersistentVolumeClaim in Namespace project-t230 named safari-pvc. It should request 2Gi storage, accessMode ReadWriteOnce and should not define a storageClassName. The PVC should be bound to the PV correctly.
Finally create a new Deployment safari in Namespace project-t230 which mounts that volume at /tmp/safari-data. The Pods of that Deployment should be of image httpd:2-alpine.
ssh cka7968# cka7968:/home/candidate/6_pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: safari-pv
spec:
capacity:
storage: 2Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/Volumes/Data"# cka7968:/home/candidate/6_pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: safari-pvc
namespace: project-t230
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gik -n project-t230 create deploy safari --image=httpd:2-alpine --dry-run=client -o yaml > 6_dep.yaml# cka7968:/home/candidate/6_dep.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: safari
name: safari
namespace: project-t230
spec:
replicas: 1
selector:
matchLabels:
app: safari
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: safari
spec:
volumes: # add
- name: data # add
persistentVolumeClaim: # add
claimName: safari-pvc # add
containers:
- image: httpd:2-alpine
name: container
volumeMounts: # add
- name: data # add
mountPath: /tmp/safari-data # addkiller.sh: CKA-B Q10. PV PVC Dynamic Provisioning
Storage Classes Dynamic Volume Provisioning
Solve this question on: ssh cka6016
There is a backup Job which needs to be adjusted to use a PVC to store backups.
Create a StorageClass named local-backup which uses provisioner: rancher.io/local-path and volumeBindingMode: WaitForFirstConsumer. To prevent possible data loss the StorageClass should keep a PV retained even if a bound PVC is deleted.
Adjust the Job at /course/10/backup.yaml to use a PVC which requests 50Mi storage and uses the new StorageClass.
The PV should be created automatically by the provisioner and not manually.
Deploy your changes, verify the Job completed once and the PVC was bound to a newly created PV.
ℹ️ To re-run a Job, delete it and create it again ℹ️ The abbreviation PV stands for PersistentVolume and PVC for PersistentVolumeClaim
ssh cka6016# cka6016:/home/candidate/sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-backup
provisioner: rancher.io/local-path
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumerk apply -f sc.yaml# cka6016:/course/10/backup.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: backup-pvc
namespace: project-bern # use same Namespace
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Mi # request the required size
storageClassName: local-backup # use the new StorageClass
---
apiVersion: batch/v1
kind: Job
metadata:
name: backup
namespace: project-bern
spec:
backoffLimit: 0
template:
spec:
volumes:
- name: backup
persistentVolumeClaim: # CHANGE
claimName: backup-pvc # CHANGE
containers:
- name: bash
image: bash:5
command:
- bash
- -c
- |
set -x
touch /backup/backup-$(date +%Y-%m-%d-%H-%M-%S).tar.gz
sleep 15
volumeMounts:
- name: backup
mountPath: /backup
restartPolicy: Neverk apply -f backup.yamlTroubleshooting 30%
kubectl
Lighting Lab
Print the names of all deployments in the admin2406 namespace in the following format:
DEPLOYMENT CONTAINER_IMAGE READY_REPLICAS NAMESPACE
<deployment name> <container image used> <ready replica count> <Namespace>.
The data should be sorted by the increasing order of the deployment name.
Example:
DEPLOYMENT CONTAINER_IMAGE READY_REPLICAS NAMESPACE
deploy0 nginx:alpine 1 admin2406
Write the result to the file /opt/admin2406_data.
k -n admin2406 get deployments -o custom-columns='DEPLOYMENT:.metadata.name,CONTAINER_IMAGE:.spec.template.spec.containers[*].image,READY_REPLICAS:.status.readyReplicas,NAMESPACE:.metadata.namespace' > /opt/admin2406_datakiller.sh: CKA-A Q7. Node and Pod Resource Usage
Tools for Monitoring Resources kubectl Quick Reference
Solve this question on: ssh cka5774
The metrics-server has been installed in the cluster. Write two bash scripts which use kubectl:
- Script
/course/7/node.shshould show resource usage of nodes - Script
/course/7/pod.shshould show resource usage of Pods and their containers
ssh cka5774
echo "kubectl top node" > /course/7/node.sh
echo "kubectl top pod --containers=true" > /course/7/pod.shkiller.sh: CKA-B Q5. Kubectl sorting
kubectl Quick Reference
Solve this question on: ssh cka8448
Create two bash script files which use kubectl sorting to:
- Write a command into
/course/5/find_pods.shwhich lists all Pods in all Namespaces sorted by their AGE (metadata.creationTimestamp) - Write a command into
/course/5/find_pods_uid.shwhich lists all Pods in all Namespaces sorted by fieldmetadata.uid
ssh cka8448
echo "kubectl get pod -A --sort-by=.metadata.creationTimestamp" > /course/5/find_pods.sh
echo "kubectl get pod -A --sort-by=.metadata.uid" > /course/5/find_pods_uid.shkiller.sh: CKA-B Q15. Cluster Event Logging
Debug with crictl kubectl Quick Reference
Solve this question on: ssh cka6016
- Write a
kubectlcommand into/course/15/cluster_events.shwhich shows the latest events in the whole cluster, ordered by time (metadata.creationTimestamp) - Delete the kube-proxy Pod and write the events this caused into
/course/15/pod_kill.logoncka6016 - Manually kill the containerd container of the kube-proxy Pod and write the events into
/course/15/container_kill.log
ssh cka6016
echo "kubectl get events -A --sort-by=.metadata.creationTimestamp" > /course/15/cluster_events.sh
k -n kube-system delete pod kube-proxy-lf2fs
kubectl get events -A --sort-by=.metadata.creationTimestamp > /course/15/pod_kill.log
crictl ps | grep kube-proxy
crictl rm --force 2fd052f1fcf78
kubectl get events -A --sort-by=.metadata.creationTimestamp > /course/15/container_kill.logkiller.sh: CKA-B Q16. Namespaces and API Resources
kubectl Quick Reference Namespaces
Solve this question on: ssh cka3200
Write the names of all namespaced Kubernetes resources (like Pod, Secret, ConfigMap…) into /course/16/resources.txt.
Find the project-* Namespace with the highest number of Roles defined in it and write its name and amount of Roles into /course/16/crowded-namespace.txt.
ssh cka3200
k api-resources --namespaced -o name > /course/16/resources.txt
k -n project-miami get role --no-headers | wc -l
echo "project-miami 300" > /course/16/crowded-namespace.txtkubelet & crictl & journalctl & Control Plane
Mock Exam 3
vi /etc/kubernetes/manifests/kube-controller-manager.yaml # 문제가 있는 부분 수정JayDemy Q16. Troubleshooting, crictl, journalctl
A kubeadm provisioned cluster was migrated to a new machine. Requires configuration changes to run successfully. Task: We need to fix a single-node cluster that got broken during machine migration. Identify the broken cluster components and investigate what caused to break those components. The decommissioned cluster used an external etcd server. Next, fix the configuration of all broken cluster components. Ensure to restart all necessary services and components for changes to take effect. Finally, ensure the cluster, single node and all pods are Ready.
k get po # kube-apiserver 가 응답하지 않음
crictl ps -a | grep apiserver # kubectl 대신 crictl 사용
crictl logs ${apiserver=container-id} # apiserver 로그 확인
journalctl -u kubelet -f # kubelet 로그에서 문제가 있는 컴포넌트 확인
vi /etc/kubernetes/manifests/kube-apiserver.yaml # 문제가 있는 부분 수정. 보통 etcd 주소가 잘못된 경우. 127.0.0.1:2379killer.sh: CKA-A Q17. Find Container of Pod and check info
Debug with crictl
Solve this question on: ssh cka2556
In Namespace project-tiger create a Pod named tigers-reunite of image httpd:2-alpine with labels pod=container and container=pod. Find out on which node the Pod is scheduled. Ssh into that node and find the containerd container belonging to that Pod.
Using command crictl:
- Write the ID of the container and the
info.runtimeTypeinto/course/17/pod-container.txtoncka2556 - Write the logs of the container into
/course/17/pod-container.logoncka2556
ℹ️ You can connect to a worker node using
ssh cka2556-node1orssh cka2556-node2fromcka2556
ssh cka2556
k -n project-tiger run tigers-reunite --image=httpd:2-alpine --labels "pod=container,container=pod"
ssh cka2556-node1
sudo -i
crictl ps | grep tigers-reunite
crictl inspect ba62e5d465ff0 | grep runtimeType
crictl logs ba62e5d465ff0
exit
echo "ba62e5d465ff0 io.containerd.runc.v2" > /course/17/pod-container.txt
echo "ssh cka2556-node1 crictl logs ba62e5d465ff0" > /course/17/pod-container.logkiller.sh: CKA-B Q6. Fix Kubelet
Troubleshooting kubeadm
Solve this question on: ssh cka1024
There seems to be an issue with the kubelet on controlplane node cka1024. It’s not running.
Fix the kubelet and confirm that the node is available in Ready state.
Create a Pod called success in default Namespace of image nginx:1-alpine.
ℹ️ The node has no taints and can schedule Pods without additional tolerations
ssh cka1024
systemctl cat kubelet
journalctl -u kubulet
cat /var/lib/kublet/config.yaml
whereis kubelet
vim /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl daemon-reload
systemctl restart kubelet
systemctl status kubelet
k run success --image nginx:1-alpinekiller.sh: CKA-B Q8. Get Controlplane Information
Kubernetes Components Create static Pods
Solve this question on: ssh cka8448
Check how the controlplane components kubelet, kube-apiserver, kube-scheduler, kube-controller-manager and etcd are started/installed on the controlplane node.
Also find out the name of the DNS application and how it’s started/installed in the cluster.
Write your findings into file /course/8/controlplane-components.txt. The file should be structured like:
kubelet: [TYPE]
kube-apiserver: [TYPE]
kube-scheduler: [TYPE]
kube-controller-manager: [TYPE]
etcd: [TYPE]
dns: [TYPE] [NAME]
Choices of [TYPE] are: not-installed, process, static-pod, pod
ssh cka8448
# /course/8/controlplane-components.txt
kubelet: process
kube-apiserver: static-pod
kube-scheduler: static-pod
kube-controller-manager: static-pod
etcd: static-pod
dns: pod corednskiller.sh: CKA-B Q14. Find out Cluster Information
Cluster Networking Create static Pods
Solve this question on: ssh cka8448
You’re asked to find out the following information about the cluster:
- How many controlplane nodes are available?
- How many worker nodes (non controlplane nodes) are available?
- What is the Service CIDR?
- Which Networking (or CNI Plugin) is configured and where is its config file?
- Which suffix will static pods have that run on
cka8448? Write your answers into file/course/14/cluster-info, structured like this:
# /course/14/cluster-info
1: [ANSWER]
2: [ANSWER]
3: [ANSWER]
4: [ANSWER]
5: [ANSWER]
ssh cka8448
# /course/14/cluster-info
1: 1
2: 0
3: 10.96.0.0/12 # cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep "--service-cluster-ip-range"
# OR /etc/kubernetes/manifests/kube-controller-manager.yaml
4: Weave, /etc/cni/net.d/10-weave.conflist
5: -cka8448