Ephemeral Containers란?
Ephemeral Container는 Kubernetes 1.25에서 GA된 실행 중인 Pod에 임시 디버깅 컨테이너를 주입하는 기능이다. Distroless 이미지나 최소 Alpine 이미지로 운영 중인 Pod에는 sh, curl, netstat 같은 도구가 없어 디버깅이 불가능하다. Ephemeral Container를 사용하면 Pod를 재시작하지 않고 디버깅 도구가 포함된 컨테이너를 추가할 수 있다.
kubectl debug 기본 사용법
# 실행 중인 Pod에 디버깅 컨테이너 추가
kubectl debug -it my-app-pod-xxx --image=busybox:1.36 --target=my-app
# --target: 대상 컨테이너의 프로세스 네임스페이스 공유
# 결과: Pod 내부에서 my-app 컨테이너의 프로세스를 볼 수 있음
ps aux
# PID USER COMMAND
# 1 node node dist/main.js ← 원본 컨테이너 프로세스
# 25 root sh ← 디버깅 셸
# 네트워크 디버깅 (같은 네트워크 네임스페이스 공유)
wget -qO- http://localhost:3000/health
netstat -tlnp
nslookup backend-service.default.svc.cluster.local
# 파일시스템 접근 (프로세스 네임스페이스 공유 시)
ls /proc/1/root/app/ # 원본 컨테이너의 파일시스템
cat /proc/1/root/app/dist/main.js
--target 플래그가 핵심이다. 이를 지정하면 대상 컨테이너와 프로세스 네임스페이스를 공유해 ps로 프로세스를 보고, /proc/1/root로 파일시스템에 접근할 수 있다.
디버깅 이미지 선택
| 이미지 | 크기 | 포함 도구 | 용도 |
|---|---|---|---|
busybox |
~4MB | sh, wget, netstat, vi | 기본 디버깅 |
nicolaka/netshoot |
~360MB | tcpdump, nmap, curl, dig, iperf | 네트워크 심화 |
alpine |
~7MB | sh, apk (패키지 설치 가능) | 필요시 도구 설치 |
ubuntu |
~77MB | apt (풀 패키지 관리) | 복잡한 디버깅 |
# 네트워크 심화 디버깅: netshoot
kubectl debug -it my-app-pod --image=nicolaka/netshoot --target=my-app
# DNS 확인
dig backend-service.default.svc.cluster.local
nslookup kubernetes.default
# TCP 연결 테스트
curl -v http://backend-service:3000/api/health
nc -zv database-service 5432
# 패킷 캡처
tcpdump -i eth0 -n port 3000 -w /tmp/capture.pcap
# 대역폭 측정
iperf3 -c backend-service -p 5201
Pod 복사본 디버깅
# 원본 Pod를 복사하여 디버깅 (원본에 영향 없음)
kubectl debug my-app-pod -it --copy-to=my-app-debug
--container=debugger
--image=ubuntu
--share-processes
# 복사본에서 명령어 변경 (entrypoint 오버라이드)
kubectl debug my-app-pod -it --copy-to=my-app-debug
--container=my-app
--image=my-app:v1.2.3
-- sh
# → 원본과 같은 이미지지만 sh로 시작하여 설정 파일 등 확인 가능
# 환경변수·볼륨 동일하게 복사됨
env | grep DATABASE_URL
cat /etc/config/application.yaml
# 디버깅 후 정리
kubectl delete pod my-app-debug
--copy-to는 원본 Pod의 스펙을 그대로 복사한 새 Pod을 생성한다. 프로덕션 Pod에 영향을 주지 않으면서 동일한 환경에서 디버깅할 수 있다.
노드 디버깅
# 노드에 디버깅 Pod 생성 (호스트 파일시스템 마운트)
kubectl debug node/worker-node-1 -it --image=ubuntu
# 호스트 파일시스템은 /host에 마운트됨
ls /host/var/log/
cat /host/var/log/syslog | tail -50
cat /host/etc/kubernetes/manifests/kube-apiserver.yaml
# 호스트의 네트워크 네임스페이스 접근
chroot /host
systemctl status kubelet
journalctl -u kubelet --since "10 minutes ago"
crictl ps
crictl logs <container-id>
# 디스크 사용량 확인
df -h /host
du -sh /host/var/lib/kubelet/pods/* | sort -rh | head -20
# 디버깅 후 정리
kubectl delete pod node-debugger-worker-node-1-xxxxx
노드 디버깅은 kubelet 로그 확인, 디스크 문제 진단, 컨테이너 런타임 상태 확인에 필수적이다.
실전 디버깅 시나리오
시나리오 1: CrashLoopBackOff 원인 분석
# 크래시 직전 상태 확인: 명령어를 sleep으로 교체
kubectl debug my-app-pod -it --copy-to=crash-debug
--container=my-app
--image=my-app:v1.2.3
-- sleep infinity
# 다른 터미널에서 접속
kubectl exec -it crash-debug -c my-app -- sh
# 설정 파일 확인
cat /app/config/production.json
# 수동으로 앱 실행하여 에러 메시지 확인
node /app/dist/main.js
# Error: ECONNREFUSED 10.0.0.5:5432 → DB 연결 문제!
시나리오 2: 느린 응답 원인 추적
# netshoot으로 네트워크 레이턴시 확인
kubectl debug -it slow-api-pod --image=nicolaka/netshoot --target=my-app
# DNS 해석 시간 측정
time nslookup database-service.default.svc.cluster.local
# real 0m2.003s → DNS 지연!
# TCP 연결 시간 측정
curl -w "@/dev/stdin" -o /dev/null -s http://backend:3000/api/health <<'EOF'
time_namelookup: %{time_namelookup}sn
time_connect: %{time_connect}sn
time_starttransfer: %{time_starttransfer}sn
time_total: %{time_total}sn
EOF
# 열린 연결 수 확인
ss -tnp | grep :5432 | wc -l
# 150 → 커넥션 풀 고갈!
시나리오 3: Distroless 컨테이너 파일 확인
# Distroless 이미지는 셸이 없음
kubectl exec my-app-pod -- sh
# OCI runtime exec failed: exec failed: unable to start container process:
# exec: "sh": executable file not found
# Ephemeral Container로 해결
kubectl debug -it my-app-pod --image=busybox --target=my-app
# /proc를 통해 원본 컨테이너 파일시스템 접근
ls /proc/1/root/app/
cat /proc/1/root/app/package.json
cat /proc/1/root/tmp/heapdump.json
# 메모리 사용량 확인
cat /proc/1/status | grep -i vm
# VmRSS: 245780 kB → 실제 사용 메모리 240MB
프로파일링과 힙 덤프
# Node.js 힙 덤프 (디버깅 컨테이너에서)
kubectl debug -it my-app-pod --image=node:20-slim --target=my-app
# Node.js 프로세스에 시그널 전송
kill -USR2 1 # 힙 덤프 생성 (앱에 heapdump 모듈 필요)
# 또는 Chrome DevTools 연결
node --inspect=0.0.0.0:9229 -e "setTimeout(() => {}, 999999)"
# 포트 포워딩 후 chrome://inspect에서 연결
# Java 앱 힙 덤프
kubectl debug -it java-app-pod --image=eclipse-temurin:21-jdk --target=java-app
jcmd 1 GC.heap_dump /tmp/heapdump.hprof
jcmd 1 Thread.print # 스레드 덤프
jcmd 1 VM.flags # JVM 플래그 확인
jstat -gc 1 1000 5 # GC 통계 (1초 간격, 5회)
보안 고려사항
# 1. RBAC으로 ephemeral container 권한 제한
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: debug-access
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/ephemeralcontainers"]
verbs: ["patch"] # 이 권한이 있어야 debug 가능
# pods/exec는 별도 — 디버깅 컨테이너 셸 접근용
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
# 2. Pod Security Standards 확인
# Ephemeral Container도 Pod의 securityContext를 따름
# Restricted 정책에서는 root 실행, hostNetwork 등 제한됨
# 3. 감사 로그로 디버깅 활동 추적
# API 서버 audit log에서 ephemeralcontainers PATCH 확인
kubectl get events --field-selector reason=EphemeralContainerAdded
# 4. 허용된 디버깅 이미지 제한 (OPA Gatekeeper)
# 특정 이미지만 ephemeral container로 허용
OPA Gatekeeper로 디버깅 이미지를 제한하는 방법은 K8s OPA Gatekeeper 정책 관리 글을 참고하자. RBAC 권한 설계는 K8s RBAC 권한 관리 심화 글에서 다루고 있다.
유용한 별칭과 스크립트
# ~/.bashrc에 추가
alias kdebug='kubectl debug -it --image=nicolaka/netshoot --target'
alias kdebug-node='kubectl debug node/ -it --image=ubuntu'
alias kdebug-copy='kubectl debug --copy-to=debug-copy --share-processes -it'
# 자주 쓰는 디버깅 원라이너
# Pod의 모든 환경변수 확인 (exec 불가능한 컨테이너)
kubectl debug -it $POD --image=busybox --target=$CONTAINER
-- cat /proc/1/environ | tr ' ' 'n'
# 컨테이너 리소스 사용량 실시간 모니터링
kubectl debug -it $POD --image=busybox --target=$CONTAINER
-- sh -c 'while true; do cat /proc/1/status | grep -E "VmRSS|Threads"; sleep 2; done'
# Ephemeral Container 상태 확인
kubectl get pod $POD -o jsonpath='{.spec.ephemeralContainers[*].name}'
kubectl get pod $POD -o jsonpath='{.status.ephemeralContainerStatuses[*]}'
마무리
| 디버깅 방법 | 명령어 | 특징 |
|---|---|---|
| Pod에 주입 | kubectl debug -it POD --image=IMG --target=CTR |
실행 중 Pod에 바로 접근 |
| Pod 복사 | kubectl debug POD --copy-to=NAME |
원본 영향 없음 |
| 노드 디버깅 | kubectl debug node/NAME |
호스트 파일시스템 접근 |
Ephemeral Container는 “셸 없는 프로덕션 컨테이너”와 “디버깅 필요성” 사이의 간극을 메운다. Distroless 이미지를 써서 보안을 강화하면서도, 필요할 때 netshoot이나 jdk를 주입해 네트워크·힙·스레드를 분석할 수 있다. Pod를 재시작하거나 이미지를 변경할 필요가 없으므로, 프로덕션 장애 대응에서 가장 먼저 꺼내야 할 도구다.