Healthchecks for your containerized Spring Boot Application
A how-to-guide for Healthchecks: Liveness, Readiness and Startup Probes for Docker or Kubernetes solutions with Spring Boot and Actuator.
Preface
In this article, I will explain how to implement health checks and why this is a career-enhancing move for containerized Spring Boot applications.
Preconditions
Before we can jump in, there are some preconditions. And I assume that if you found this guide, you do
- have a decent understanding of Docker.
If not, please read first: https://medium.com/javarevisited/top-5-free-courses-to-learn-docker-for-beginners-best-of-lot-b2b1ad2b98ad - have advanced knowledge about Spring Boot development, particularly Spring Boot Actuator.
If not, please read first: https://spring.io/guides/gs/actuator-service/ - have a decent understanding of Kubernetes.
If not, please read first: https://kubernetes.io/docs/tutorials/kubernetes-basics/
*Nope, I’m not secretly sponsored to list these links, nor do I get a gold star every time you click one. These are either Google-gifted or from the mysterious depths of my bookmarks. It’s just some developer-curated content for your benefit. So, enjoy this free tour through my biased digital lens! End of a cheeky disclaimer.
Implementation
Technical Preconditions
To work conveniently with health check commands, I recommend having wget or curl as well as jq installed in your image.
For a production-proof example Dockerfile, which contains all those tools, check out my previous article:
Healthcheck Command Exit Status Codes
0: success, the container is healthy and ready for use1: unhealthy, the container is not working correctly2: reserved, do not use this exit code
Docker makes use of the standard Linux exit status codes.
Dockerfile Healthcheck
Even if it is less known, there is a way to define the health check directly in a Dockerfile.
Hint: Only one health check is allowed, and the last one will be used.
If you are using an image which comes with a predefined health check and you would like to change some parameters or even disable it at all, you can do that with the following options:
See here for more information: https://docs.docker.com/engine/reference/run/#healthcheck
Docker Compose Healthcheck
Following are two examples of how to define health checks in Docker Compose. The first health check uses the binary pg_isready from Postgres itself to check on the Postgres service, and the second checks if the Spring Boot application is healthy by making use of the Actuator endpoint /actuator/health.
Tipp: If you have more advanced health check commands to run, I recommend extracting and placing them in a separate file.
Docker, Specifying durations
Some configuration options, such as the interval and timeout sub-options for check, accept a duration as a string in a format that looks like this:
2.5s
10s
1m30s
2h32m
5h34m56sThe supported units are us, ms, s, m and h.
Kubernetes Healthchecks
- Startup probe: A startup probe verifies whether the application within a container is started. Startup probes run before any other probe; unless it successfully finishes, it disables other probes. If a container fails its startup probe, then the container is killed and follows the pod’s
restartPolicy.
Spring Boot does not expose a separate endpoint for the startup probe. For this use case, you could use the liveness probe, readiness probe, or a custom-developed health indicator. The reason to have a different probe in Kubernetes is to enable a long timeout for the initial startup of the application, which might take some time. After the first successful startup probe call, the liveness probe takes over, reducing timeout values to detect a failure and restart the application quickly.
- Readiness probe: Readiness probes determine whether or not a container is ready to serve requests. If the readiness probe returns a failed state, then Kubernetes removes the IP address for the container from the endpoints of all Services. Developers use readiness probes to instruct Kubernetes that a running container should not receive any traffic. This is useful when waiting for an application to perform time-consuming initial tasks, such as establishing network connections, loading files, and warming caches.
- Liveness probe (health check): Liveness probes determine whether or not an application running in a container is healthy. If the liveness probe detects an unhealthy state, then Kubernetes kills the container and tries to redeploy it.
To see all fields which can be configured, see the following reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#probe-v1-core
Implementing your own Health Indicator
To create your health indicator for Spring Actuator, you must create a Java class that implements the HealthIndicator interface provided by Spring Boot. This interface has a single method called by the Actuator to check the health of your application. In this method, you can perform any checks you want to determine the health of your application and return an Health object that reflects the result of those checks.
Here is an example implementation of a HealthIndicator
@Component
public class MyHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// Perform some specific health check
int errorCode = check();
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
private int check() {
// Perform some health check and return an error code
// (0 if the check is successful, non-zero if there is an error)
}
}You can then access the health information provided by your health indicator by requesting the /actuator/health endpoint on your application. This endpoint will return a JSON object that includes the health status of all registered health indicators, including your own. This will look similar to the following example:
{
"status": "UP",
"components": {
"aluna": {
"status": "UP",
"details": {
"commandsTotal": 10,
"productionMode": false,
"currentActiveInteractions": 0,
"currentActiveInteractionTimeouts": 0,
"interactionObserver": {
"buttons": 0,
"string_select": 0,
"entity_select": 0,
"modal": 0
},
"shardsTotal": 1,
"shards": [
{
"id": 0,
"status": "CONNECTED",
"serverCount": 1
}
]
}
},
"diskSpace": {
"status": "UP",
...
},
"ping": {
"status": "UP"
}
}
}For more information about health indicators and the HealthIndicator interface, you can check out the Spring Boot documentation.
Graceful Shutdown
At this point, ensure you have set a graceful shutdown for your Spring Boot application. This feature will help you with the lifecycle of applications and containers in Kubernetes. Generally, a graceful shutdown is preferable for any application that saves its state. When the standard shutdown procedures are not done with the graceful shutdown, the result can be data corruption of your program and operating system files. The corruption can result in instability, incorrect functioning or failure to boot.
To enable graceful shutdown, configure the server.shutdown property, as shown in the following example:
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=20sSee the following reference for more details: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/spring-boot-features.html#boot-features-graceful-shutdown
Explanation — Why do you need health checks?
Software architecture must be monitorable, allowing for the ongoing supervision of its condition. By ongoing, we don’t mean a dedicated admin, a site reliability engineer, or a DevOps professional to be assigned to constantly check the health of a service 8 hours a day, 365 days a year. There is a lot of space for automation here, but the process always starts with some indicator, triggering further actions.
Health checks can serve as such agents since they indicate the general state of the microservices and their dependencies.
Having health checks exposed, the dedicated monitoring software can periodically check on them. As a result, the engineering team has information about the solutions’ architecture elements experiencing downtimes or malfunctions. This should be subject to automated reactions.
What reactions can it trigger? — For example, a load balancer redirecting traffic to another service, a container orchestrator attempting to restart the unresponsive backend service, or even sending emails to the people responsible for specific processes can’t be easily and automatically diagnosed and recovered.
References, Useful links
- Configure Liveness, Readiness and Startup Probes
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ - Part V. Spring Boot Actuator: Production-ready features
https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/production-ready.html - Docker Docs, Healthcheck (Dockerfile)
https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck - Docker Docs, Healthcheck (Docker Compose)
https://docs.docker.com/engine/reference/builder/#healthcheck - Liveness and Readiness Probes with Spring Boot
https://spring.io/blog/2020/03/25/liveness-and-readiness-probes-with-spring-boot
Feedback and updates matter 📝☕. Enjoy my articles? Show support with claps, follows, and coffee donations. I keep all content regularly updated.
Support: ko-fi.com/niksta | Discord: devhotel.io
Disclosure: This article was assisted by ChatGPT (OpenAI) and refined using Grammarly for spelling and style. Visuals created with Midjourney’s AI tool.

