Spring Boot cookbook · Intermediate
Shut down Spring Boot gracefully on Kubernetes
Deploy new versions without dropping in-flight requests or failing health checks.
Approach
Enable graceful shutdown (default in recent Boot versions) with a timeout, expose liveness/readiness probes, and add a short preStop sleep so the pod is removed from Service endpoints before Tomcat stops accepting connections. Keep terminationGracePeriodSeconds longer than preStop + shutdown timeout.
Solution
# application.yml
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 25s
management:
endpoint:
health:
probes:
enabled: true
# deployment.yaml (excerpt)
spec:
terminationGracePeriodSeconds: 45
containers:
- name: api
image: registry.example.com/shop-api:1.42.0
readinessProbe:
httpGet: { path: /actuator/health/readiness, port: 8081 }
periodSeconds: 5
livenessProbe:
httpGet: { path: /actuator/health/liveness, port: 8081 }
periodSeconds: 10
lifecycle:
preStop:
exec: { command: ["sh", "-c", "sleep 10"] }
Pitfalls
- No preStop delay: endpoints update after the app already stopped accepting connections (502s).
- Grace period shorter than shutdown timeout (SIGKILL mid-request).
- Liveness probes on external dependencies.
Variations
- Distroless images without
sh: use asleepbinary orpreStop.sleep(Kubernetes 1.30+).
Further reading: Spring Boot: Graceful shutdown
Reference: https://docs.spring.io/spring-boot/reference/web/graceful-shutdown.html
More Spring Boot recipes
- Add correlation IDs to Spring Boot logs
- Add retries and a circuit breaker with Resilience4j
- Authenticate machine clients with API keys in Spring Security
- Cache service results in Redis with @Cacheable
- Consume Kafka messages with retries and a dead-letter topic
- Handle concurrent updates with optimistic locking
- Implement soft delete with Hibernate
- Make POST endpoints idempotent in Spring Boot