LabHub
배우기 러닝패스 코스

CKA — Kubernetes管理者

壊してから直す

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 된 노드와 테인트된 노드가 하나씩 있습니다. 어느 쪽을 쓰려면 무엇이 필요한지 계산한 뒤 배포하세요.