워크로드 디버깅
Pod 상태별 디버깅 플로우차트
기본 디버깅 명령어
# Pod 상태 확인
kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
# 현재/이전 컨테이너 로그 확인
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
# 네임스페이스 이벤트 확인
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
# 리소스 사용량 확인
kubectl top pods -n <namespace>
kubectl debug 활용법
Ephemeral Container (실행 중인 Pod에 디버그 컨테이너 추가)
# 기본 ephemeral container
kubectl debug <pod-name> -it --image=busybox --target=<container-name>
# 네트워크 디버깅 도구가 포함된 이미지
kubectl debug <pod-name> -it --image=nicolaka/netshoot --target=<container-name>
Pod Copy (Pod을 복제하여 디버깅)
# Pod을 복제하고 다른 이미지로 시작
kubectl debug <pod-name> --copy-to=debug-pod --image=ubuntu
# Pod 복제 시 커맨드 변경
kubectl debug <pod-name> --copy-to=debug-pod --container=<container-name> -- sh
Node Debugging (노드에 직접 접근)
# 노드 디버깅 (호스트 파일시스템은 /host에 마운트됨)
kubectl debug node/<node-name> -it --image=ubuntu
kubectl debug vs SSM
kubectl debug node/ 는 SSM Agent가 설치되지 않은 노드에서도 사용 가능합니다. 다만, 호스트 네트워크 네임스페이스에 접근하려면 --profile=sysadmin 옵션을 추가하세요.
배포는 됐는데 안 되는 패턴
Pattern 1: Probe 실패 루프 (Running but 0/1 Ready)
Pod은 Running 상태이지만 READY 컬럼이 0/1로 표시되어 트래픽을 받지 못하는 상황입니다.
# 증상 확인
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# api-server-xxx 0/1 Running 0 5m
# readinessProbe 실패 이벤트 확인
kubectl describe pod api-server-xxx | grep -A 10 "Readiness probe failed"
진단 플로우차트
일반적인 원인
| 원인 | 증상 | 해결 방법 |
|---|---|---|
| readinessProbe path ≠ 실제 endpoint | Probe가 404 Not Found 반환 | 앱의 실제 헬스체크 경로와 일치시키기 (/health, /healthz, /ready 등) |
| initialDelaySeconds < 앱 부팅 시간 | 앱이 준비되기 전에 Probe 시작 → 실패 | Spring Boot/JVM 앱 은 30초 이상 필요. initialDelaySeconds 증가 또는 startupProbe 사용 |
| startupProbe 미사용 | 느린 앱이 반복 재시작 | startupProbe를 추가하여 초기 시작 시간 확보 (최대 failureThreshold × periodSeconds) |
| 헬스체크에 외부 의존성 포함 | DB 장애 시 모든 Pod Ready=false | readinessProbe는 Pod 자체의 준비 상태만 확인 (DB 연결 제외) |
해결 예제
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-app
spec:
template:
spec:
containers:
- name: app
image: my-spring-app:latest
ports:
- containerPort: 8080
# 1. startupProbe: 앱 시작 완료 확인 (Spring Boot는 느림)
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30 # 최대 300초(30 × 10s) 대기
periodSeconds: 10
# 2. readinessProbe: 트래픽 수신 준비 확인
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# 3. livenessProbe: 데드락 감지 (외부 의존성 제외!)
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
Liveness Probe에 외부 의존성 포함 금지
Liveness Probe에서 DB/Redis 연결을 확인하면 안 됩니다. 외부 서비스 장애 시 모든 Pod이 재시작되는 cascading failure를 유발합니다. Liveness는 앱 자체의 데드락만 감지하세요.
Pattern 2: ConfigMap/Secret 변경 미반영
ConfigMap 또는 Secret을 업데이트했지만 Pod에 반영되지 않는 경우입니다.
동작 방식 비교
| 마운트 방식 | 자동 업데이트 | 반영 시간 | 비고 |
|---|---|---|---|
| volumeMount (일반) | ✅ 자동 업데이트 | 1-2분 (kubelet sync 주기) | 권장 방식 |
| volumeMount + subPath | ❌ 업데이트 안 됨 | N/A | Pod 재시작 필수 |
| envFrom / env | ❌ 업데이트 안 됨 | N/A | Pod 재시작 필수 |
# ConfigMap 업데이트 확인
kubectl get cm <configmap-name> -o yaml
# Pod이 마운트한 ConfigMap 버전 확인 (Pod 내부)
kubectl exec <pod-name> -- cat /etc/config/app.conf
# Pod 재시작 (변경사항 즉시 반영)
kubectl rollout restart deployment/<deployment-name>
subPath 사용 시 주의사항
# ❌ 나쁜 예: subPath 사용 → ConfigMap 업데이트가 반영되지 않음
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
volumeMounts:
- name: config
mountPath: /etc/app/config.yaml
subPath: config.yaml # ← 문제: 자동 업데이트 안 됨
volumes:
- name: config
configMap:
name: app-config
# ✅ 좋은 예: subPath 제거 → 자동 업데이트 가능
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
volumeMounts:
- name: config
mountPath: /etc/app # 디렉토리 전체 마운트
volumes:
- name: config
configMap:
name: app-config
Reloader를 사용한 자동 재시작
stakater/reloader를 사용하면 ConfigMap/Secret 변경 시 자동으로 Deployment를 재시작할 수 있습니다.
# Reloader 설치
kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
# Deployment에 annotation 추가
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
annotations:
reloader.stakater.com/auto: "true" # 모든 ConfigMap/Secret 감시
# 또는 특정 리소스만:
# configmap.reloader.stakater.com/reload: "app-config,common-config"
spec:
template:
spec:
containers:
- name: app
image: my-app:latest
Pattern 3: HPA 미작동
Horizontal Pod Autoscaler가 스케일링하지 않는 경우입니다.
# HPA 상태 확인
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# web-hpa Deployment/web <unknown>/50% 2 10 2
# HPA 상세 정보
kubectl describe hpa web-hpa
# metrics-server 동작 확인
kubectl get deployment metrics-server -n kube-system
kubectl top pods # 이 명령어가 실패하면 metrics-server 문제
HPA 미작동 원인 및 해결
| 증상 | 원인 | 해결 |
|---|---|---|
TARGETS가 <unknown> | metrics-server 미설치 또는 장애 | metrics-server 설치 및 상태 확인 |
unable to get metrics | Pod에서 메트릭 수집 실패 | Pod의 resource requests 설정 확인 (requests 없으면 CPU 사용률 계산 불가) |
current replicas above Deployment.spec.replicas | minReplicas > Deployment replicas | HPA minReplicas ≤ Deployment replicas |
| 스케일업 후 즉시 스케일다운 | stabilizationWindow 미설정 | behavior.scaleDown.stabilizationWindowSeconds 설정 (기본 300초) |
invalid metrics | 커스텀 메트릭 소스 오류 | Prometheus Adapter 설정 확인 |
올바른 HPA 설정 예제
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5분간 안정화 후 스케일다운
policies:
- type: Percent
value: 50 # 한 번에 최대 50%만 축소
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0 # 즉시 스케일업
policies:
- type: Percent
value: 100 # 한 번에 최대 100% 증가 (2배)
periodSeconds: 15
- type: Pods
value: 4 # 한 번에 최대 4개 추가
periodSeconds: 15
selectPolicy: Max # 두 정책 중 더 큰 값 선택
HPA를 위한 필수 조건
- metrics-server 설치 필수: EKS 클러스터에 기본 설치되어 있지 않습니다.
- Pod에 resource requests 설정 필수: CPU/메모리 사용률을 계산하려면 requests 값이 필요합니다.
- Deployment와 HPA minReplicas 일치: Deployment의 replicas ≥ HPA minReplicas