CKA — Kubernetes Administrator
Break It, Then Fix It
한국어 원문으로 표시합니다.
목표
실제 현장에서 가장 자주 만나는 고장 다섯 가지를 직접 만들고 직접 고치면서, 증상에서 원인으로 내려가는 순서를 몸에 새깁니다.
왜 중요한가
트러블슈팅은 CKA 배점의 30%, 가장 큰 도메인입니다. 그런데 고쳐 놓은 것만 보면 배우는 게 없습니다. 그래서 이 실습은 깨진 상태를 학생이 만들고, 증상을 파일로 남기고, 그 다음 고치는 순서로 설계했습니다. 각 단계의 채점은 고쳐진 결과뿐 아니라 깨져 있었다는 증거도 함께 봅니다.
증상을 남기는 습관 자체가 실무 기술입니다. 장애가 끝나면 증거는 사라집니다. 원인을 나중에 설명하려면 그 순간의 이벤트와 상태를 남겨 두어야 합니다.
앞 단계에서 만든 클러스터 상태(cordon 된 노드, 테인트된 노드)는 뒤 단계에도 그대로 남습니다. 마지막 문제는 그 상태를 정확히 기억해야 풀립니다.
단계
- 네임스페이스
cka-broken을 만들고 Deploymentweb(레플리카 2)을 이미지nginx:1.99-nonexistent로 만든다. 그 잘못된 이미지 태그가 보이는 출력을/root/cka-broken/bad-image.txt에 저장한 뒤, 이미지를nginx:1.27로 교체해 2/2 Ready 로 만든다. 디플로이먼트를 지우지 말고 이미지만 고친다. - 파드
heavy(이미지nginx:1.27)를 requestscpu: 500,memory: 2000Gi로 만든다. Pending 이 되는 것을 확인하고 그 사유가 담긴 출력을/root/cka-broken/pending.txt에 저장한다.heavy는 지우지 말고 남긴 채, Deploymentheavy-fixed(레플리카 1, 이미지nginx:1.27, requestscpu: 500m,memory: 2000Mi)를 만들어 1/1 Ready 로 만든다. - 서비스
api-svc(셀렉터app=api, port 80)를 만들고, Deploymentapi를 파드 라벨과 셀렉터를app=api-v2로 잘못 만든다.api-svc의 엔드포인트가 빈 것을/root/cka-broken/svc-before.txt에 저장한 뒤,api를 라벨app=api로 바로잡아 레플리카 2를 Ready 로 만든다. 서비스 셀렉터는app=api그대로 둔다. - 네임스페이스
cka-broken-quota를 만들고 ResourceQuotacka-quota를pods: "2",requests.cpu: "1"로 만든다. Deploymentq-app(레플리카 4, 이미지nginx:1.27, requestscpu: 200m)을 만들면 일부만 뜬다.exceeded quota가 보이는 이벤트를/root/cka-broken/quota.txt에 저장한 뒤, 쿼터의pods를5로 올려 4/4 Ready 로 만든다. cka-broken에 Deploymentcritical(레플리카 2, 이미지nginx:1.27, 파드 라벨app=critical)과 PDBcritical-pdb(셀렉터app=critical,minAvailable: 2)를 만든다.lab-node-2를 drain 해 보고 막히는 메시지를/root/cka-broken/pdb.txt에 저장한 뒤,minAvailable을1로 낮추고lab-node-2를 cordon + drain 해 완전히 비운다.lab-node-0에 라벨disktype=ssd와 테인트maintenance=true:NoSchedule을 건다. 파드needs-toleration(이미지nginx:1.27, nodeSelectordisktype=ssd, 톨러레이션 없음)을 만들어 Pending 을 확인하고 사유를/root/cka-broken/taint.txt에 저장한다.needs-toleration은 남겨 둔 채, 파드needs-toleration-fixed를 같은 nodeSelector 에 톨러레이션까지 붙여 만들어lab-node-0에 배치한다.- 파드
data-app(이미지nginx:1.27)이 PVCapp-data를/data에 마운트하도록 만든다. PVC 가 아직 없어 뜨지 못하는 사유를/root/cka-broken/pvc.txt에 저장한 뒤, PVcka-fix-pv(1Gi, RWO, storageClassNamecka-fix, hostPath/mnt/cka-fix)와 PVCapp-data(1Gi, RWO,cka-fix)를 만들어 Bound 시키고data-app이 Running 이 되게 한다. - Deployment
recovered(레플리카 4, 이미지nginx:1.27, 파드 라벨app=recovered)를cka-broken에 만든다. requests 는cpu: 100m,memory: 128Mi,maintenance=true:NoSchedule톨러레이션, topologySpreadConstraints 는 maxSkew 1 / topologyKeykubernetes.io/hostname/ whenUnsatisfiableScheduleAnyway/ labelSelectorapp=recovered. 4/4 Ready 로 만들고, 고친 문제 다섯 가지를/root/cka-broken/summary.md에 정리한다. 이 파일에는image,taint,selector,quota,pdb다섯 단어가 모두 들어가야 한다.
참고
- 스케줄 실패 사유는
kubectl describe pod <이름> -n cka-broken의 Events 절에 있습니다. - 쿼터 초과는 파드가 아니라
kubectl describe rs나kubectl get events -n cka-broken-quota에서 보입니다. - drain 은
--ignore-daemonsets --delete-emptydir-data --force --timeout=60s를 붙이면 진행이 수월합니다. - 흔한 실수 1: 증거 파일을 남기기 전에 먼저 고쳐 버리는 것. 순서가 곧 채점 항목입니다.
- 흔한 실수 2: 8단계에서 톨러레이션을 빼먹는 것.
lab-node-2는 cordon,lab-node-0은 테인트 상태라 쓸 수 있는 노드가 하나밖에 남지 않습니다.
잘못된 이미지 태그
네임스페이스 cka-broken 을 만들고 Deployment web (레플리카 2)을 이미지 nginx:1.99-nonexistent 로 만든다. 그 잘못된 이미지 태그가 보이는 출력을 /root/cka-broken/bad-image.txt 에 저장한 뒤, 이미지를 nginx:1.27 로 교체해 2/2 Ready 로 만든다. 디플로이먼트를 지우지 말고 이미지만 고친다.
먼저 잘못된 태그로 만들고 증거를 남긴 뒤 이미지만 교체하세요. 디플로이먼트를 지우고 다시 만들면 문제 리비전이 사라져 채점에서 걸립니다.
자원 요청 단위 실수
파드 heavy (이미지 nginx:1.27)를 requests cpu: 500, memory: 2000Gi 로 만든다. Pending 이 되는 것을 확인하고 그 사유가 담긴 출력을 /root/cka-broken/pending.txt 에 저장한다. heavy 는 지우지 말고 남긴 채, Deployment heavy-fixed (레플리카 1, 이미지 nginx:1.27, requests cpu: 500m, memory: 2000Mi)를 만들어 1/1 Ready 로 만든다.
cpu 값에서 m 을 빠뜨리면 밀리코어가 아니라 코어가 됩니다. describe 의 Events 절에 스케줄러가 왜 실패했는지 그대로 나옵니다.
서비스와 라벨이 어긋난 디플로이먼트
서비스 api-svc (셀렉터 app=api, port 80)를 만들고, Deployment api 를 파드 라벨과 셀렉터를 app=api-v2 로 잘못 만든다. api-svc 의 엔드포인트가 빈 것을 /root/cka-broken/svc-before.txt 에 저장한 뒤, api 를 라벨 app=api 로 바로잡아 레플리카 2를 Ready 로 만든다. 서비스 셀렉터는 app=api 그대로 둔다.
디플로이먼트의 spec.selector 는 불변입니다. 잘못 만들었다면 수정이 아니라 다시 만들어야 합니다. 서비스 쪽 셀렉터는 건드리지 마세요.
ResourceQuota 초과
네임스페이스 cka-broken-quota 를 만들고 ResourceQuota cka-quota 를 pods: "2", requests.cpu: "1" 로 만든다. Deployment q-app (레플리카 4, 이미지 nginx:1.27, requests cpu: 200m)을 만들면 일부만 뜬다. exceeded quota 가 보이는 이벤트를 /root/cka-broken/quota.txt 에 저장한 뒤, 쿼터의 pods 를 5 로 올려 4/4 Ready 로 만든다.
쿼터에 걸린 파드는 파드가 아니라 ReplicaSet 의 이벤트로 나타납니다. 쿼터를 올리기 전에 그 이벤트를 먼저 저장하세요.
PDB 로 막힌 drain
cka-broken 에 Deployment critical (레플리카 2, 이미지 nginx:1.27, 파드 라벨 app=critical)과 PDB critical-pdb (셀렉터 app=critical, minAvailable: 2)를 만든다. lab-node-2 를 drain 해 보고 막히는 메시지를 /root/cka-broken/pdb.txt 에 저장한 뒤, minAvailable 을 1 로 낮추고 lab-node-2 를 cordon + drain 해 완전히 비운다.
레플리카 2에 minAvailable 2 면 한 개도 뺄 수 없습니다. --force 로 밀어붙이는 대신 PDB 가 무엇을 지키려는지 다시 계산하세요.
톨러레이션 누락
lab-node-0 에 라벨 disktype=ssd 와 테인트 maintenance=true:NoSchedule 을 건다. 파드 needs-toleration (이미지 nginx:1.27, nodeSelector disktype=ssd, 톨러레이션 없음)을 만들어 Pending 을 확인하고 사유를 /root/cka-broken/taint.txt 에 저장한다. needs-toleration 은 남겨 둔 채, 파드 needs-toleration-fixed 를 같은 nodeSelector 에 톨러레이션까지 붙여 만들어 lab-node-0 에 배치한다.
NoSchedule 테인트는 새 파드만 막고 이미 떠 있는 파드는 건드리지 않습니다. 문제 파드는 지우지 말고 남겨 두세요.
존재하지 않는 PVC
파드 data-app (이미지 nginx:1.27)이 PVC app-data 를 /data 에 마운트하도록 만든다. PVC 가 아직 없어 뜨지 못하는 사유를 /root/cka-broken/pvc.txt 에 저장한 뒤, PV cka-fix-pv (1Gi, RWO, storageClassName cka-fix, hostPath /mnt/cka-fix)와 PVC app-data (1Gi, RWO, cka-fix)를 만들어 Bound 시키고 data-app 이 Running 이 되게 한다.
파드를 먼저 만들어 실패를 확인한 뒤 볼륨을 만드세요. PVC 가 묶이면 스케줄러가 그 파드를 다시 시도하니 잠시 기다리면 됩니다.
종합: 남은 클러스터에서 복구 배포하기
Deployment recovered (레플리카 4, 이미지 nginx:1.27, 파드 라벨 app=recovered)를 cka-broken 에 만든다. requests 는 cpu: 100m, memory: 128Mi, maintenance=true:NoSchedule 톨러레이션, topologySpreadConstraints 는 maxSkew 1 / topologyKey kubernetes.io/hostname / whenUnsatisfiable ScheduleAnyway / labelSelector app=recovered. 4/4 Ready 로 만들고, 고친 문제 다섯 가지를 /root/cka-broken/summary.md 에 정리한다. 이 파일에는 image, taint, selector, quota, pdb 다섯 단어가 모두 들어가야 한다.
지금 이 클러스터에는 cordon 된 노드와 테인트된 노드가 하나씩 있습니다. 어느 쪽을 쓰려면 무엇이 필요한지 계산한 뒤 배포하세요.