kubectl debug로 distroless 파드에 셸 붙이기
이거 모르는 분 꽤 많더라. 요즘 이미지 최적화한다고 distroless로 다 갈아엎는 팀이 늘어나면서, 정작 장애 났을 때 파드 안에 들어갈 방법이 없어서 당황하는 경우를 몇 번 봤다. kubectl exec 때려도 sh not found 뜨고, 로그만 봐서는 원인 파악이 안 되는 상황.
kubectl debug 로 ephemeral container 붙이면 된다. 1.25에서 GA 됐고 지금은 안정적이다. 오늘 자주 쓰는 패턴 3개만 정리한다.
1. distroless 파드에 셸 붙이기
가장 흔한 케이스. target 컨테이너의 프로세스/네트워크 네임스페이스를 공유하는 임시 컨테이너를 하나 띄운다.
kubectl debug -it my-pod \
--image=nicolaka/netshoot \
--target=my-container -- bash
--target 이 핵심이다. 이걸 안 붙이면 컨테이너는 붙긴 하는데 원래 컨테이너 프로세스가 안 보인다. ps aux 쳐서 target 컨테이너의 앱 프로세스가 보이면 성공.
netshoot 대신 busybox:latest, alpine:3.20 도 되는데, 네트워크 디버깅까지 할 거면 netshoot이 tcpdump/dig/nslookup/mtr까지 다 들어있어서 편하다.
2. CrashLoopBackOff 파드 복사해서 디버깅
이미 죽고 있는 파드에 exec은 안 붙는다. 그럴 땐 파드를 복사해서 command만 바꿔 띄운다.
kubectl debug my-crashing-pod -it \
--copy-to=my-debug \
--container=my-container \
--image=my-image:latest \
--share-processes \
-- sh
--copy-to 로 새 이름으로 복제하고, entrypoint를 shell로 덮어써서 앱 시작 로직을 우회한다. 그다음 컨테이너 안에서 앱 바이너리를 직접 실행해보면 stdout으로 에러가 그대로 나온다. envsubst 실패, config 마운트 경로 오타 같은 것들이 이때 잡힌다.
원본 파드는 안 건드리니까 오토스케일러나 컨트롤러가 개입할 걱정도 없다.
3. 노드에 셸 붙이기
파드 문제가 아니라 노드 레벨 문제(디스크, kubelet, 네트워크)일 때. SSH 없이도 노드 호스트 네임스페이스에 붙을 수 있다.
kubectl debug node/ip-10-0-1-42 -it \
--image=nicolaka/netshoot
이러면 호스트 루트 파일시스템이 /host 에 마운트된 privileged 파드가 뜬다. chroot /host 로 들어가면 사실상 노드에 SSH 붙은 것과 같다. journalctl, iptables, crictl 다 된다.
카프카 EBS 볼륨 100% 찼을 때 이걸로 붙어서 로그 파일 정리한 적 있는데, SSH 키 배포 안 된 노드였어도 되니까 유용했다.
주의할 점 하나
kubectl debug 는 RBAC 상 pods/ephemeralcontainers 리소스에 대한 update 권한이 필요하다. 개발자 role에 이게 안 붙어있으면 실패한다. 팀 role 설정 확인해두면 좋다. 우리 팀은 dev role에는 뺐고, oncall role에만 넣어놨다.
노드 debug 는 아예 파드 생성 권한이라 더 조심해야 한다. 사실상 노드 루트 권한이니까.
혹시 cdebug 같은 래퍼 툴 쓰시는 분 있나. 몇 번 써봤는데 이미지 프리셋이 편하긴 한데 결국 하는 일은 같아서 요즘은 그냥 kubectl debug 만 쓴다. 다른 워크플로 있으면 공유해주세요.