Spring Boot + Kubernetes






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

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

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줄)

  1. startupProbe를 두면, Kubernetes 문서에 따라 startupProbe가 성공하기 전까지 liveness/readiness probe는 시작되지 않습니다. 느린 기동(마이그레이션/캐시 워밍업)에서 필수입니다.
  2. readinessProbe는 Kubernetes 문서에 따라 Service의 백엔드에서 Pod를 제거/복귀시키는 신호입니다(트래픽 제어).
  3. livenessProbe는 Kubernetes 문서에 따라 컨테이너를 재시작할지 판단하는 신호입니다(진짜 “살아있음”).
  4. Spring Boot 문서에 따르면 graceful shutdown은 기본 활성화이며, 기존 요청은 grace 기간 동안 완료되지만 새 요청은 거부됩니다.
  5. Spring Boot 문서에 따르면 grace 기간은 spring.lifecycle.timeout-per-shutdown-phase로 조정합니다.
  6. Spring Boot Actuator 문서에 따르면 health endpoint는 liveness/readiness 상태를 노출할 수 있고, management.endpoint.health.probes.enabled로 제어할 수 있습니다.
  7. 실무에서는 startup → readiness → liveness 순서로 “단계별로 엄격”하게 만들고, readiness가 내려가는 순간에 트래픽이 빠지도록 설계합니다.
  8. 마지막으로, 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를 도입할 때 “기동 중 오탐으로 죽이는 문제”를 피하기 위한 기능입니다.

공식 문서 링크:
Configure Liveness, Readiness and Startup Probes

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. 전체 흐름(운영자가 기대하는 시간 순서)

  1. Pod 생성
  2. startupProbe가 애플리케이션 기동 완료를 확인
  3. startupProbe 성공 이후 readinessProbe가 성공하면 Service 백엔드에 포함되어 트래픽 수신
  4. 운영 중 장애/데드락 등 “진행 불가”가 감지되면 livenessProbe 실패 → kubelet이 재시작 판단
  5. 롤링 업데이트/스케일 인 등으로 종료가 시작되면 SIGTERM → Spring Boot graceful shutdown 수행
  6. 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: 체크리스트)

  1. 기동 시간 계측: cold start / warm start가 각각 몇 초인지 로그+메트릭으로 확인
  2. startupProbe 도입: 느린 기동이면 반드시 startupProbe로 기동 구간을 분리
  3. readiness 의미 정리: “트래픽 받을 수 있음”을 명확히 정의(예: DB 연결 필수인지, 캐시 워밍업까지 포함인지)
  4. liveness는 ‘생존’에 집중: 외부 의존성 장애(예: 일시적 MySQL 장애)로 liveness가 죽지 않게 설계하는 원칙을 정함
  5. graceful shutdown 타임아웃 설정: spring.lifecycle.timeout-per-shutdown-phase를 실제 요청 p99에 맞춰 설정
  6. 검증: 배포 중 (1) readiness 내려감, (2) 새 요청 차단, (3) 기존 요청 완료, (4) 종료 순서가 기대와 일치하는지 재현 테스트
  7. 관측 가능성: 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: 검증 절차)

  1. 테스트 환경에서 배포/재시작/스케일 인을 재현하고, Pod event로 probe 실패/재시작 여부를 확인합니다.
  2. 애플리케이션 로그에서 SIGTERM 수신 및 graceful shutdown 구간의 로그를 확인합니다.
  3. 요청 로그/분산 트레이싱에서 종료 시점에 in-flight 요청이 정상 완료되는지 확인합니다.
  4. 수치(초 단위)는 서비스별로 다르므로, 최종 값은 “측정 결과”로 확정합니다.

참고(공식 문서)


위로 스크롤
WordPress Appliance - Powered by TurnKey Linux