CrashLoopBackOff 란?
CrashLoopBackOff는 그 자체가 오류가 아니라 상태입니다. 컨테이너가 시작 → 종료(크래시) → 재시작을 반복하자, kubelet이 재시작 간격을 점점 늘려(back-off) 폭주를 막고 있다는 뜻입니다. 즉 "컨테이너가 자꾸 죽어서 잠시 쉬었다가 다시 시도 중"인 상태입니다.
- 재시작 간격은 10s → 20s → 40s … 로 두 배씩 증가, 최대 5분
- 원인은 컨테이너 안에 있으므로, 핵심은 왜 죽었는지를 찾는 것
restartPolicy가Always(기본)/OnFailure일 때 발생
CrashLoopBackOff는 원인 그 자체가 아니라 "증상의 묶음"입니다. 종료 코드와 로그를 보지 않고 매니페스트만 수정하면 헛수고하기 쉽습니다. 항상 종료 코드 → 로그 → 이벤트 순으로 좁혀가세요.
1단계: 전체 상태 파악
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# myapp-xxx 0/1 CrashLoopBackOff 5 3m
kubectl describe pod myapp-xxxdescribe 출력에서 다음 두 곳을 먼저 봅니다.
Last State: Terminated
Reason: Error
Exit Code: 1 ← 핵심 단서
Events:
Warning BackOff ... Back-off restarting failed container2단계: 종료 코드(Exit Code) 해석
종료 코드는 원인을 빠르게 좁혀줍니다.
| Exit Code | 의미 | 흔한 원인 |
|---|---|---|
| 0 | 정상 종료 | 메인 프로세스가 할 일 끝내고 종료(데몬이 아님) |
| 1 | 일반 애플리케이션 오류 | 코드 예외, 설정 누락, 의존 서비스 미연결 |
| 2 | 셸 사용법/명령 오류 | command/args 오타 |
| 126 | 실행 불가 | 권한 없음, 바이너리 아님 |
| 127 | 명령 없음 | command 경로 오타, 패키지 미설치 |
| 137 | SIGKILL(128+9) | OOMKilled 또는 강제 종료 |
| 139 | SIGSEGV(128+11) | 세그폴트(네이티브 크래시) |
| 143 | SIGTERM(128+15) | 종료 신호 정상 수신 |
3단계: 로그 확인 — 가장 중요한 단서
현재 컨테이너가 아니라 직전에 죽은 컨테이너의 로그를 봐야 합니다.
kubectl logs myapp-xxx # 현재(또는 마지막) 인스턴스
kubectl logs myapp-xxx --previous # 이전에 크래시한 인스턴스 ← 핵심
kubectl logs myapp-xxx -c sidecar # 멀티 컨테이너 시 특정 컨테이너재시작이 빠르면 로그를 잡기 전에 컨테이너가 사라집니다. --previous로 직전 인스턴스 로그를 봐야 진짜 원인이 보입니다.
원인별 해결
A. 애플리케이션 시작 실패 (Exit 1)
설정/환경변수 누락, DB 연결 실패가 대부분입니다.
kubectl logs myapp-xxx --previous
# 예: "ECONNREFUSED postgres:5432" → DB가 아직 안 떴거나 Service명 오타- 환경변수/ConfigMap/Secret이 제대로 주입됐는지 확인
- 의존 서비스 기동 순서 문제라면
initContainers로 대기
initContainers:
- name: wait-db
image: busybox:1.36
command: ['sh','-c','until nc -z postgres 5432; do echo waiting; sleep 2; done']B. OOMKilled (Exit 137)
메모리 limit 초과로 커널이 컨테이너를 죽인 경우입니다.
kubectl describe pod myapp-xxx | grep -A3 'Last State'
# Reason: OOMKilled해결: limit 상향 또는 앱 메모리 사용 점검.
resources:
requests: { memory: 256Mi }
limits: { memory: 512Mi } # 실제 사용량 + 여유JVM·Node 등은 limit과 무관하게 호스트 메모리를 보고 힙을 잡으려다 OOM이 납니다. -XX:MaxRAMPercentage 또는 --max-old-space-size로 컨테이너 limit에 맞춰 제한하세요.
C. 잘못된 command/args (Exit 127/126)
kubectl logs myapp-xxx --previous
# "exec: \"node\": executable file not found" → 이미지에 없는 명령이미지의 ENTRYPOINT를 덮어쓸 때 경로/철자를 확인하고, 디버깅용으로 직접 셸을 띄워봅니다.
kubectl run debug --rm -it --image=myapp:1.0 --command -- /bin/shD. 라이브니스 프로브 실패
앱은 멀쩡한데 livenessProbe가 너무 빡빡해 kubelet이 계속 죽이는 경우입니다. 이때는 종료 코드가 137/143이고 로그에는 에러가 없습니다.
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
initialDelaySeconds: 30 # 부팅 느린 앱은 충분히
periodSeconds: 10
failureThreshold: 3
# 부팅이 매우 느리면 startupProbe로 분리
startupProbe:
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 30
periodSeconds: 5| 단서 | 가능성 높은 원인 |
|---|---|
| 로그에 앱 에러 + Exit 1 | 설정/의존성 문제 (A) |
| Reason: OOMKilled, Exit 137 | 메모리 부족 (B) |
| "not found" + Exit 127 | command/이미지 문제 (C) |
| 로그 깨끗 + 주기적 137/143 | 프로브 오설정 (D) |
E. 설정 리소스 누락 (CreateContainerConfigError)
엄밀히는 CrashLoop 직전 단계지만 함께 자주 만납니다.
kubectl describe pod myapp-xxx
# Warning Failed ... configmap "app-config" not found참조하는 ConfigMap/Secret/key가 같은 네임스페이스에 있는지 확인합니다.
실시간 디버깅 기법
# 이벤트를 시간순으로 — 클러스터 차원 원인(스케줄링/이미지풀) 파악
kubectl get events --sort-by=.lastTimestamp
# 임시로 죽지 않게 만들어 안에서 진단 (command를 sleep로 덮어쓰기)
kubectl run probe --rm -it --image=myapp:1.0 \
--command -- sleep 3600
kubectl exec -it probe -- sh
# 기존 Pod에 디버그 컨테이너 주입(이미지 변경 없이)
kubectl debug -it myapp-xxx --image=busybox:1.36 --target=myapp운영 중인 Deployment를 임시 검사할 때 kubectl edit로 command를 sleep로 바꾸면 크래시 루프가 멈춰 안에서 천천히 조사할 수 있습니다. 조사 후 원복을 잊지 마세요.
정리
| 단계 | 명령 | 얻는 것 |
|---|---|---|
| 상태 | kubectl get/describe pod | STATUS, Exit Code, 이벤트 |
| 종료 코드 | describe의 Last State | 원인 카테고리 추정 |
| 로그 | kubectl logs --previous | 진짜 크래시 원인 |
| 이벤트 | kubectl get events | 스케줄링/이미지/설정 문제 |
| 진단 | kubectl run/exec/debug | 컨테이너 내부 직접 확인 |
| 종료 코드 | 1순위 해결 |
|---|---|
| 1 | 로그 확인 → 설정/의존성 |
| 137 | 메모리 limit 상향 (OOMKilled) |
| 127/126 | command/이미지 점검 |
| 137/143 + 로그 정상 | 프로브 완화/ startupProbe |
CrashLoopBackOff는 "다시 시도 중"이라는 상태일 뿐, 원인은 항상 컨테이너 안에 있습니다. 종료 코드 → --previous 로그 → 이벤트 순서로 좁히면 거의 모든 케이스를 체계적으로 해결할 수 있습니다.
이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.
질문 & 답변 (Q&A)
이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.