Kubernetes Pod 트러블슈팅 완벽 가이드 | CrashLoopBackOff·ImagePullBackOff 해결

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 명령어로 진단하는 방법을 익힙니다
  • 실무 체크리스트를 활용할 수 있습니다
  • 자주 발생하는 에러를 빠르게 해결합니다

목차

  1. Pod 상태 이해
  2. 진단 도구
  3. CrashLoopBackOff 해결
  4. ImagePullBackOff 해결
  5. Pending 상태 해결
  6. 실무 체크리스트
  7. 트러블슈팅 패턴
  8. 마무리

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 해결

원인

  1. 애플리케이션 에러 (가장 흔함)
  2. 설정 오류 (환경 변수, ConfigMap)
  3. 의존성 누락 (데이터베이스 연결 실패)
  4. 리소스 부족 (메모리 OOM)
  5. 헬스체크 실패 (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. 이미지가 존재하지 않음
  2. 이미지 태그 오류
  3. 레지스트리 인증 실패
  4. 네트워크 문제
  5. 레지스트리 다운

진단 순서

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 상태 해결

원인

  1. 리소스 부족 (CPU/메모리)
  2. PVC 바인딩 실패
  3. 노드 선택 실패 (nodeSelector, affinity)
  4. 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 트러블슈팅체계적인 진단 순서를 따르면 빠르게 해결할 수 있습니다.

핵심 원칙:

  1. Pod 상태 확인 (kubectl get pods)
  2. 로그 확인 (kubectl logs)
  3. 상세 정보 확인 (kubectl describe pod)
  4. 이벤트 확인 (kubectl get events)
  5. 리소스 확인 (kubectl top)

자주 발생하는 에러:

  • CrashLoopBackOff: 애플리케이션 로그 확인
  • ImagePullBackOff: 이미지 이름, 인증 확인
  • Pending: 리소스, PVC, 노드 확인

예방 방법:

  • 헬스체크 설정 (liveness/readiness probe)
  • 리소스 제한 설정 (requests/limits)
  • 로깅 및 모니터링 (Prometheus, Grafana)
  • 테스트 환경에서 충분히 검증

Docker 최적화는 Docker 멀티스테이지 빌드와 함께 보시면 도움이 됩니다.