본문 바로가기
Q&A해결2026년 8월 23일1분 읽기

쿠버네티스 파드가 부팅 도중 계속 재시작되는데 liveness probe 때문일까요?

k
k8s_garam
조회 508댓글 4

스프링 부트 앱을 k8s에 올렸는데, 앱 자체는 멀쩡한데 파드가 뜬 지 20~30초쯤 되면 자꾸 재시작됩니다. RESTARTS 카운트가 계속 올라가요. 로그를 보면 애플리케이션은 정상적으로 부팅 중인데 그 도중에 SIGTERM을 받고 죽습니다.

NAME             READY   STATUS    RESTARTS   AGE
api-7d9f8-xk2l   0/1     Running   4          3m

livenessProbe는 이렇게 걸어놨습니다.

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3

앱 부팅이 좀 무거워서 완전히 뜨는 데 40초 정도 걸리는데, 이게 관련이 있을까요? CrashLoopBackOff는 아니고 그냥 Running 상태에서 재시작만 반복됩니다.

댓글 4

김김영삼2개월 전
정확히 그것 때문입니다. 지금 설정으로 liveness가 앱을 죽이기까지 걸리는 시간을 계산해보면, initialDelaySeconds 10 + periodSeconds 5 × failureThreshold 3 = 대략 25초예요. 그런데 앱은 40초 걸려서 뜨죠. 그러니까 앱이 아직 부팅 중일 때 health가 200을 안 주고, 25초 지점에서 liveness가 '얘 죽었네' 판정하고 SIGTERM 보내서 죽입니다. 그리고 재시작, 또 부팅 중에 죽고, 무한 반복이에요.

initialDelaySeconds를 크게 늘리는 걸로 때우고 싶겠지만 그건 안티패턴입니다. 그 값을 60으로 잡으면 정상 운영 중에 앱이 진짜 hang 됐을 때도 60초를 기다려야 감지되거든요. 부팅 느린 것과 런타임 헬스체크는 목적이 다른데 하나의 노브로 둘 다 맞추려니 안 되는 거예요.

정답은 startupProbe입니다. startupProbe가 성공할 때까지 kubelet은 liveness랑 readiness를 아예 시작조차 안 해요. 그래서 느린 부팅은 startupProbe한테 넉넉하게 맡기고, liveness는 짧고 공격적으로 유지할 수 있습니다.

startupProbe:
httpGet: { path: /actuator/health/liveness, port: 8080 }
failureThreshold: 30
periodSeconds: 5

이러면 부팅에 최대 150초(30 × 5)까지 봐주고, 그동안 liveness는 잠자코 있습니다. 부팅 끝나고 startupProbe 통과한 뒤부터 liveness가 원래대로 5초 간격으로 감시 시작해요. 재시작 루프 바로 멈출 겁니다.
kk8s_garam(guest)2개월 전
startupProbe 넣으니까 재시작이 딱 멈췄습니다! 며칠째 왜 죽나 했는데 살았네요.

하나만 더 여쭤볼게요. liveness랑 readiness를 지금처럼 둘 다 /actuator/health 통짜로 써도 되나요, 아니면 분리하는 게 나은가요?
김김영삼2개월 전
분리하는 걸 강력히 권합니다. 둘은 물어보는 질문이 달라요.

liveness는 '이 프로세스가 살아있나, 아니면 재시작해야 하나'를 묻습니다. readiness는 '지금 트래픽 받을 준비가 됐나'를 물어요. 예를 들어 DB 연결이 잠깐 끊기면 이건 재시작한다고 해결되는 문제가 아니거든요. 앱은 살아있으니 liveness는 통과해야 하고, 대신 readiness만 실패시켜서 트래픽을 잠깐 빼는 게 맞습니다.

그런데 /actuator/health 통짜로 쓰면 스프링 헬스는 DB 상태까지 다 물려 있어서, DB가 깜빡하는 순간 liveness까지 fail 나고 멀쩡한 파드가 불필요하게 재시작됩니다. DB 잠깐 끊긴 걸로 전체 파드가 재시작 도미노 타는 거예요.

스프링 부트는 health.liveness 와 health.readiness 그룹을 따로 지원합니다. management.endpoint.health.probes.enabled=true 켜면 /actuator/health/liveness 랑 /actuator/health/readiness 가 각각 생겨요. liveness 프로브는 앞엣걸, readiness 프로브는 뒤엣걸 물게 하세요. liveness 그룹엔 DB 같은 외부 의존성 체크를 넣지 말고 정말 프로세스 생존만 보게 하는 게 핵심입니다.
kk8s_garam(guest)2개월 전
아 이제 확실히 이해됐습니다. liveness에 DB를 물리면 안 되는 이유가 딱 와닿네요. 그룹 분리해서 적용했어요 🙏
Ctrl+Enter로 등록