CKA 시험을 보면서 기출 문제가 굉장히 중요하다는 것을 알게 되었다. 인터넷에서 살펴본 기출 문제들에서 다 고만고만하게 나오는 느낌이 있었고 살펴본 결과 약 1~2년 전부터 쓰인 블로그들을 통해서 기출 문제들을 분석했는데, 실제 시험과 비슷하게 나왔다. 나 또한 CKA 시험을 보고 난 후에 기출 문제를 정리함으로써 CKA를 준비하는 사람들에게 많은 도움이 되고자 내용을 정리했다.
본론
CKA의 시험 환경은 생각보다 많이 친절하다. 아마도 killer.sh나 Kodekloud를 통해서 mock exam을 본 사람들이 많을텐데, 이에 비해서 엄청나게 친절하다. 키워드들(pod name, path) 등에 복사를 편리하게 해줄 수 있게 클릭으로 복사를 지원하거나, 관련된 문제의 레퍼런스를 직접 달아두어 바로 접근할 수 있게 해준다.
이 외에도 ssh 연결이나 sudo 등의 권한이 필요한 경우에는 사용 방법을 알려주는 등 리눅스에 대한 것들도 알려주는 등 친절한 환경이 있다. 가장 중요한 것은 쿠버네티스 공식 문서의 레퍼런스를 달아둔다는 점인데, 직접 시험 환경에 접속하면 레퍼런스를 통해서 문제를 해결하는 것 위주이기 때문에 이번 포스팅에서는 공식 레퍼런스와 함께 기출 문제를 정리하였으니, 반드시 공식 레퍼런스와 함께 외우자. 시험장에서는 공식 레퍼런스를 볼 수 있기 때문에 여기에 쓰인 내용대로 공식 문서를 이해한다면, 시험장에서도 문제 없이 편하게 문제를 풀 수 있다. 개인적으로 생각하는 중요도 순서대로 정렬하였으며, 참고하자.
ETCD Backup & Restore ( 필수 )
ETCD Backup & Restore는 꼭 한 번 씩은 나온다. 공식 레퍼런스를 정독하고, 직접 실습하고 확인까지 하고 현장에 가는 게 좋다.
- ETCD Backup & Restore : https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/
ETCD 접근 확인
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
member list
각각의 파라미터에 문제에서 제시하는 파일을 넣어준다. 그리고 member list로 먼저 제대로 작동하는지 확인한다. 확인이 끝났다면 백업 및 복구를 바로 진행하자.
ETCD 백업
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
snapshot save /opt/data/etcd-backup-data.db
/opt/data/etcd-backup-data.db에 저장하라고 나와 있다면 위와 같이 저장한다. snapshot save 기능을 사용한다.
ETCD 복구
공식 문서에 나와있는 명령어는 아래와 같다. 스냅샷을 ENDPOINT에 복구하는 명령어다.
ETCDCTL_API=3 etcdctl --endpoints $ENDPOINT snapshot save snapshot.db
실제 시험 환경에서는 아래과 같이 사용한다. 이미 존재하는 스냅샷을 적당한 엔드포인트에 복구한다. 기본 ETCD의 저장소가 /var/lib/etcd이므로, 나는 /var/lib/etcd-backup을 사용했다. /data/previous-etcd-backup.db 과 같이 이전의 데이터가 있다면 아래와 같이 복구할 수 있다.
ETCDCTL_API=3 etcdctl --endpoints /var/lib/etcd-backup snapshot save /data/previous-etcd-backup.db
etcd.yaml 수정
마지막으로는 static pod으로 실행되고 있는 etcd.yaml이 백업된 etcd의 디렉토리를 바라보게 만들어야 한다. 다음과 같이 수정하면 알아서 이를 감지하고 etcd가 자동으로 실행된다. 참고로 static pod의 디렉터리는 /etc/kubernetes/manifests 이다. spec.volumes를 다음과 같이 수정한다.
# ...
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd-backup # 백업한 디렉터리로 수정한다.
type: DirectoryOrCreate
name: etcd-data
status: {}
여기까지 한 후에 etcd를 체크해보면 바라보고 있는 volumes 디렉터리가 바뀌어있을 것이다. 이를 체크하고나면 넘어가면 된다.
Cluster Upgrade ( 필수 )
ETCD backup & restore와 함께 반드시 나오는 내용이므로 이것도 기계적으로 숙지가 필요하다. 다음의 레퍼런스를 참고한다.
- Kubernetes Upgrade : https://v1-31.docs.kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/
최근 시험 문제에서는 마스터 노드만 업그레이드하게끔 나오는 것으로 보인다. 여기서는 마스터 노드만 1.31.0에서 1.31.1 버전으로 업그레이드하는 명령어를 쓴다.
# 마스터 노드 드레인
kubectl drain controlplane --ignore-daemonsets
sudo apt update
sudo apt-cache madison kubeadm
# madison kubeadm 명령어를 통해 나오는 버전을 입력한다.
sudo apt-mark unhold kubeadm && \
sudo apt-get update && sudo apt-get install -y kubeadm='1.31.1-1.1' && \
sudo apt-mark hold kubeadm
kubeadm version
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.31.1
# kubelet과 kubectl도 업그레이드
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get update && sudo apt-get install -y kubelet='1.31.1-1.1' kubectl='1.31.1-1-1' && \
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# drain 시켰던 것을 해제
kubectl uncordon controlplain
# 확인
kubectl get nodes -o wide
마지막 명령어를 통해서 각 노드의 버전을 확인할 수 있다. 만약 워커 노드의 업그레이드도 필요하다고 하면, 컨트롤 플레인에서 드레인 시킨 후 워커 노드에서는 kubelet의 업데이트를 수행하면 된다.
Ingress 생성 ( 필수 )
Ingress를 다루는 문제도 필수적으로 나온다. 이 문제는 직접 테스트하는 것까지 중요하기 때문에 꼭 curl 명령어로 확인을 해보자. 이 문제에서 Pod와 Service는 일반적으로 주어진다. 잘 맞춰서 Ingress를 생성한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ping
namespace: ing-internal
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx-example # 이 부분은 지운다.
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: hello # service의 이름을 입력한다.
port:
number: 5678
위 레퍼런스에서 Ingress에 대한 yaml 파일 템플릿을 가져온 후 위와 같이 변경한다. name은 ping, namespace는 ing-internal, 그리고 /hello 로 요청하면 hello라는 이름의 service로 보내는 경우에는 위와 같다. 아래와 같이 확인할 수 있다.
# IP 확인
kubectl describe ingress ping -n ing-internal
# 테스트 및 응답
curl -kL <cluster-ip>/hello
> hello
Kubelet 트러블슈팅 ( 필수 )
특정 노드가 이상하다고 NotReady를 Ready로 바꾸라는 문제이다. 생각보다 복잡한 내용이 없이 kubelet을 재실행하는 것으로 끝난다. systemctl을 사용하기 때문에 따로 큰 레퍼런스는 없다. 꼭 나오는 문제이기 때문에 알아두자.
# 문제의 노드 확인
kubectl get node -o wide
# 문제의 노드 접속하기
ssh k8s-node-1
kubelet.service를 확인한 후에 발생한 문제들을 해결해야하는데, 시험에서는 크게 별 다른 이상 없이 CPU Load로 인해 inactive로 표시되어있다. 이를 재실행하면 된다. 마지막에서는 다시 exit로 돌아와서 확인해보자.
# kubelet 상태 확인하기 ( inactive )
systemctl status kubelet
# kubelet 재시작하기
systemctl restart kubelet
# kubelet 상태 확인하기 ( active로 바뀌어있을 것이다. )
systemctl status kubelet
제대로 kubelet이 확인 되었다면, 마지막으로 kubectl get nodes -o wide를 통해서 확인해보자. 제대로 Ready로 표시가 되어있는 지 보자.
SC를 사용하는 PVC 생성 ( 필수 )
이 부분은 어느 정도 문제가 정형화되어 있다. 다음의 레퍼런스에서 SC를 사용하는 yaml 파일을 작성하면 된다. 그 후 Pod을 생성할 때, hostPath와 persistentVolumeClaim을 지정한다. 마지막으로 request를 10Mi에서 70Mi로 상향하라는 조건도 있다. 꼭 까먹지 말고 kubectl edit pvc pv-volume으로 변경하자.
- Persistent Volumes : https://kubernetes.io/docs/concepts/storage/persistent-volumes/
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume
spec:
storageClassName: csi-hostpath-sc
dataSource:
name: new-snapshot-test
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
위의 yaml 파일을 적당히 변형하여 pv-volume을 생성한다. 그 후에 Pod를 생성할때 아래와 같이 마운트를 지정해주면 된다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/lib/data/nginx"
name: just-name
volumes:
- name: just-name
persistentVolumeClaim:
claimName: pv-volume # 생성한 pvc의 이름을 입력한다.
위와 같이 지정한 경로로 mountPath를 설정하면 된다. 마지막에 용량을 증설하라는 명령이 작게 쓰여 있다면 꼭 edit 명령어로 pvc를 설정하자.
Serviceaccount와 권한 문제 ( 필수 )
Serviceaccount 문제도 꼭 나오는 문제이다. 꼭 직접 해보고 가자. 이 문제는 kubectl의 create 명령어로 손쉽게 해결할 수 있다. 명령어를 사용할 때마다 --help 파라미터를 통해서 명령어 사용법을 계속 확인해가면서 놓친 게 없는지 착실하게 순서대로 진행하자. clusterrole -> serviceaccount -> clusterrolebinding 순서대로 만들면 된다.
Cluster Role
# 명령어의 정확한 사용 방법을 확인한다.
kubectl create clusterrole -h
kubectl create clusterrole deploy-cluster --verb=create \
--resource=deployment,statefulset
항상 -h를 통해서 정확한 명령어를 제대로 확인하고 가야한다! 문제에서 제시하는 조건을 하나도 빼먹으면 안된다.
Service Account
kubectl create serviceaccount -h
# serviceaccount 생성
kubectl create serviceaccount cicd-token --namespace=developer
Cluster Role Binding
kubectl create clusterrolebinding -h
kubectl create clusterrolebinding cluster-role-binding --clusterrole=deploy-cluster \
--serviceaccount=developer:cicd-token
위와 같은 순서로 생성해주면 문제는 끝이 난다. 중요한 점은 항상 -h를 붙여 명령어 사용법을 제대로 쓰고 있는 지를 확인해가면서, 신중하게 문제에서 주어진 조건들을 집어넣어 명령어를 완성하자.
그 외 간단한 문제들
그 외에 간단한 문제들은 평범한 난이도이기 때문에 기계적으로 숙지하지 않아도 현장에서는 간단하게 레퍼런스를 통해서 풀 수 있는 수준의 레벨이기 때문에 이쪽 섹션으로 빼두었다. 이 부분도 다른 레퍼런스를 찾아보았을 때, 거의 똑같이 나오기 때문에 여러번 보고 가자. 훑어보는 정도로도 괜찮을 것 같다.
Deployment의 replicas 변경
# 다음의 명령어로 replicas를 변경한다.
kubectl edit deployment nginx-deploy
CPU 사용량이 가장 높은 노드의 이름 저장하기
# CPU 사용량 조회
kubectl top pods
# 저장
echo "CPU-POD-f5sa2" > /opt/answer.txt
스케줄링 가능한 노드의 개수 저장하기
# 모든 노드를 확인한다.
kubectl get node
# 스케줄링이 가능한지 확인하기, 스케줄링이 가능한 노드는 NoSchedule이 아무것도 잡히지 않는다.
kubectl describe k8s-node-0 | grep -i NoSchedule
# 개수 저장
echo "2" > /opt/answer.txt
멀티 컨테이너 Pod 생성
kubectl run nginx --image=nginx --dry-run=client -o yaml > multi.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: multi-container
spec:
containers:
- image: nginx
name: nginx
- image: memcached
name: memcached
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
위와 같이 하나의 이미지를 추가해준 후 생성하면 된다. 아래와 같이 생성 및 확인할 수 있다. 문제가 없다면 다음 문제로 넘어가자.
# 생성
kubectl create -f multi.yaml
# 확인
kubectl describe pod multi-container
NodePort 타입의 service 생성하기
dry-run=client을 통해서 service를 생성하는 방법이 있지만, kubectl expose를 사용하는 편이 안전하고 편리하다. 다음의 명령어를 통해 해결할 수 있다. ( NodePort 대문자 잘 적기! )
kubectl expose pod nginx-resolver --name=nginx-resolver-service --port=80 \
--target-port=80 --type=NodePort
그 후에는 생성된 Service를 확인하면 끝이다.
log를 추출해서 저장하기
kubectl logs abnormal-pod | grep error-reason > /opt/answer.txt
마치며
대학교를 졸업하기 전에 꽤 인지도 있는 유명한 자격증인 AWS의 SAA-C03와 CKA를 취득했는데, 개인적으로는 CKA의 편이 좀 더 재미있었던 것 같다. 원격 접속을 통해 시험 환경에서 직접 실기로 진행하니까. 확실하게 손맛이 있다.
시험 환경은 꽤나 친절하기 때문에 한 번 접속하기만 하면 편리하게 시험을 볼 수 있다. 다만 PSI라는 클라이언트를 통해서 원격 환경에 접근하는데, 나는 그 전에 응용 프로그램 종료에서 문제가 발생했다. ScreenSharingSubscriber라는 어떤 프로세스가 남아있어서 시험 진행이 불가능했는데, 다음의 명령어를 통해서 힘들게 끄고 진행했다.
# 문제의 프로세스 확인
ps aux | grep ScreenSharingSubscriber
# 프로세스 제거
sudo kill -9 PROCESS_ID
시험 전에는 웹서핑이 되니까, 혹시 시험 입장 전에 같은 에러를 본 사람은 꼭 이곳으로 돌아오시길... 두 시간동안 보는 시험이니 멘탈이 시작부터 깨지지 않았으면 한다.
참고
- [피터의 개발이야기] CKA 기출문제 정리 : https://peterica.tistory.com/540
감사합니다.
'DevOps > kubernetes' 카테고리의 다른 글
쿠버네티스의 Kustomize에 대해서 (1) | 2024.12.20 |
---|---|
ETCD Leader Election이란? (1) | 2024.12.18 |
Kubernetes의 Ingress와 Service 차이점에 대한 고찰 (0) | 2024.12.17 |
로컬 쿠버네티스 클러스터 환경 세팅 ( feat. minikube, lens ) (1) | 2024.12.16 |
[K8s homeserver 구축 - 3] github actions를 통한 CI (0) | 2023.11.10 |