advanced~4h

Spring Boot on Kubernetes: Health Probes, Config, Scaling & Observability

Running Spring Boot in Kubernetes well requires integrating with five areas: health probes (Spring Actuator /health/liveness and /health/readiness mapping exactly to Kubernetes probe types), configura

Running Spring Boot in Kubernetes well requires integrating with five areas: health probes (Spring Actuator /health/liveness and /health/readiness mapping exactly to Kubernetes probe types), configuration management (ConfigMaps and Secrets as environment variables or volume-mounted files), graceful shutdown (server.shutdown: graceful + terminationGracePeriodSeconds), Prometheus metrics via Micrometer, and resource sizing based on real JVM heap and non-heap memory measurement rather than guessing.

  • Spring Boot Actuator exposes /actuator/health with sub-endpoints: /actuator/health/liveness (should the container restart?) and /actuator/health/readiness (should this Pod receive traffic?). Map these directly to livenessProbe and readinessProbe.

  • Startup probe uses /actuator/health/liveness with a long initialDelaySeconds or failureThreshold -- prevents liveness killing the Pod before initial startup completes (JVM warm-up, data loading).

  • ConfigMaps mount as environment variables (envFrom: configMapRef) or as files (volumeMounts to a directory the application reads). Secrets mount identically but for sensitive values.

  • server.shutdown: graceful + spring.lifecycle.timeout-per-shutdown-phase: 20s gives Spring Boot time to finish in-flight requests. Pair with terminationGracePeriodSeconds on the Pod spec (longer than the graceful shutdown timeout).

  • Micrometer with micrometer-registry-prometheus adds auto-instrumented JVM, HTTP, and Tomcat metrics on /actuator/prometheus in Prometheus text format.

  • JVM memory sizing: Kubernetes limits set the container ceiling. JVM calculates MaxHeapSize as a fraction of available memory by default (-XX:MaxRAMPercentage=75 is a common starting point), leaving room for non-heap (metaspace, direct buffers, code cache).

  • Add spring-boot-starter-actuator and micrometer-registry-prometheus to pom.xml/build.gradle.

  • Configure management.endpoint.health.probes.enabled: true and management.health.livenessState.enabled/readinessState.enabled.

  • Map /actuator/health/liveness to livenessProbe and /actuator/health/readiness to readinessProbe in the Deployment.

  • Add startup probe with high failureThreshold for long JVM startup (data loading, connection pool warm-up).

  • Configure ConfigMaps for non-sensitive app config and Secrets for DB passwords, API keys.

  • Set server.shutdown: graceful and terminationGracePeriodSeconds (longer than the shutdown timeout).

  • Set -XX:MaxRAMPercentage=75 as JVM option; set container memory request and limit to control total JVM memory.

  • Zero-downtime rolling deploys of Spring Boot microservices via readiness probe gating.

  • Startup probe preventing liveness restarts during a data-loading Spring Boot application's 90-second startup.

  • Micrometer metrics feeding Grafana dashboards with JVM heap, GC pause times, and HTTP request latency P99.

  • ConfigMap-driven feature flags that can be updated and re-mounted without rolling a new container image.

  • Always define all three probe types: startup, liveness, and readiness -- each serves a distinct purpose.

  • Use /actuator/health/liveness for liveness (not /actuator/health which includes readiness indicators).

  • Set terminationGracePeriodSeconds to at least 10s more than spring.lifecycle.timeout-per-shutdown-phase.

  • Use -XX:MaxRAMPercentage rather than explicit -Xmx to automatically scale heap with container memory limits.

  • Using /actuator/health (aggregate) for the liveness probe -- a Down database will cause Pods to restart unnecessarily.

  • Setting terminationGracePeriodSeconds equal to or shorter than the graceful shutdown timeout -- SIGKILL arrives before drain completes.

  • Not setting JVM memory flags -- JVM may see node physical memory (much larger than container limit) and set heap too large.

  • Forgetting startup probe -- liveness probe kills the Pod during the JVM's normal startup window if initialDelaySeconds is too short.

  • Use GraalVM native image for Spring Boot applications with strict cold-start latency requirements.

  • Use Spring Boot's lazy initialization (spring.main.lazy-initialization: true) to reduce startup time at the cost of first-request latency.

  • Use -XX:+UseG1GC or -XX:+ZGC based on heap size and GC pause tolerance.

  • Run at least 2 replicas of every Spring Boot production service -- single-replica services have zero fault tolerance.

  • Set PodDisruptionBudget (minAvailable: 1) so node drain does not take the only instance offline.

  • Monitor JVM heap utilization and GC metrics (micrometer JVM metrics) in Grafana for memory pressure detection.

  • Deploy a Spring Boot application and confirm that Kubernetes invokes /actuator/health/liveness and /actuator/health/readiness as probes.

  • Simulate a graceful shutdown by running kubectl delete pod and observing that in-flight requests complete before the process exits.

  • View JVM metrics in Prometheus/Grafana after deploying micrometer-registry-prometheus.

  • Map Spring Actuator /health/liveness to livenessProbe and /health/readiness to readinessProbe exactly.

  • Startup probe prevents liveness from killing the Pod during normal JVM startup.

  • server.shutdown: graceful + terminationGracePeriodSeconds > shutdown timeout = zero-downtime deploys.

  • Use -XX:MaxRAMPercentage=75 to scale JVM heap automatically with container memory limits.

  • Micrometer + Prometheus provides full JVM, HTTP, and GC observability with no manual instrumentation.

Want a visual for this concept?

Generate a diagram tailored to “Spring Boot on Kubernetes: Health Probes, Config, Scaling & Observability” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to Production: HA, DR, Namespace Strategy & Cluster Hardening← Back to all Kubernetes chapters