Developer Playground
Graceful Shutdown of Spring Boot Applications in Kubernetes: SIGTERM, preStopHook, and Actuator
Table of Contents
Why is Graceful Shutdown Important?
In modern application development using microservices architecture and container environments, especially Kubernetes, "application termination" means more than just shutting down a process. Abrupt termination can lead to serious problems like data loss, service inconsistencies, and degraded user experience.
Imagine a user sending a payment request, and the server Pod processing that request suddenly terminates.
Potential Issues of Abrupt Termination
- Data Loss/Inconsistency: Ongoing transactions can be interrupted, leading to incomplete data in the database or loss of critical information.
- Resource Leaks: Open database connections and file handles might not be properly closed, resulting in resource leaks.
- Degraded User Experience: In-progress requests might fail, displaying error messages to users or temporarily interrupting service.
- Reduced System Stability: Unexpected terminations can trigger alerts in monitoring systems and consume unnecessary time for incident response.
To prevent these issues, applications must undergo a Graceful Shutdown process, essentially announcing: "I'm about to shut down, so I'll finish what I'm doing and clean up neatly!"
Understanding Kubernetes Pod Termination Lifecycle
Kubernetes follows a defined sequence when terminating a Pod. Understanding this process is key to implementing Graceful Shutdown.
- Pod Termination Request and Transition to Terminating State: Kubernetes decides a Pod needs to be terminated (e.g., due to
kubectl delete pod
, deployment updates, or scaling down). The Pod changes fromRunning
toTerminating
status. - Removal of Pod IP from Service Endpoints: Almost simultaneously with the Pod entering the
Terminating
state, the Kubernetes control plane begins removing the Pod's IP address from the endpoint list of all relevant Services. This is crucial! New traffic will now no longer be routed to this Pod. - preStopHook Execution (Optional): If a
preStopHook
is defined in the Pod specification, this hook executes before the SIGTERM signal is sent to the container.preStopHook
can be anexec
(executing a command inside the container) orhttpGet
(sending an HTTP request).- Key Point: Kubernetes waits for the
preStopHook
to complete before sending SIGTERM. - The
terminationGracePeriodSeconds
countdown begins at this point.
- SIGTERM Signal Sent: Immediately after the
preStopHook
successfully completes, or if nopreStopHook
is defined, as soon as the Pod enters theTerminating
state and is removed from endpoints, Kubernetes sends a SIGTERM signal to the container's main process (PID 1).- SIGTERM is a soft termination signal, asking the application to "wrap up what you're doing and shut down gracefully."
terminationGracePeriodSeconds
Wait: From the moment SIGTERM is sent, Kubernetes waits for the duration specified byterminationGracePeriodSeconds
for the application to shut down on its own. During this period, the application should complete ongoing requests, close database connections, release resources, etc.- SIGKILL Signal Sent (Last Resort): If the application does not terminate within the
terminationGracePeriodSeconds
, Kubernetes stops waiting and forcibly sends a SIGKILL signal. SIGKILL immediately terminates the process in any situation, risking data loss or resource leaks because the application cannot complete its shutdown tasks.
Graceful Shutdown in Spring Boot: server.shutdown=graceful
Spring Boot has built-in functionality to gracefully shut down when it receives a SIGTERM signal. Since Spring Boot 2.3, you can activate this with a simple configuration.
Add the following to application.yml
or application.properties
:
Spring Boot Graceful Shutdown Configuration (application.yml
)
server:
shutdown: graceful # Enable graceful shutdown
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # Optional: Max wait time per shutdown phase
With this setting, when a Spring Boot application receives SIGTERM:
- It immediately stops accepting new requests.
- It waits for currently processing requests to complete.
- Once all requests are processed, it performs cleanup tasks such as shutting down Tomcat (or other web servers) and closing the Spring context.
When is preStopHook Useful? (Primarily for sleep
)
Even with the server.shutdown=graceful
setting, Spring Boot applications will gracefully shut down upon receiving SIGTERM. However, using a preStopHook
enhances the certainty of Traffic Draining.
It's common to use a short sleep
command in preStopHook
.
Kubernetes Pod preStopHook
Example
apiVersion: apps/v1
kind: Deployment
# ... other deployment configurations ...
spec:
template:
spec:
containers:
- name: my-app-container
image: your-docker-image:latest
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"] # Wait for 10 seconds
terminationGracePeriodSeconds: 60 # Sufficient time for app to shut down (e.g., 60 seconds)
Why use sleep
?
Mitigate Load Balancer/Service Mesh Synchronization Delays: Even when Kubernetes removes a Pod's IP from endpoints, it can take a few seconds for external load balancers or service meshes (like Istio, Nginx Ingress) to detect this change and actually stop routing traffic to the Pod.
The sleep
in preStopHook
explicitly ensures this "detection delay" time is compensated, providing enough time for all new traffic to be certainly blocked from reaching the Pod before SIGTERM arrives.
How long should the sleep
be? It's important to keep it short, generally recommended between 5 to 15 seconds. Too long will unnecessarily increase deployment time and reduce the time available for SIGTERM processing, increasing the risk of SIGKILL.
Role and Security of Actuator Shutdown (/actuator/shutdown
)
Spring Boot Actuator's /actuator/shutdown
endpoint explicitly commands the application to "shut down now." You can call this endpoint with curl
or similar in a preStopHook
to initiate shutdown.
Actuator Shutdown Call in preStopHook
(Security Warning!)
# Example of calling Actuator shutdown in preStopHook (Security Warning!)
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "curl -X POST -u ${ACTUATOR_USERNAME}:${ACTUATOR_PASSWORD} http://localhost:8080/actuator/shutdown"]
Important: Security is a Must!
The /actuator/shutdown
endpoint is highly sensitive and must never be exposed externally without proper security configurations! Use Spring Security to restrict access and securely pass authentication information (e.g., using Kubernetes Secrets) when calling it from preStopHook
.
When to use this method? This approach might be considered in specific scenarios where fine-grained control is difficult with only SIGTERM processing, or if the application needs to initiate shutdown upon receiving an explicit external signal. However, considering the complexity of security configuration and potential risks, the server.shutdown=graceful
and SIGTERM handling approach is generally more recommended.
Final Recommendations and Best Practices
For graceful shutdown of Spring Boot applications in Kubernetes, the best practices are as follows:
Key Best Practices
- Absolutely enable Spring Boot's
server.shutdown=graceful
. This is the core mechanism for your application to perform graceful shutdown tasks upon receiving SIGTERM. - Consider adding a short
sleep
topreStopHook
. This provides an additional safety measure to ensure the Pod is completely detached from service endpoints and no new traffic comes in before SIGTERM is delivered (e.g.,sleep 5
tosleep 15
). - Set
terminationGracePeriodSeconds
sufficiently long to match your application's shutdown time. Measure the time your application needs to receive SIGTERM and complete all cleanup tasks, then set an appropriate value (typically 30 seconds to 120 seconds). ThepreStopHook
duration should also be accounted for within this period. - If using Actuator shutdown, always protect it thoroughly with Spring Security or similar. Use environment variables and Kubernetes Secrets to securely manage authentication information.
By adopting this approach, your Spring Boot applications in a Kubernetes environment will be more stable, predictable, and capable of shutting down gracefully without data loss. This ultimately leads to a more robust and reliable microservices architecture.
Advertisement