Theme:

Pod이 계속 빨간색으로 표시되는데 로그에는 아무것도 없고, describe를 봐도 뭐가 문제인지 모르겠다면 어디서부터 봐야 할까요?

Kubernetes를 운영하다 보면 다양한 에러를 만나게 됩니다. 중요한 건 에러 메시지를 보고 "이건 이런 원인이구나"를 빠르게 판단하는 것입니다. 자주 발생하는 에러별로 원인과 해결 방법을 체계적으로 정리합니다.

트러블슈팅 기본 흐름

어떤 에러든 다음 순서로 접근하면 대부분 원인을 찾을 수 있습니다.

SHELL
# 1단계: 상태 확인
kubectl get pods -o wide

# 2단계: 상세 정보와 이벤트 확인
kubectl describe pod <pod-name>

# 3단계: 로그 확인
kubectl logs <pod-name>
kubectl logs <pod-name> --previous    # 크래시된 이전 컨테이너 로그

# 4단계: 클러스터 이벤트 확인
kubectl get events --sort-by='.lastTimestamp'

# 5단계: 노드 상태 확인
kubectl describe node <node-name>

CrashLoopBackOff

증상: Pod이 Running → Error → CrashLoopBackOff를 반복

SHELL
kubectl get pods
# NAME      READY   STATUS             RESTARTS   AGE
# my-app    0/1     CrashLoopBackOff   5          3m

원인 및 해결

원인확인 방법해결
애플리케이션 에러kubectl logs코드/설정 수정
잘못된 command/argskubectl describe실행 명령어 확인
설정 파일 누락kubectl logsConfigMap/Secret 확인
DB 연결 실패kubectl logs네트워크/인증 정보 확인
OOMKilledkubectl describe → Last State메모리 limits 증가
livenessProbe 실패kubectl describe → EventsProbe 설정 조정
SHELL
# 상세 디버깅
kubectl describe pod my-app | grep -A 10 "Last State"
# Last State:     Terminated
#   Reason:       Error
#   Exit Code:    1

kubectl logs my-app --previous
# Error: Cannot connect to database at mysql:3306

Exit Code 해석

Exit Code의미흔한 원인
0정상 종료잘못된 restartPolicy
1일반 에러애플리케이션 예외
126실행 권한 없음chmod 필요
127명령어를 찾을 수 없음잘못된 command
137SIGKILL (128+9)OOMKill 또는 외부 kill
143SIGTERM (128+15)정상 종료 요청

ImagePullBackOff

증상: 이미지를 가져올 수 없음

SHELL
kubectl get pods
# NAME      READY   STATUS             RESTARTS   AGE
# my-app    0/1     ImagePullBackOff   0          2m

원인 및 해결

SHELL
kubectl describe pod my-app | grep -A 5 Events
# Failed to pull image "my-app:latest": rpc error: ...
원인해결
이미지 이름/태그 오타이미지 이름 확인, latest 대신 구체적 태그
프라이빗 레지스트리 인증 실패imagePullSecrets 설정
이미지가 존재하지 않음레지스트리에서 이미지 확인
네트워크 문제노드에서 레지스트리 접근 확인
YAML
# imagePullSecrets 설정
spec:
  imagePullSecrets:
    - name: registry-secret
SHELL
# 레지스트리 Secret 생성
kubectl create secret docker-registry registry-secret \
  --docker-server=myregistry.io \
  --docker-username=user \
  --docker-password=pass

OOMKilled

증상: 메모리 초과로 컨테이너가 강제 종료

SHELL
kubectl describe pod my-app
# Last State:     Terminated
#   Reason:       OOMKilled
#   Exit Code:    137

해결

YAML
# 메모리 limits 증가
resources:
  requests:
    memory: 512Mi
  limits:
    memory: 1Gi    # 애플리케이션 실제 사용량에 맞게 조정
SHELL
# 실제 메모리 사용량 확인
kubectl top pod my-app
# NAME      CPU(cores)   MEMORY(bytes)
# my-app    100m         480Mi          # limits(512Mi)에 근접!

Java 애플리케이션이라면 JVM 힙 설정도 확인하세요.

YAML
env:
  - name: JAVA_OPTS
    value: "-Xmx768m -Xms256m"  # limits보다 작아야 함

Pending

증상: Pod이 스케줄링되지 못하고 대기 중

SHELL
kubectl get pods
# NAME      READY   STATUS    RESTARTS   AGE
# my-app    0/1     Pending   0          5m

원인 진단

SHELL
kubectl describe pod my-app | grep -A 10 Events
메시지원인해결
Insufficient cpu/memory노드 리소스 부족노드 추가 또는 requests 줄이기
didn't match selectornodeSelector 불일치노드 레이블 확인
had taintsTaint 미허용Toleration 추가
pod has unbound PVCPVC가 바인딩되지 않음PV/StorageClass 확인
didn't find available PV적합한 PV 없음PV 생성 또는 StorageClass 확인
SHELL
# 노드 리소스 상황 확인
kubectl describe nodes | grep -A 5 "Allocated resources"

CreateContainerConfigError

증상: 컨테이너 설정 오류로 시작 불가

SHELL
kubectl get pods
# NAME      READY   STATUS                       RESTARTS   AGE
# my-app    0/1     CreateContainerConfigError    0          1m

주로 ConfigMap이나 Secret이 존재하지 않을 때 발생합니다.

SHELL
# 원인 확인
kubectl describe pod my-app
# Warning  Failed  ... Error: configmap "app-config" not found

# 해결
kubectl get configmap app-config
kubectl get secret db-credentials

Evicted

증상: 노드 리소스 부족으로 Pod이 퇴출됨

SHELL
kubectl get pods
# NAME        READY   STATUS    RESTARTS   AGE
# my-app-1    0/1     Evicted   0          30m
SHELL
# 원인 확인
kubectl describe pod my-app-1
# Status: Failed
# Reason: Evicted
# Message: The node was low on resource: memory

# Evicted Pod 정리
kubectl get pods --field-selector=status.phase=Failed -o name | xargs kubectl delete

노드의 디스크나 메모리가 부족하면 kubelet이 Pod을 퇴출합니다. ResourceQuota와 LimitRange를 설정하여 예방하세요.

네트워크 관련 문제

Service에 접근 불가

SHELL
# 1. Endpoints 확인
kubectl get endpoints my-service
# ENDPOINTS가 비어있으면 레이블 매칭 실패

# 2. 레이블 확인
kubectl get pods --show-labels
kubectl get svc my-service -o yaml | grep selector

# 3. Pod 내부에서 DNS 확인
kubectl exec my-pod -- nslookup my-service

# 4. Pod 내부에서 연결 테스트
kubectl exec my-pod -- curl -v http://my-service:8080

DNS 문제

SHELL
# CoreDNS 상태 확인
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns

# DNS 테스트
kubectl run dnstest --image=busybox:1.36 --rm -it -- nslookup kubernetes.default

kubectl debug — 고급 디버깅

Kubernetes 1.25+에서 사용 가능한 강력한 디버깅 도구입니다.

SHELL
# 실행 중인 Pod에 디버깅 컨테이너 추가
kubectl debug my-pod -it --image=busybox:1.36

# Pod 복사본을 만들어 디버깅 (원본에 영향 없음)
kubectl debug my-pod -it --image=busybox:1.36 --copy-to=debug-pod

# 노드 디버깅 (노드의 파일시스템에 접근)
kubectl debug node/node-1 -it --image=busybox:1.36

디버깅용 도구 이미지

SHELL
# 네트워크 도구가 포함된 이미지
kubectl run netshoot --rm -it --image=nicolaka/netshoot -- bash

# 안에서 사용 가능한 도구들:
# curl, wget, nslookup, dig, ping, traceroute,
# tcpdump, iptables, ss, ip, netstat 등

자주 사용하는 디버깅 명령어 모음

SHELL
# Pod 전체 상태 (넓은 출력)
kubectl get pods -o wide --all-namespaces

# 특정 상태의 Pod만 필터
kubectl get pods --field-selector=status.phase!=Running

# 리소스 사용량 상위 Pod
kubectl top pods --sort-by=memory

# 이벤트 (시간순)
kubectl get events --sort-by='.lastTimestamp' -n production

# Pod의 YAML 출력 (현재 상태 포함)
kubectl get pod my-pod -o yaml

# 강제 삭제 (stuck Pod)
kubectl delete pod my-pod --force --grace-period=0

체계적인 디버깅 체크리스트

PLAINTEXT
1. kubectl get pods -o wide          → 어떤 상태인가?
2. kubectl describe pod <name>       → 이벤트에 원인이 있는가?
3. kubectl logs <name> [--previous]  → 애플리케이션 에러가 있는가?
4. kubectl get events                → 클러스터 수준 문제인가?
5. kubectl describe node <name>      → 노드에 문제가 있는가?
6. kubectl debug <name>              → 컨테이너 내부를 조사해야 하는가?

정리

Kubernetes 트러블슈팅의 핵심은 describelogsevents 순서로 원인을 좁혀가는 것입니다. CrashLoopBackOff는 애플리케이션 에러나 OOMKill, Pending은 스케줄링 실패, ImagePullBackOff는 이미지 접근 문제가 대부분입니다. Exit Code를 해석하고, kubectl debug로 컨테이너 내부를 조사하는 방법까지 알아두면 대부분의 문제를 체계적으로 해결할 수 있습니다.

댓글 로딩 중...