CrashLoopBackOff, “왜 계속 죽었다가 살아날까?” 빠르게 원인 좁히는 실전 요약

도입부: Kubernetes에서 CrashLoopBackOff는 자주 만나지만, 막상 대응할 땐 어디부터 봐야 할지 헷갈리기 쉽습니다. 이 글에서는 CrashLoopBackOff의 의미와 대표 원인, 그리고 가장 빨리 근본 원인을 좁히는 점검 순서를 체크리스트 형태로 정리합니다.

CrashLoopBackOff란 무엇인가요?

CrashLoopBackOff는 컨테이너가 시작 → 크래시 → 재시작 → 재크래시를 반복할 때 Kubernetes가 재시작 간격(backoff)을 점점 늘리며 다시 띄우는 상태입니다. 즉 “일시적 장애”라기보다 반복 재시작 루프가 핵심 시그널입니다.

이 상태에서 중요한 포인트는 두 가지입니다.

  • 컨테이너는 “아예 실행이 안 되는 것”이 아니라 실행은 되지만 곧바로 종료되고 있습니다.
  • Kubernetes는 무작정 즉시 재시작하지 않고, 실패가 반복될수록 대기 시간을 늘리며(backoff) 재시도합니다.

대표 원인: 크게 7가지 범주로 보면 빨라집니다

제가 공감했던 문서(이미지)의 장점은 원인을 “경험 기반 범주”로 묶어 탐색 공간을 빨리 줄이는 방식이었습니다.

  1. 애플리케이션 자체 크래시
    • 예외 발생, 설정 파일 파싱 실패, 필수 파일 누락 등
  2. 설정/환경변수 불일치 (ConfigMap/Secret 포함)
    • 키 이름 오타, 값 타입 오류, 누락된 환경변수
  3. 외부 의존성 연결 실패
    • DB/Redis/Kafka 등 연결 불가, DNS/NetworkPolicy, 인증 실패
  4. 엔트리포인트/커맨드/이미지 문제
    • command/args 오타, 실행 파일 권한/경로 문제, 잘못된 이미지 태그
  5. Probe(liveness/readiness) 실패
    • 앱은 살아있는데 헬스체크가 너무 타이트해서 kubelet이 죽이는 경우
  6. 리소스 문제 (특히 OOMKilled)
    • 메모리 부족, limit 설정 과도, 스파이크로 OOM 발생
  7. 런타임 제약(권한/포트 등)
    • privileged/권한 부족, 포트 바인딩 실패, 파일시스템 write 불가 등

이 분류가 좋은 이유는 “로그만 보자”로 시작하면 놓치기 쉬운 케이스(프로브/OOM/권한)를 초기에 분기할 수 있기 때문입니다.

가장 빠른 트러블슈팅 순서: Logs보다 Events가 먼저인 이유

대화에서도 핵심으로 나왔던 부분인데, CrashLoopBackOff애플리케이션 로그보다 Kubernetes 이벤트(Events)가 더 빨리 정답을 말해주는 경우가 많습니다. 저는 아래 순서를 추천합니다.

1) Pod 상태 확인: 현재 무엇이 반복되는지부터 잡기

kubectl get pods -n <ns>
kubectl get pod <pod> -n <ns> -o wide
  • RESTARTS가 증가하는지
  • 특정 노드에만 몰리는지(노드 이슈 가능성)
  • 상태가 CrashLoopBackOff인지 Error인지 등 큰 흐름을 봅니다.

2) kubectl describe pod: Events에서 “쿠버네티스 관점의 원인”을 확인

kubectl describe pod <pod> -n <ns>

여기서 보는 핵심은:

  • Events
    • Back-off restarting failed container
    • Liveness probe failed, Readiness probe failed
    • OOMKilled 힌트(또는 Status/Last State에서 확인)
    • FailedMount, FailedPull 같은 인프라/이미지/볼륨 이슈
  • Container States / Last State
    • Exit Code, Reason(예: OOMKilled, Error)
    • “왜 종료됐는지”가 로그보다 먼저 보이는 경우가 많습니다.

제가 느끼는 포인트는 이겁니다. CrashLoopBackOff는 ‘앱이 왜 죽었는지’와 ‘쿠버네티스가 왜 죽였는지(프로브 등)’가 섞여 있는 문제라서, Events가 우선순위를 잡아줍니다.

3) kubectl logs + --previous: “직전 크래시 로그”가 가장 중요

kubectl logs <pod> -n <ns> -c <container>
kubectl logs <pod> -n <ns> -c <container> --previous
  • --previous는 직전 컨테이너 인스턴스의 로그를 보여주기 때문에, 재시작 루프에서는 사실상 필수입니다.
  • 앱이 시작 직후 죽으면 “현재 로그”는 비어 있고, --previous에만 단서가 있는 일이 흔합니다.

4) 원인 범주별로 “수정 포인트”를 빠르게 적용

아래는 많이 나오는 패턴별로, 어디를 고쳐야 하는지의 감을 잡는 가이드입니다.

  • Config/Env 문제: Deployment/Helm values의 env, ConfigMap/Secret 키/값 점검
  • 의존성 연결 실패: 서비스 DNS, 네트워크 정책, 인증 정보, 초기화 순서(의존성이 늦게 뜨는지) 확인
  • 엔트리포인트 문제: 이미지 내 실행 경로/권한, command/args 검증
  • Probe 실패: 초기 기동이 느리면 startupProbe 도입, initialDelaySeconds/timeoutSeconds/failureThreshold 재조정
  • OOMKilled: resources.requests/limits 재조정, 메모리 누수/캐시 정책 점검
  • 권한/포트: securityContext, FS 권한, privileged 필요 여부, 포트 충돌 점검

인사이트: “관측성은 무조건 중요”하지만, 우선순위가 있습니다

대화에서 “관측성은 무조건 중요합니다”라는 말이 나왔는데, 저도 동의합니다. 다만 CrashLoopBackOff 대응에서 모든 APM을 먼저 붙이기보다, 가성비가 높은 신호부터 챙기는 게 현실적입니다.

CrashLoopBackOff에 특히 효과적인 1순위 신호는 보통 이 3가지입니다.

  1. kubectl describe의 Events
  2. 컨테이너 종료 사유(ExitCode/Reason, OOMKilled 등)
  3. kubectl logs --previous

이 “최소 3종 세트”만 제대로 수집/공유돼도, 반복 재시작 이슈의 상당수는 훨씬 빨리 끝납니다. 그리고 그 다음 단계로 메트릭/트레이싱을 붙여 “재현이 어렵거나 간헐적인 크래시”까지 커버하는 전략이 자연스럽습니다.

마무리

CrashLoopBackOff는 “계속 죽는다”보다 **“죽고 다시 뜨는 루프 + backoff”**라는 현상을 정확히 이해하는 게 시작입니다. 저는 get → describe(Events) → logs(–previous) 순서로 습관을 잡는 것만으로도, 원인 좁히는 속도가 눈에 띄게 빨라졌습니다.

[출처] https://www.linkedin.com/feed/update/urn:li:groupPost:6585254-7472633961161236481/

1개의 좋아요