쿠버네티스에는 헬스체크가 두 종류 있는데, livenessProbe와 readinessProbe를 혼동하면 멀쩡한 앱이 계속 재시작되거나, 반대로 죽은 앱에 트래픽이 계속 흘러갑니다. 둘은 묻는 질문이 다릅니다. liveness는 "이 컨테이너를 죽이고 재시작해야 하나?", readiness는 "지금 이 Pod로 트래픽을 보내도 되나?"를 판단합니다.
두 프로브가 하는 일
| 프로브 | 질문 | 실패하면 |
|---|---|---|
livenessProbe | 살아 있나? | 컨테이너 재시작 (kill + restart) |
readinessProbe | 요청 받을 준비됐나? | Service 엔드포인트에서 제외 (재시작 안 함) |
startupProbe | 기동 끝났나? | 기동 동안 다른 프로브 보류 |
핵심: liveness 실패는 재시작을, readiness 실패는 트래픽 차단을 부릅니다. 재시작이 필요 없는 일시적 과부하에 liveness를 쓰면 안 됩니다.
설정 예시
spec:
containers:
- name: web
image: myapp:1.0
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readiness는 DB 연결 등 의존성까지 확인하는 /ready로, liveness는 프로세스 자체만 보는 가벼운 /healthz로 분리하는 것이 정석입니다.
잘못 쓰면 생기는 일
① 기동이 느린데 liveness만 둠 — 앱이 30초 걸려 뜨는데 initialDelaySeconds가 짧으면, 기동 중 liveness가 실패해 계속 재시작되며 영원히 못 뜹니다. startupProbe로 기동 구간을 분리하세요.
② readiness에 DB 의존성을 넣고 liveness에도 같은 걸 넣음 — DB가 잠깐 끊기면 liveness까지 실패해 Pod가 재시작됩니다. 재시작해도 DB는 여전히 끊겨 있으니 무한 재시작이 됩니다. liveness는 외부 의존성을 보지 않게 합니다.
③ readiness 없이 배포 — 앱이 뜨자마자 트래픽을 받는데 아직 워밍업이 안 끝나, 배포 직후 502가 쏟아집니다.
진단 명령
kubectl describe pod <pod> # Liveness/Readiness 실패 이벤트
kubectl get endpoints <svc> # 트래픽 받는 Pod 목록(readiness 결과)
kubectl get pods -w # RESTARTS 증가 = liveness 의심
RESTARTS 숫자가 계속 오르면 liveness, READY가 0/1인데 재시작은 없으면 readiness 문제입니다. 이 둘만 구분해도 원인이 절반으로 좁혀집니다.
프로브를 일부러 실패시켜 재시작과 트래픽 차단의 차이를 눈으로 확인하는 실습은 쿠버네티스 트랙에서 해볼 수 있습니다 — 회원가입 없이 무료로.