Developer Playground

Spring Boot on EKS: Optimizing Health Probes for Efficient Deployments

Updated: May 8, 2025

When deploying Spring Boot applications on Amazon Elastic Kubernetes Service (EKS), managing application health is crucial for reliable service operations. Kubernetes provides three types of health probes—startup, liveness, and readiness—that work together to ensure your applications start correctly, remain responsive, and handle traffic appropriately.

However, one significant challenge is probe timing configuration. If probe settings are too conservative, deployment times become unnecessarily long, while overly aggressive settings can result in errors when the application receives traffic before it's fully ready.

This article focuses on configuring Spring Boot Actuator with basic probe settings and optimizing probe timing to match your application's actual startup time, minimizing deployment delays while maintaining service stability.

Understanding Kubernetes Probes

Kubernetes uses three distinct probe types to determine the health and availability of your containers:

Probe Types

  • Startup Probe: Determines whether the application has started successfully. Disables liveness and readiness checks until it succeeds.
  • Liveness Probe: Verifies if the application is running. If it fails, the container is restarted.
  • Readiness Probe: Checks if the container is ready to receive traffic. If it fails, the pod is removed from service endpoints.

Each probe can be configured with the following parameters:

  • initialDelaySeconds: Seconds after container starts before probe begins
  • periodSeconds: How often the probe runs (default: 10 seconds)
  • timeoutSeconds: Seconds after which probe times out (default: 1 second)
  • successThreshold: Minimum consecutive successes to consider probe successful (default: 1)
  • failureThreshold: Number of failures before giving up (default: 3)
Kubernetes Probe Flow Pod Container Spring Boot Application 1. Startup Probe: /actuator/health/startup 2. Liveness Probe: /actuator/health/liveness 3. Readiness Probe: /actuator/health/readiness Traffic

Spring Boot Actuator Setup

Spring Boot's Actuator provides health endpoints that integrate perfectly with Kubernetes probes:

1. Adding Actuator Dependency (Maven)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Gradle Configuration

implementation("org.springframework.boot:spring-boot-starter-actuator")

2. Configuring Health Endpoints

management:
  endpoint:
    health:
      probes:
        enabled: true
      show-details: always
      group:
        readiness:
          include: readinessState, db, redis, diskSpace
        liveness:
          include: livenessState
        startup:
          include: startupState
  endpoints:
    web:
      exposure:
        include: health

With this configuration, Spring Boot provides the following endpoints:

  • /actuator/health/readiness: Checks if the application and dependent services are ready to handle traffic
  • /actuator/health/liveness: Verifies the application is responsive
  • /actuator/health/startup: Confirms application initialization is complete

Optimizing Probe Timing for Actual Startup Time

When your application has an actual startup time of around 20 seconds, it's important to optimize probe settings accordingly. Overly conservative settings unnecessarily extend deployment time, while too aggressive settings may cause errors.

Measuring Actual Startup Time

Started Application in 19.329 seconds (JVM running for 20.412)

This information serves as the baseline for your probe timing configuration.

Startup Probe Configuration for ~20s Startup Time

startupProbe:
  httpGet:
    path: /actuator/health/startup
    port: 8080
  initialDelaySeconds: 5    # Start checking 5 seconds after container starts
  periodSeconds: 5          # Check every 5 seconds
  failureThreshold: 6       # Allow up to 6 failures (total 30 seconds)
  timeoutSeconds: 1         # 1 second timeout for each check

This configuration allows up to 35 seconds for startup (5s initial delay + 5s × 6 failures), providing a reasonable buffer over the typical 20-second startup time to accommodate occasional slower starts.

Optimizing Liveness & Readiness Probes

livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  periodSeconds: 20         # Check every 20 seconds
  failureThreshold: 3       # Restart after 3 consecutive failures
  timeoutSeconds: 3         # 3 second timeout

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  periodSeconds: 10         # Check every 10 seconds
  failureThreshold: 3       # Remove from service after 3 failures
  timeoutSeconds: 3         # 3 second timeout

Note the absence of initialDelaySeconds. Since these probes only activate after the Startup Probe succeeds, additional delays are unnecessary.

Deployment Timing Issues & Solutions

Several common issues can affect your deployment timing when using health probes:

Issue 1: Overly Conservative Probe Settings

Problem: When an application starts in 20 seconds but probe timeout is set to 5 minutes, deployment times are unnecessarily extended.

Solution: Set timeouts based on actual startup time plus a reasonable buffer (e.g., 50%). For a 20-second startup time, around 30 seconds is appropriate.

Optimized Startup Probe Settings

startupProbe:
  # 20s startup time + 10s buffer = 30s total allowance
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 5  # 5 × 5s = 25s (plus 5s initial delay for 30s total)

Issue 2: Startup Time Variations Under Load

Problem: Application startup time may vary with system load or resource constraints.

Solution:

  1. Test startup times under conditions similar to production
  2. Monitor and collect statistics on application startup times
  3. Set probe timeouts based on 95th percentile startup time

Issue 3: Dependency Initialization Delays

Problem: External dependencies like databases and caches can affect application startup time.

Solution:

  1. Check external dependency states in Readiness Probes
  2. Parallelize application startup and dependency initialization where possible
  3. Use asynchronous initialization patterns to reduce startup time

Hikari Connection Pool Configuration

# application.yml
spring:
  datasource:
    hikari:
      initialization-fail-timeout: 0  # Fail fast on connection failures to reduce startup time

Optimized Deployment Example

Here's a complete Kubernetes deployment manifest optimized for a Spring Boot application with approximately 20 seconds startup time:

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-service
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-boot-service
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0  # Set to 0 for zero-downtime deployments
  template:
    metadata:
      labels:
        app: spring-boot-service
    spec:
      containers:
      - name: spring-boot-service
        image: ${ECR_REPO}/spring-boot-service:${IMAGE_TAG}
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "1Gi"
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "production"
        # Startup Probe - optimized for ~20s startup time
        startupProbe:
          httpGet:
            path: /actuator/health/startup
            port: 8080
          initialDelaySeconds: 5    # Wait 5s after container starts
          periodSeconds: 5          # Check every 5s
          failureThreshold: 6       # Allow up to 6 failures (total 30s)
          timeoutSeconds: 1

        # Liveness Probe - checks application responsiveness
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          periodSeconds: 20
          failureThreshold: 3
          timeoutSeconds: 3

        # Readiness Probe - checks traffic readiness
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          periodSeconds: 10
          failureThreshold: 3
          timeoutSeconds: 3

        # Graceful shutdown handling
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 5"]  # Time for request draining

      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  name: spring-boot-service
  namespace: production
spec:
  selector:
    app: spring-boot-service
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

Monitoring & Tuning Deployment Times

After optimizing probe settings, it's important to monitor and continuously tune deployment times:

1. Measuring Deployment Time

# Start deployment
DEPLOY_START=$(date +%s)
kubectl apply -f deployment.yaml

# Wait for deployment completion
kubectl rollout status deployment/spring-boot-service -n production

# Deployment complete
DEPLOY_END=$(date +%s)
echo "Deployment took $((DEPLOY_END-DEPLOY_START)) seconds"

2. Monitoring Probe Failures

# Check for container restarts and probe failures
kubectl get events -n production | grep -E 'Unhealthy|Pulled|Started'

3. Incrementally Adjusting Probe Settings

Gradually adjust probe settings based on your measurements. Finding the right balance between deployment speed and stability is key.

  • If deployments are consistently successful and fast, you might reduce timeouts slightly
  • If occasional failures occur, increase timeouts incrementally
  • Document the correlation between startup times and probe settings for future reference

Conclusion

Optimizing probe timing for Spring Boot applications on EKS is crucial for balancing deployment speed and service stability. By accurately measuring your application's actual startup time (around 20 seconds in our example) and configuring probes accordingly, you can minimize unnecessary deployment delays while maintaining reliable service operations.

The basic Spring Boot Actuator health endpoints integrate seamlessly with Kubernetes probes, and with proper timing settings, you can build an efficient deployment pipeline.

Key takeaways:

  • Configure probe settings based on actual startup time plus a small buffer
  • Use Startup Probes to protect application initialization
  • Continuously monitor and optimize deployment times and probe settings
  • Find the right balance between speed and stability for your specific application

Advertisement