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
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
- CSR, Role, Role Binding 생성
- 서비스 생성 후k run test —image=busybox —rm -it —restart=Never — nslookup
- Static Pod 생성
- HPA 생성
- GW TLS 설정
- helm uninstall
- Network Policy 생성
Cluster Architecture, Installation & Configuration 25%
CRI
JayDemy
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 # 검증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-dockerkernel parameter 설정
Mock 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_forwardCNI, podSubnet
Prepium
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 configmap 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.yamlMock 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
cat /root/pod-cidr.txt
172.17.0.0/16kubeconfig
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 작동 확인kubeadm Cluster Upgrade
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 node01ETCD 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.dbRBAC, 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: pvviewerCRD
Prepium
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.txtMock 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.txtHelm
JayDemy
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 template argocd argo/argo-cd --namespace argocd --version 7.7.3 --set crds.install=false > /argo-helm.yaml
helm install argocd argo/argo-cd --namespace argocd --version 7.7.3 --set crds.install=falseMock 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 defaultReview
- helm 으로 argocd 설치
- helm install
- helm upgrade
- helm get values
Workloads & 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-criticalConfigMap, Secrets
Prepium
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} # 실패해야 정상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
Deployment
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-deploySidecar Container
Prepium
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: {}
...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 -fTaint & Toleration, Node Affinity, Node Selector
Prepium
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.yamlMock 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"Review
- Pod 에 nodeSelector (disktype=ssd) 추가하여 특정 Node 에 배포
Resource Requests and Limits
Prepium
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 edit deployment web-app
...
template:
...
spec:
containers:
...
resources:
requests:
cpu: "10m"
memory: "10Mi"
limits:
cpu: "10m"
memory: "10Mi"
...PriorityClass
Prepium
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
...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
...HPA, VPA
JayDemy
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.yamlMock 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: 1kServices & Networking 20%
CoreDNS
Review
/etc/hosts에서 주소를 찾고 없으면/etc/resolv.conf에서 주소를 찾음
Service
JayDemy
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
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: 30080Mock 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.podIngress
JayDemy
Create a new Ingress resource echo in echo-sound namespace exposing Service echoserver-service on http://example.org/echo using Service port 8080.
# vi ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
namespace: echo-sound
spec:
ingressClassName: nginx
rules:
- host: example.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echoserver-service
port:
number: 8080Mock 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/Gateway API
Prepium
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: 80Mock 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: 20NetworkPolicy
Prepium
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.yamlMock 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: 80Storage 10%
PersistentVolume, PersistentVolumeClaim, StorageClass
Prepium
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
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:
volumes:
- name: mariadb-storage
persistentVolumeClaim:
claimName: mariadb
...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: WaitForFirstConsumerTroubleshooting 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_dataReview
- Pod 로그 확인하여 특정 단어가 들어간 log grep 해서 파일로 저장
- Taint 가 없는 노드 개수 파일로 저장
- 노드 Ready 개수 파일로 저장
- 사용률이 가장 높은 파드를 특정 label 로 조회해서 파일로 저장
- explain 명령어로 특정 속성값 정보 파일에 저장하기
kubelet
Review
- 리눅스 kubelet 로그 보기 journal -u kubulet -r - kubelet의 설정 파일 위치 /var/lib/kublet/config.yaml
- whereis kubelet 명령어 kubelet 의 바이너리 경로를 확인가능
- systemctl cat kubelet 쿠블렛 설정파일 위치 찾기
Node Troubleshooting
Review
# 클러스터에서 NotReady 상태의 노드 확인
# 원인 파악, 해당 노드를 Ready 상태로 만들기
# 1. containerd 가 작동하고 있어야 함
# 2. kubelet 이 작동하고 있어야 함
# 3. cni 가 작동하고 있어야 함
kubectl get nodes
ssh hk8s-worker2
systemctl status containerd
systemctl status kubelet # 보통 kubelet 이 inactive 상태임
systemctl enable --now kubelet
systemctl status kubelet
exit
kubectl get nodes- NotReady 상태 Ready 가 되도록 트러블슈팅
- 보통 kubelet
Pod Troubleshooting
JayDemy
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/kubernets/manifests/kube-apiserver.yaml # 문제가 있는 부분 수정. 보통 etcd 주소가 잘못된 경우. 127.0.0.1:2379Mock Exam 3
vi /etc/kubernetes/manifests/kube-controller-manager.yaml # 문제가 있는 부분 수정