LabHub
배우기 러닝패스 코스

CKA — Kubernetes Administrator

Break It, Then Fix It

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

실제 현장에서 가장 자주 만나는 고장 다섯 가지를 직접 만들고 직접 고치면서, 증상에서 원인으로 내려가는 순서를 몸에 새깁니다.

왜 중요한가

트러블슈팅은 CKA 배점의 30%, 가장 큰 도메인입니다. 그런데 고쳐 놓은 것만 보면 배우는 게 없습니다. 그래서 이 실습은 깨진 상태를 학생이 만들고, 증상을 파일로 남기고, 그 다음 고치는 순서로 설계했습니다. 각 단계의 채점은 고쳐진 결과뿐 아니라 깨져 있었다는 증거도 함께 봅니다.

증상을 남기는 습관 자체가 실무 기술입니다. 장애가 끝나면 증거는 사라집니다. 원인을 나중에 설명하려면 그 순간의 이벤트와 상태를 남겨 두어야 합니다.

앞 단계에서 만든 클러스터 상태(cordon 된 노드, 테인트된 노드)는 뒤 단계에도 그대로 남습니다. 마지막 문제는 그 상태를 정확히 기억해야 풀립니다.

단계

  1. 네임스페이스 cka-broken 을 만들고 Deployment web (레플리카 2)을 이미지 nginx:1.99-nonexistent 로 만든다. 그 잘못된 이미지 태그가 보이는 출력을 /root/cka-broken/bad-image.txt 에 저장한 뒤, 이미지를 nginx:1.27 로 교체해 2/2 Ready 로 만든다. 디플로이먼트를 지우지 말고 이미지만 고친다.
  2. 파드 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 로 만든다.
  3. 서비스 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 그대로 둔다.
  4. 네임스페이스 cka-broken-quota 를 만들고 ResourceQuota cka-quotapods: "2", requests.cpu: "1" 로 만든다. Deployment q-app (레플리카 4, 이미지 nginx:1.27, requests cpu: 200m)을 만들면 일부만 뜬다. exceeded quota 가 보이는 이벤트를 /root/cka-broken/quota.txt 에 저장한 뒤, 쿼터의 pods5 로 올려 4/4 Ready 로 만든다.
  5. 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 에 저장한 뒤, minAvailable1 로 낮추고 lab-node-2 를 cordon + drain 해 완전히 비운다.
  6. 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 에 배치한다.
  7. 파드 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 이 되게 한다.
  8. 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 다섯 단어가 모두 들어가야 한다.

참고

잘못된 이미지 태그

네임스페이스 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-quotapods: "2", requests.cpu: "1" 로 만든다. Deployment q-app (레플리카 4, 이미지 nginx:1.27, requests cpu: 200m)을 만들면 일부만 뜬다. exceeded quota 가 보이는 이벤트를 /root/cka-broken/quota.txt 에 저장한 뒤, 쿼터의 pods5 로 올려 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 에 저장한 뒤, minAvailable1 로 낮추고 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 된 노드와 테인트된 노드가 하나씩 있습니다. 어느 쪽을 쓰려면 무엇이 필요한지 계산한 뒤 배포하세요.