Kubernetes Pod 'CrashLoopBackOff' 원인 분석 및 해결 가이드
🎯 타겟 독자: kubectl 명령어가 익숙지 않은 백엔드 개발자, 배포 직후 파드(Pod)가 빨간불로 켜졌다 꺼지기를 반복하는 상황에 처한 데브옵스 입문자.
📝 요약: CrashLoopBackOff는 쿠버네티스에서 가장 흔하지만 가장 당혹스러운 에러 상태입니다. 컨테이너가 시작되자마자 죽고, K8s가 이를 살리려다 다시 죽는 루프에 빠진 것입니다. 이 글에서는 로그 확인(Logs), 상태 상세 조회(Describe), 프로브(Probe) 설정을 통해 원인을 핀포인트로 찾아내는 3단계 디버깅 기법을 다룹니다.
1. 상황 파악: "파드가 자꾸 죽었다 살아나요"
배포 스크립트를 실행하고 kubectl get pods를 쳤는데, STATUS 컬럼이 Running이 아니라 CrashLoopBackOff 또는 Error로 바뀌며 RESTARTS 횟수가 계속 올라가는 상황입니다.
이는 컨테이너 내부의 애플리케이션이 '실행 직후 비정상 종료(Exit Code 1, 137 등)'되었음을 의미합니다. 쿠버네티스는 이를 감지하고 재시작 정책(Restart Policy)에 따라 살려내지만, 원인이 해결되지 않았기에 다시 죽는 과정이 반복되는 것입니다.
2. 디버깅 1단계: 죽기 직전의 유언(Logs) 확인
가장 먼저 해야 할 일은 애플리케이션이 죽으면서 남긴 표준 출력(Standard Output) 로그를 확인하는 것입니다.
특히 --previous 옵션이 중요합니다. 현재 컨테이너는 막 재시작되어 로그가 없을 수 있지만, 방금 죽은 녀석은 "DB 연결 실패"나 "환경 변수 누락" 같은 결정적인 단서를 남겼을 확률이 높습니다.
3. 디버깅 2단계: 쿠버네티스의 시선(Describe) 확인
애플리케이션 로그에 아무것도 없다면, 쿠버네티스 레벨의 문제일 수 있습니다. 파드의 상세 명세와 이벤트를 확인합니다.
출력 결과의 맨 아래 Events 섹션과 중간의 State 섹션을 주목하세요.
- OOMKilled (Exit Code 137): 메모리 부족으로 강제 종료됨.
👉 해결: resources.limits.memory를 늘리거나 메모리 누수를 잡으세요. - Liveness probe failed: 헬스 체크 실패로 K8s가 스스로 파드를 죽임.
👉 해결: 초기 구동 시간이 길다면 `initialDelaySeconds`를 늘리세요. - Back-off restarting failed container: 반복적인 재시작 시도 중.
4. 주요 원인 BEST 3 및 해결책
| 원인 | 증상 | 해결법 |
|---|---|---|
| 설정 오류 | 로그에 'ConfigMap not found' 또는 'Panic' 발생 | 환경변수/ConfigMap 마운트 경로 확인 |
| 즉시 종료됨 | CMD/ENTRYPOINT가 백그라운드 프로세스가 아님 | 포그라운드 실행 유지 (`nginx -g 'daemon off;'` 등) |
| 리소스 부족 | Status: OOMKilled (Code 137) | `resources` 요청/제한 값 증설 |
💡 꿀팁: 디버깅용으로 강제 실행하기
원인을 도저히 모르겠다면, 파드를 일단 살려놓고 내부에 접속해서 직접 실행해 보는 방법이 있습니다.
이렇게 설정하고 배포하면 파드가 Running 상태를 유지합니다. 이때 kubectl exec -it my-pod -- /bin/sh로 접속하여 원래 실행 명령어를 수동으로 입력해보면 에러 원인을 실시간으로 볼 수 있습니다.
5. 결론
CrashLoopBackOff는 "나 좀 봐줘, 설정이 틀렸거나 아파서 못 뜨겠어"라는 컨테이너의 비명입니다. 당황하지 말고 로그(Logs) -> 상세 상태(Describe) -> 리소스(Resource) 순으로 접근하면 99% 해결할 수 있습니다.