Kubernetes Pod 트러블슈팅 완벽 가이드 | CrashLoopBackOff·ImagePullBackOff 해결
이 글의 핵심
Kubernetes Pod 트러블슈팅 완벽 가이드. CrashLoopBackOff, ImagePullBackOff, Pending 상태를 kubectl logs, describe, events로 진단. 실무 체크리스트와 해결 패턴.
들어가며
Kubernetes Pod 트러블슈팅은 실무에서 가장 자주 마주치는 작업입니다. Pod가 CrashLoopBackOff, ImagePullBackOff, Pending 상태에 빠지면 서비스가 중단되므로 빠른 진단과 해결이 필요합니다.
비유로 말씀드리면, Pod 트러블슈팅은 자동차 고장 진단과 비슷합니다. 시동이 안 걸리면(CrashLoopBackOff), 연료가 없는지(ImagePullBackOff), 주차 공간이 없는지(Pending) 체크리스트를 따라 확인합니다.
이 글을 읽으면
- Pod 상태별 원인과 해결 방법을 파악합니다
- kubectl 명령어로 진단하는 방법을 익힙니다
- 실무 체크리스트를 활용할 수 있습니다
- 자주 발생하는 에러를 빠르게 해결합니다
목차
Pod 상태 이해
Pod 라이프사이클
| 상태 | 의미 | 원인 |
|---|---|---|
| Pending | 스케줄링 대기 | 리소스 부족, PVC 바인딩 실패 |
| Running | 실행 중 | 정상 |
| Succeeded | 완료 (Job) | 정상 종료 |
| Failed | 실패 | 비정상 종료 |
| Unknown | 상태 불명 | 노드 통신 실패 |
| CrashLoopBackOff | 반복 크래시 | 애플리케이션 에러 |
| ImagePullBackOff | 이미지 가져오기 실패 | 이미지 없음, 인증 실패 |
Pod 상태 확인
kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-5d4b7c8f9-abc12 1/1 Running 0 5m
myapp-5d4b7c8f9-def34 0/1 CrashLoopBackOff 5 3m
myapp-5d4b7c8f9-ghi56 0/1 ImagePullBackOff 0 2m
myapp-5d4b7c8f9-jkl78 0/1 Pending 0 1m
진단 도구
kubectl logs
기본 사용법:
# 현재 로그
kubectl logs <pod-name>
# 이전 컨테이너 로그 (재시작된 경우)
kubectl logs <pod-name> --previous
# 실시간 로그 (tail -f)
kubectl logs <pod-name> -f
# 특정 컨테이너 로그 (멀티 컨테이너 Pod)
kubectl logs <pod-name> -c <container-name>
# 최근 100줄
kubectl logs <pod-name> --tail=100
kubectl describe
상세 정보 확인:
kubectl describe pod <pod-name>
중요 섹션:
- Events: 최근 발생한 이벤트 (가장 중요!)
- Containers: 컨테이너 상태, 재시작 횟수
- Conditions: Pod 조건 (Ready, Initialized 등)
- Volumes: 볼륨 마운트 상태
kubectl get events
클러스터 이벤트 확인:
# 모든 이벤트
kubectl get events --sort-by=.metadata.creationTimestamp
# 특정 네임스페이스
kubectl get events -n <namespace>
# 특정 Pod 이벤트만
kubectl get events --field-selector involvedObject.name=<pod-name>
CrashLoopBackOff 해결
원인
- 애플리케이션 에러 (가장 흔함)
- 설정 오류 (환경 변수, ConfigMap)
- 의존성 누락 (데이터베이스 연결 실패)
- 리소스 부족 (메모리 OOM)
- 헬스체크 실패 (liveness probe)
진단 순서
1단계: 로그 확인
kubectl logs <pod-name>
kubectl logs <pod-name> --previous
2단계: 상세 정보 확인
kubectl describe pod <pod-name>
Events 섹션 확인:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m default-scheduler Successfully assigned default/myapp-abc to node1
Normal Pulled 2m kubelet Successfully pulled image
Normal Created 2m kubelet Created container
Normal Started 2m kubelet Started container
Warning BackOff 1m (x5 over 2m) kubelet Back-off restarting failed container
해결 패턴
패턴 1: 애플리케이션 에러
# 로그에서 에러 확인
kubectl logs myapp-abc | grep -i error
# 예시 에러
Error: Cannot connect to database
해결:
# deployment.yaml
env:
- name: DATABASE_URL
value: "postgresql://user:pass@db:5432/mydb"
패턴 2: 환경 변수 누락
# 로그 확인
kubectl logs myapp-abc
# Error: Environment variable API_KEY is not set
해결:
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: api-secret
key: api-key
패턴 3: 메모리 OOM
# describe에서 확인
kubectl describe pod myapp-abc
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
해결:
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi"
패턴 4: Liveness Probe 실패
kubectl describe pod myapp-abc
Liveness probe failed: HTTP probe failed with statuscode: 500
해결:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30 # 시작 대기 시간 증가
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
ImagePullBackOff 해결
원인
- 이미지가 존재하지 않음
- 이미지 태그 오류
- 레지스트리 인증 실패
- 네트워크 문제
- 레지스트리 다운
진단 순서
1단계: 이미지 이름 확인
kubectl describe pod <pod-name>
Events:
Type Reason Message
---- ------ -------
Normal Pulling pulling image "myregistry.com/myapp:v1.0.0"
Warning Failed Failed to pull image "myregistry.com/myapp:v1.0.0": rpc error: code = NotFound
Warning Failed Error: ErrImagePull
2단계: 이미지 존재 확인
# Docker Hub
docker pull myapp:v1.0.0
# 프라이빗 레지스트리
docker pull myregistry.com/myapp:v1.0.0
해결 패턴
패턴 1: 이미지 태그 오류
# 잘못된 예
image: myapp:v1.0.0 # 태그가 존재하지 않음
# 올바른 예
image: myapp:latest
패턴 2: 레지스트리 인증
Secret 생성:
kubectl create secret docker-registry regcred \
--docker-server=myregistry.com \
--docker-username=myuser \
--docker-password=mypassword \
[email protected]
Deployment에 적용:
spec:
imagePullSecrets:
- name: regcred
containers:
- name: myapp
image: myregistry.com/myapp:v1.0.0
패턴 3: 이미지 정책
# 항상 최신 이미지 가져오기
imagePullPolicy: Always
# 로컬에 없을 때만 가져오기
imagePullPolicy: IfNotPresent
# 로컬 이미지만 사용
imagePullPolicy: Never
Pending 상태 해결
원인
- 리소스 부족 (CPU/메모리)
- PVC 바인딩 실패
- 노드 선택 실패 (nodeSelector, affinity)
- Taint/Toleration 불일치
진단 순서
1단계: Events 확인
kubectl describe pod <pod-name>
Events:
Type Reason Message
---- ------ -------
Warning FailedScheduling 0/3 nodes are available: insufficient cpu
해결 패턴
패턴 1: 리소스 부족
# 노드 리소스 확인
kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node1 1950m 97% 7500Mi 93%
node2 1900m 95% 7200Mi 90%
해결:
- 리소스 요청 줄이기
- 노드 추가
- 불필요한 Pod 삭제
resources:
requests:
cpu: "100m" # 1000m → 100m
memory: "128Mi" # 512Mi → 128Mi
패턴 2: PVC 바인딩 실패
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES
myapp-pvc Pending - - -
kubectl describe pvc myapp-pvc
Events:
Type Reason Message
---- ------ -------
Warning ProvisioningFailed storageclass "fast" not found
해결:
# 올바른 StorageClass 사용
storageClassName: standard # 또는 gp2, ebs-sc 등
패턴 3: 노드 선택 실패
kubectl describe pod <pod-name>
Events:
Warning FailedScheduling 0/3 nodes are available: node(s) didn't match node selector
해결:
# nodeSelector 제거 또는 수정
nodeSelector:
disktype: ssd # 이 레이블을 가진 노드가 없음
실무 체크리스트
빠른 진단 체크리스트
# 1. Pod 상태 확인
kubectl get pods
# 2. 로그 확인
kubectl logs <pod-name>
kubectl logs <pod-name> --previous
# 3. 상세 정보 확인
kubectl describe pod <pod-name>
# 4. 이벤트 확인
kubectl get events --sort-by=.metadata.creationTimestamp
# 5. 리소스 확인
kubectl top nodes
kubectl top pods
CrashLoopBackOff 체크리스트
- 애플리케이션 로그 확인 (
kubectl logs) - 환경 변수 확인 (ConfigMap, Secret)
- 의존성 확인 (데이터베이스, Redis 등)
- 헬스체크 설정 확인 (liveness/readiness probe)
- 리소스 제한 확인 (메모리 OOM)
- 컨테이너 명령 확인 (CMD, ENTRYPOINT)
ImagePullBackOff 체크리스트
- 이미지 이름 확인 (오타, 대소문자)
- 이미지 태그 확인 (존재 여부)
- 레지스트리 주소 확인
- 인증 정보 확인 (imagePullSecrets)
- 네트워크 확인 (레지스트리 접근 가능)
- 이미지 정책 확인 (imagePullPolicy)
Pending 체크리스트
- 노드 리소스 확인 (
kubectl top nodes) - PVC 바인딩 확인 (
kubectl get pvc) - nodeSelector 확인
- Taint/Toleration 확인
- Affinity 규칙 확인
- 노드 상태 확인 (
kubectl get nodes)
트러블슈팅 패턴
패턴 1: 데이터베이스 연결 실패
증상:
kubectl logs myapp-abc
Error: connect ECONNREFUSED 10.0.0.1:5432
원인:
- 데이터베이스 Service가 없음
- 환경 변수 오류
- 네트워크 정책
해결:
# Service 확인
kubectl get svc
# 환경 변수 확인
kubectl exec myapp-abc -- env | grep DATABASE
# 올바른 설정
env:
- name: DATABASE_URL
value: "postgresql://postgres:5432/mydb"
패턴 2: ConfigMap/Secret 누락
증상:
kubectl describe pod myapp-abc
Warning Failed Error: configmap "app-config" not found
해결:
# ConfigMap 생성
kubectl create configmap app-config \
--from-literal=API_URL=https://api.example.com
# Secret 생성
kubectl create secret generic app-secret \
--from-literal=API_KEY=your-api-key
패턴 3: 권한 문제
증상:
kubectl logs myapp-abc
Error: EACCES: permission denied, open '/app/data/file.txt'
해결:
# SecurityContext 설정
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
패턴 4: 헬스체크 타임아웃
증상:
kubectl describe pod myapp-abc
Liveness probe failed: Get "http://10.0.0.1:8080/health": context deadline exceeded
해결:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 60 # 시작 대기 시간 증가
periodSeconds: 10
timeoutSeconds: 5 # 타임아웃 증가
failureThreshold: 3
마무리
Kubernetes Pod 트러블슈팅은 체계적인 진단 순서를 따르면 빠르게 해결할 수 있습니다.
핵심 원칙:
- Pod 상태 확인 (
kubectl get pods) - 로그 확인 (
kubectl logs) - 상세 정보 확인 (
kubectl describe pod) - 이벤트 확인 (
kubectl get events) - 리소스 확인 (
kubectl top)
자주 발생하는 에러:
- CrashLoopBackOff: 애플리케이션 로그 확인
- ImagePullBackOff: 이미지 이름, 인증 확인
- Pending: 리소스, PVC, 노드 확인
예방 방법:
- 헬스체크 설정 (liveness/readiness probe)
- 리소스 제한 설정 (requests/limits)
- 로깅 및 모니터링 (Prometheus, Grafana)
- 테스트 환경에서 충분히 검증
Docker 최적화는 Docker 멀티스테이지 빌드와 함께 보시면 도움이 됩니다.