kubectl get pods를 쳤을 때 STATUS에 CrashLoopBackOff가 떠 있다면, 쿠버네티스가 컨테이너를 띄웠지만 곧바로 죽어서 점점 더 긴 간격(back-off)으로 재시작을 반복하고 있다는 뜻입니다. 즉 **CrashLoopBackOff는 에러가 아니라 "결과 상태"**입니다. 원인은 따로 있고, 우리가 할 일은 "컨테이너가 왜 죽는지"를 찾는 것입니다.
1단계 — 죽은 이유를 직접 본다
추측하지 말고 두 곳을 봅니다.
# 직전(죽은 그) 컨테이너의 로그
kubectl logs <pod> --previous
# Pod 이벤트·종료 코드·상태
kubectl describe pod <pod>
describe 출력의 Last State: Terminated와 Exit Code가 가장 중요한 단서입니다.
2단계 — Exit Code로 원인 좁히기
| Exit Code | 흔한 의미 | 어디를 보나 |
|---|---|---|
| 0 | 정상 종료인데 재시작 | 장기 실행 프로세스가 아님(스크립트가 끝나버림) |
| 1 | 애플리케이션 예외 | logs --previous의 스택트레이스 |
| 137 | OOM 또는 SIGKILL | 메모리 limit 초과 → describe의 OOMKilled |
| 139 | 세그폴트 | 네이티브 의존성·아키텍처 불일치 |
| 143 | SIGTERM | 헬스체크 실패로 강제 종료 |
원인 5가지와 해결
① 앱이 시작하자마자 예외로 죽음 (Exit 1) — 환경변수·시크릿 누락, DB 접속 실패가 대부분. logs --previous의 첫 예외를 확인하고 kubectl get secret/configmap으로 주입 여부를 점검합니다.
② 메모리 초과 (Exit 137, OOMKilled) — resources.limits.memory가 실제 사용량보다 낮을 때. limit을 올리거나 앱 메모리를 줄입니다. describe에 Reason: OOMKilled가 명시됩니다.
③ 라이브니스 프로브 실패 (Exit 143) — 앱은 멀쩡한데 livenessProbe가 너무 빨리·엄격하게 검사해 죽이는 경우. initialDelaySeconds를 앱 기동 시간보다 길게 잡습니다.
④ 프로세스가 그냥 끝남 (Exit 0) — 컨테이너 CMD가 일회성 명령이라 끝나버리는 경우. 포그라운드로 상주하는 프로세스로 바꿉니다.
⑤ 잘못된 명령·이미지 (Exit 127/139) — command/args 오타, 또는 arm64 이미지를 amd64 노드에서 실행하는 아키텍처 불일치. 이미지 태그와 플랫폼을 확인합니다.
30초 체크리스트
kubectl describe pod <pod> # Exit code·OOM·이벤트
kubectl logs <pod> --previous # 죽기 직전 로그
kubectl get events --sort-by=.lastTimestamp
이 3개면 위 5원인 대부분이 좁혀집니다.
CrashLoopBackOff를 일부러 만들어 보고 로그로 원인을 좁히는 실습은 쿠버네티스 트랙에서 직접 해볼 수 있습니다 — 회원가입 없이 무료로.