Spring Boot + Kubernetes 심화: startup/readiness/liveness probe와 Graceful Shutdown을 ‘한 세트’로 설계하는 체크리스트

운영에서 장애를 만드는 건 보통 “기능 버그”가 아니라 생명주기(lifecycle) 설계의 빈틈입니다.
대표적으로는 다음 같은 상황입니다.
- Spring Boot가 아직 완전히 뜨지 않았는데 liveness가 먼저 실패해 CrashLoopBackOff로 들어감
- 배포 중 트래픽이 아직 준비되지 않은 Pod로 유입되어 초기 5xx가 튐
- 종료(SIGTERM) 시점에 트래픽 드레이닝이 안 돼서 사용자 요청이 중간에 끊김
이 글은 위 3가지를 startup/readiness/liveness probe + Spring Boot graceful shutdown을 “한 세트”로 묶어서 해결하는 실무 패턴을 정리합니다.
본문에서 확정하는 동작/주장은 공식 문서 근거로만 설명합니다.
TL;DR (실무 결론 8줄)
- startupProbe를 두면, Kubernetes 문서에 따라 startupProbe가 성공하기 전까지 liveness/readiness probe는 시작되지 않습니다. 느린 기동(마이그레이션/캐시 워밍업)에서 필수입니다.
- readinessProbe는 Kubernetes 문서에 따라 Service의 백엔드에서 Pod를 제거/복귀시키는 신호입니다(트래픽 제어).
- livenessProbe는 Kubernetes 문서에 따라 컨테이너를 재시작할지 판단하는 신호입니다(진짜 “살아있음”).
- Spring Boot 문서에 따르면 graceful shutdown은 기본 활성화이며, 기존 요청은 grace 기간 동안 완료되지만 새 요청은 거부됩니다.
- Spring Boot 문서에 따르면 grace 기간은
spring.lifecycle.timeout-per-shutdown-phase로 조정합니다. - Spring Boot Actuator 문서에 따르면 health endpoint는 liveness/readiness 상태를 노출할 수 있고,
management.endpoint.health.probes.enabled로 제어할 수 있습니다. - 실무에서는 startup → readiness → liveness 순서로 “단계별로 엄격”하게 만들고, readiness가 내려가는 순간에 트래픽이 빠지도록 설계합니다.
- 마지막으로, probe 설정은 무조건 로그/이벤트로 검증하고(“추정 금지”), 실패 모드별 대응(타임아웃/threshold 조정)을 문서화합니다.
1) Kubernetes probe 3종의 역할을 ‘정확히’ 구분하기 (공식 문서 기반)
1-1. livenessProbe: “죽었거나 진행 불가면 재시작”
Kubernetes 공식 문서는 kubelet이 liveness probe를 컨테이너 재시작 판단에 사용한다고 설명합니다.
예시로 “데드락처럼 프로세스는 돌지만 진행이 안 되는 상태”를 들며, 재시작으로 가용성을 높일 수 있다고 설명합니다.
따라서 liveness는 “서비스 품질”이 아니라 “프로세스 생존” 신호에 가깝게 설계하는 게 안전합니다.
1-2. readinessProbe: “트래픽을 받을 준비가 되었는가”
Kubernetes 공식 문서는 kubelet이 readiness probe를 컨테이너가 트래픽을 받을 준비 여부 판단에 사용한다고 설명하며,
Pod가 준비되지 않으면 Service 로드밸런서의 백엔드에서 제거된다고 명시합니다.
즉 readiness는 “(바로 지금) 트래픽을 받을 수 있나”를 표현하는 게 핵심입니다.
1-3. startupProbe: “기동이 끝날 때까지 다른 probe를 지연”
Kubernetes 공식 문서는 startup probe가 설정되면, 성공하기 전까지 liveness/readiness probe가 시작되지 않는다고 설명합니다.
느리게 시작하는 컨테이너에 liveness를 도입할 때 “기동 중 오탐으로 죽이는 문제”를 피하기 위한 기능입니다.
2) Spring Boot graceful shutdown: “기존 요청은 완료, 새 요청은 거부” (공식 문서 기반)
Spring Boot 공식 문서는 graceful shutdown이 Jetty/Reactor Netty/Tomcat(임베디드)에서 기본 활성화라고 설명합니다.
또한 애플리케이션 컨텍스트 종료 과정에서 수행되며, grace 기간 동안 기존 요청은 완료되도록 허용하지만 새 요청은 허용되지 않는다고 설명합니다.
2-1. timeout(그레이스 기간) 설정
Spring Boot 문서에 따라 spring.lifecycle.timeout-per-shutdown-phase로 grace 기간을 설정합니다.
예시 (application.yaml)
spring:
lifecycle:
timeout-per-shutdown-phase: "20s"
2-2. 즉시 종료를 강제해야 할 때
Spring Boot 문서에 따르면 server.shutdown=immediate로 graceful shutdown을 비활성화할 수 있습니다.
(대부분의 서비스에서는 추천되지 않지만, 특정 배치/실험 환경에서 의도적으로 즉시 종료가 필요할 때가 있습니다.)
공식 문서 링크:
Spring Boot Reference: Graceful Shutdown
3) Spring Boot Actuator로 readiness/liveness 엔드포인트를 만들기 (공식 문서 기반)
Spring Boot Actuator 문서는 Health endpoint에서 다양한 HealthIndicator를 자동 구성하며,
그 목록에 livenessstate / readinessstate가 포함될 수 있음을 설명합니다.
또한 이 probe 노출은 management.endpoint.health.probes.enabled로 비활성화할 수 있다고 명시합니다.
3-1. 권장 매핑(실무 패턴)
- readinessProbe → Actuator health의 readiness 신호(트래픽 수신 가능 여부)
- livenessProbe → Actuator health의 liveness 신호(프로세스가 정상 진행 가능한지)
- startupProbe → 기동 완료 조건(예: 애플리케이션이 완전히 초기화되고 필수 의존성이 준비된 시점)
공식 문서 링크:
Spring Boot Reference: Actuator Endpoints (Health 관련 설명 포함)
4) “한 세트” 설계: startup → readiness → graceful shutdown → liveness
4-1. 전체 흐름(운영자가 기대하는 시간 순서)
- Pod 생성
- startupProbe가 애플리케이션 기동 완료를 확인
- startupProbe 성공 이후 readinessProbe가 성공하면 Service 백엔드에 포함되어 트래픽 수신
- 운영 중 장애/데드락 등 “진행 불가”가 감지되면 livenessProbe 실패 → kubelet이 재시작 판단
- 롤링 업데이트/스케일 인 등으로 종료가 시작되면 SIGTERM → Spring Boot graceful shutdown 수행
- readinessProbe가 먼저 내려가 트래픽이 빠지고, grace 기간 동안 in-flight 요청을 마무리
4-2. 예시 Deployment 스니펫 (개념 강조용)
아래는 “개념을 보여주는 예시”입니다. 실제 값(initialDelay/timeout/threshold)은 애플리케이션 기동 시간과
트래픽 패턴, 외부 의존성(MySQL 등)에 맞춰 관측 기반으로 조정해야 합니다.
containers:
- name: app
image: your-registry/your-app:tag
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 60
periodSeconds: 2
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 6
probe의 HTTP 성공/실패 판정 기준(HTTP status code 범위 등)과 GET/exec/tcp/grpc 타입은 Kubernetes 문서에 설명되어 있습니다.
(예: HTTP GET은 200~399가 성공으로 처리될 수 있다는 예시가 문서에 포함됩니다.)
공식 문서 링크:
Kubernetes: Configure Probes
5) 운영 체크리스트 (필수 보강요소 1: 체크리스트)
- 기동 시간 계측: cold start / warm start가 각각 몇 초인지 로그+메트릭으로 확인
- startupProbe 도입: 느린 기동이면 반드시 startupProbe로 기동 구간을 분리
- readiness 의미 정리: “트래픽 받을 수 있음”을 명확히 정의(예: DB 연결 필수인지, 캐시 워밍업까지 포함인지)
- liveness는 ‘생존’에 집중: 외부 의존성 장애(예: 일시적 MySQL 장애)로 liveness가 죽지 않게 설계하는 원칙을 정함
- graceful shutdown 타임아웃 설정:
spring.lifecycle.timeout-per-shutdown-phase를 실제 요청 p99에 맞춰 설정 - 검증: 배포 중 (1) readiness 내려감, (2) 새 요청 차단, (3) 기존 요청 완료, (4) 종료 순서가 기대와 일치하는지 재현 테스트
- 관측 가능성: Pod event(프로브 실패), 애플리케이션 로그(SIGTERM 수신), 요청 로그(중간 끊김)로 교차 검증
6) 트러블슈팅 매트릭스 (필수 보강요소 2: 매트릭스)
| 증상 | 관측 포인트 | 가능한 원인(설계 관점) | 대응(공식 동작에 맞춘 조정) |
|---|---|---|---|
| 배포 직후 CrashLoopBackOff | Pod event에 liveness 실패 반복 | 기동이 느린데 liveness가 너무 빨리 시작됨 | startupProbe 추가/조정(성공 전까지 liveness/readiness 지연은 Kubernetes 문서 동작) |
| 롤링 업데이트 중 5xx 스파이크 | Ingress/Service 로그에서 특정 Pod로 5xx 집중 | readiness가 실제 준비 상태를 반영하지 못함 | readiness 조건을 재정의(트래픽 수신 가능 상태가 되었을 때만 true) |
| 스케일 인/배포 시 요청이 중간에 끊김 | 클라이언트에서 connection reset, 서버 로그에서 종료 시점과 겹침 | graceful shutdown 타임아웃이 너무 짧거나 새 요청 차단이 늦음 | Spring Boot grace 타임아웃 조정(문서의 spring.lifecycle.timeout-per-shutdown-phase) + readiness 먼저 내려가도록 설계 |
7) FAQ (필수 보강요소 3: FAQ)
Q1. startupProbe가 있으면 readiness/liveness는 정말 “아예 시작 안 하나요?”
Kubernetes 공식 문서는 startup probe가 설정되면, 성공하기 전까지 liveness/readiness probe가 시작되지 않는다고 설명합니다.
따라서 느린 기동에서 “기동 중 오탐 재시작”을 줄이기 위해 startupProbe를 분리하는 것이 문서가 의도한 사용 방식입니다.
Q2. Spring Boot graceful shutdown은 기본으로 켜져 있나요?
Spring Boot 공식 문서는 graceful shutdown이 Jetty/Reactor Netty/Tomcat 임베디드 서버에서 기본 활성화라고 설명합니다.
단, 실제 운영에서 “제대로” graceful하게 보이려면 readiness 드레이닝, 인프라(LB/Ingress)의 연결 유지 특성 등을 함께 점검해야 합니다.
Q3. Health endpoint에서 liveness/readiness를 분리해서 제공할 수 있나요?
Spring Boot Actuator 문서는 health 관련 indicator 목록에 livenessstate, readinessstate가 포함될 수 있음을 설명합니다.
노출 여부는 management.endpoint.health.probes.enabled로 제어할 수 있습니다.
(정확한 노출 URL/구성은 사용 중인 Spring Boot 버전의 Reference를 기준으로 확인하세요.)
8) “추정 금지” 검증 절차 (필수 보강요소 4: 검증 절차)
- 테스트 환경에서 배포/재시작/스케일 인을 재현하고, Pod event로 probe 실패/재시작 여부를 확인합니다.
- 애플리케이션 로그에서 SIGTERM 수신 및 graceful shutdown 구간의 로그를 확인합니다.
- 요청 로그/분산 트레이싱에서 종료 시점에 in-flight 요청이 정상 완료되는지 확인합니다.
- 수치(초 단위)는 서비스별로 다르므로, 최종 값은 “측정 결과”로 확정합니다.
참고(공식 문서)
-
Kubernetes: Configure Liveness, Readiness and Startup Probes
— https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ -
Spring Boot Reference: Graceful Shutdown
— https://docs.spring.io/spring-boot/reference/web/graceful-shutdown.html -
Spring Boot Reference: Actuator Endpoints (Health 관련 설명 포함)
— https://docs.spring.io/spring-boot/reference/actuator/endpoints.html