Liveness Probe가 장애를 복구한다고요? Kubernetes가 정상 Pod를 죽이는 7가지 설정

Kubernetes 헬스체크와 장애 신호를 상징하는 심전도 모니터
애플리케이션의 맥박을 잘못 읽으면, Kubernetes는 정상 Pod까지 죽입니다. Photo: Joshua Chehov / Unsplash

트래픽이 몰린 순간, Kubernetes가 가장 바쁜 Pod부터 차례로 재시작했습니다.

애플리케이션이 죽은 것도 아니고 메모리가 부족한 것도 아니었습니다. 응답이 잠시 느려지자 livenessProbe가 실패했고, kubelet은 컨테이너를 재시작했습니다. 살아남은 Pod로 요청이 더 몰렸고, 그 Pod들마저 Probe에 실패했습니다. 복구 장치가 장애 증폭기가 된 순간입니다.

헬스체크는 대시보드용 신호가 아닙니다 Probe 결과는 트래픽 차단과 컨테이너 재시작을 직접 일으키는 제어 신호입니다. 잘못 설계된 한 줄이 운영 장애의 원인이 될 수 있습니다.

세 가지 Probe, 이름보다 결과가 중요하다

Kubernetes 공식 문서가 구분하는 핵심은 단순합니다. Startup은 시작을 기다리고, Readiness는 트래픽을 끊고, Liveness는 컨테이너를 재시작합니다.

Probe실패하면답해야 할 질문대표 용도
startup성공 전까지 다른 Probe를 보류앱이 시작됐나?느린 부팅·캐시 워밍업
readinessService 엔드포인트에서 제외지금 요청을 받아도 되나?일시적 과부하·의존성 장애
liveness컨테이너 재시작재시작 없이는 회복 불가능한가?교착·복구 불가능 상태
애플리케이션 상태를 실시간으로 보여주는 병원 바이탈 모니터
신호를 많이 수집하는 것보다, 신호 하나가 어떤 행동을 일으키는지 아는 것이 먼저입니다. Photo: Maxim Tolchinskiy / Unsplash

정상 Pod를 죽이지 않는 7가지 규칙

1. Liveness에서는 외부 의존성을 검사하지 않는다

데이터베이스, Redis, 외부 API가 잠시 느리다는 이유로 애플리케이션 프로세스를 재시작해도 의존성은 복구되지 않습니다. 오히려 재기동 비용과 재접속 폭주가 더해집니다. Liveness는 프로세스 교착처럼 재시작해야만 회복되는 상태에 집중하세요.

2. 일시적 문제는 Readiness로 트래픽만 뺀다

요청을 처리하기 어려운 Pod는 Service 대상에서 잠시 제외하면 됩니다. Readiness 실패 시 EndpointSlice에서 해당 Pod가 준비되지 않은 상태로 반영되지만 컨테이너 자체를 죽이지는 않습니다. 과부하와 일시적 의존성 장애에는 이 차이가 매우 큽니다.

3. 느린 시작은 initialDelaySeconds가 아니라 Startup Probe로 보호한다

부팅 시간이 환경마다 달라진다면 고정 지연값 하나로 버티지 마세요. Startup Probe가 성공하기 전에는 Liveness와 Readiness가 실행되지 않습니다. 허용 시작 시간은 대략 failureThreshold × periodSeconds로 계산할 수 있습니다.

4. timeout과 실패 횟수는 감이 아니라 지연시간으로 정한다

Probe의 기본값을 그대로 복사하면 네트워크 흔들림이나 GC 구간을 장애로 오판할 수 있습니다. 실제 시작 시간과 헬스 엔드포인트의 p99 지연시간을 측정한 뒤 timeoutSeconds, periodSeconds, failureThreshold를 명시하세요.

5. /live와 /ready의 판단 기준을 분리한다

두 Probe가 같은 URL을 호출하면 이름만 다르고 결과는 같아집니다. /live는 프로세스 내부의 최소 상태만 빠르게 확인하고, /ready는 요청 처리에 반드시 필요한 조건을 확인하세요. 무거운 SQL, 전체 테이블 조회, 외부 인터넷 호출은 Probe 경로에서 피해야 합니다.

6. 아래 YAML은 출발점일 뿐, 그대로 복사하지 않는다

containers:
  - name: api
    image: example/api:1.0.0
    ports:
      - name: http
        containerPort: 8080

    startupProbe:
      httpGet:
        path: /health/startup
        port: http
      periodSeconds: 5
      timeoutSeconds: 2
      failureThreshold: 60   # 최대 5분 대기

    readinessProbe:
      httpGet:
        path: /health/ready
        port: http
      periodSeconds: 5
      timeoutSeconds: 2
      failureThreshold: 2
      successThreshold: 1

    livenessProbe:
      httpGet:
        path: /health/live
        port: http
      periodSeconds: 10
      timeoutSeconds: 2
      failureThreshold: 3

이 값은 예시입니다. 실제 서비스의 부팅 분포, 정상 지연시간, 복구 시간 목표에 맞춰 조정하고 먼저 일부 Pod에 카나리로 적용하세요.

7. 재시작 횟수와 Probe 실패를 배포 성공 조건에 넣는다

HTTP 200 응답만 보고 배포 성공으로 판단하지 마세요. 새 버전의 restartCount, NotReady 시간, Probe 실패 이벤트를 함께 관찰해야 합니다. 재시작이 늘면 자동 승격을 중단하고 이전 버전으로 되돌릴 수 있어야 합니다.

잘못된 Kubernetes 헬스체크의 영향을 받는 운영 서버 인프라
Probe 한 줄의 뒤에는 고객 요청을 처리하는 실제 인프라가 있습니다. Photo: Eric Stoynov / Unsplash

장애가 났다면 이 세 줄부터 확인한다

kubectl describe pod <pod-name>
kubectl logs <pod-name> --previous
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[*].restartCount}'

describe의 Events에서 Unhealthy와 Killing을 찾고, --previous로 재시작 직전 로그를 확인하세요. Probe 값을 무작정 늘리기 전에 실제 실패가 타임아웃인지, 잘못된 경로인지, 애플리케이션 교착인지 구분해야 합니다.

Liveness를 추가하기 전 세 가지 질문
  1. 이 실패는 컨테이너 재시작으로 실제 복구되는가?
  2. 외부 의존성 실패를 애플리케이션 사망으로 오판하고 있지 않은가?
  3. 프로세스가 이미 스스로 종료하고 restartPolicy로 복구된다면 Liveness가 꼭 필요한가?

마무리: Kubernetes는 Probe가 거짓말하는지 모른다

Kubernetes는 헬스 엔드포인트의 의미를 해석하지 않습니다. 실패라는 신호를 받으면 설정된 행동을 정확하게 수행할 뿐입니다. 그래서 좋은 Probe는 많은 것을 검사하는 Probe가 아니라 행동의 결과까지 정확히 설계한 Probe입니다.

죽지 않은 Pod를 살리겠다며 재시작하는 순간, 자동 복구는 자동 장애가 됩니다.


참고 문서: Kubernetes — Liveness, Readiness, and Startup Probes · Configure Probes · Pod Lifecycle

댓글

이 블로그의 인기 게시물

금융권 망분리 환경에서 클로드 코드 도입할 때 실제로 걸리는 5가지 — 보안팀 질문과 대응 설정

맥 스튜디오 M5 Ultra 512GB, 3,000만원을 어떻게 결제할까 — 카드 한도 상향·18개월 무이자·잔존가치 금융리스 총정리

Kubernetes Pod Pending 해결법: FailedScheduling 원인별 실전 점검 가이드