Cloud Native 13 min read

Achieve Zero‑Downtime Deployments with K8s and Spring Boot: Health Checks, Rolling Updates, and Autoscaling

This guide explains how to combine Kubernetes and Spring Boot to implement zero‑downtime releases by configuring readiness and liveness probes, defining graceful shutdown, applying rolling update strategies, setting up horizontal pod autoscaling, integrating Prometheus monitoring, and separating configuration via ConfigMaps for reusable images.

Programmer DD
Programmer DD
Programmer DD
Achieve Zero‑Downtime Deployments with K8s and Spring Boot: Health Checks, Rolling Updates, and Autoscaling

Zero‑Downtime Deployment with K8s and Spring Boot

Health Check

Readiness probe + Liveness probe

Probe types: exec, tcpSocket, httpGet

Business Layer

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

Define access port, path and permissions in application.yaml:

management:
  server:
    port: 50000  # enable independent management port
  endpoint:
    health:
      probes:
        enabled: true
  endpoints:
    web:
      exposure:
        base-path: /actuator
        include: health

Expose the following endpoints:

http://127.0.0.1:50000/actuator/health/readiness
http://127.0.0.1:50000/actuator/health/liveness

Operations Layer

K8s deployment template ( deployment.yaml) with probes:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: {APP_NAME}
        image: {IMAGE_URL}
        ports:
        - containerPort: {APP_PORT}
        - name: management-port
          containerPort: 50000
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: management-port
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 1
          successThreshold: 1
          failureThreshold: 6
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: management-port
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 1
          successThreshold: 1
          failureThreshold: 6

Rolling Update

Rolling update strategy to achieve zero‑downtime releases:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {APP_NAME}
spec:
  selector:
    matchLabels:
      app: {APP_NAME}
  replicas: {REPLICAS}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1

Graceful Shutdown

Enable graceful shutdown in Spring Boot and expose the shutdown endpoint:

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
server:
  port: 8080
  shutdown: graceful
management:
  server:
    port: 50000
  endpoint:
    shutdown:
      enabled: true
  health:
    probes:
      enabled: true
  endpoints:
    web:
      exposure:
        base-path: /actuator
        include: health,shutdown

Call the shutdown endpoint:

curl -X POST 127.0.0.1:50000/actuator/shutdown

Operations Layer

Dockerfile template (ensure curl is installed):

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ARG WORK_PATH="/app"
ARG EXPOSE_PORT=8080
ENV JAVA_OPTS=""
ENV JAR_FILE=${JAR_FILE}
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' > /etc/timezone \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
    && apk add --no-cache curl
COPY target/$JAR_FILE $WORK_PATH/
WORKDIR $WORK_PATH
EXPOSE $EXPOSE_PORT
ENTRYPOINT exec java $JAVA_OPTS -jar $JAR_FILE

Autoscaling

Define resource limits and create a HorizontalPodAutoscaler:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: {APP_NAME}
        resources:
          limits:
            cpu: 0.5
            memory: 1Gi
          requests:
            cpu: 0.15
            memory: 300Mi
---
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta2
metadata:
  name: {APP_NAME}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {APP_NAME}
  minReplicas: {REPLICAS}
  maxReplicas: 6
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

Prometheus Integration

Dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Configure Prometheus endpoints:

management:
  server:
    port: 50000
  metrics:
    tags:
      application: ${spring.application.name}
  endpoints:
    web:
      exposure:
        base-path: /actuator
        include: metrics,prometheus

Expose /actuator/metric and /actuator/prometheus:

http://127.0.0.1:50000/actuator/metric
http://127.0.0.1:50000/actuator/prometheus

Annotate pods for Prometheus scraping:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        prometheus.io/port: "50000"
        prometheus.io/path: /actuator/prometheus
        prometheus.io/scrape: "true"

Config Separation

Generate a ConfigMap from an external application-test.yaml file:

# Generate ConfigMap YAML (dry‑run)
kubectl create cm -n <namespace> <APP_NAME> --from-file=application-test.yaml --dry-run=1 -o yaml > configmap.yaml
# Apply the ConfigMap
kubectl apply -f configmap.yaml

Mount the ConfigMap and activate a profile:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      env:
      - name: SPRING_PROFILES_ACTIVE
        value: test
      volumeMounts:
      - name: conf
        mountPath: "/app/config"
        readOnly: true
      volumes:
      - name: conf
        configMap:
          name: {APP_NAME}

Summary Configuration

Combined dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

Unified application.yaml settings:

spring:
  application:
    name: project-sample
  profiles:
    active: @profileActive@
  lifecycle:
    timeout-per-shutdown-phase: 30s
server:
  port: 8080
  shutdown: graceful
management:
  server:
    port: 50000
  metrics:
    tags:
      application: ${spring.application.name}
  endpoint:
    shutdown:
      enabled: true
    health:
      probes:
        enabled: true
  endpoints:
    web:
      exposure:
        base-path: /actuator
        include: health,shutdown,metrics,prometheus

Dockerfile (same as above) and final deployment.yaml include readiness/liveness probes, resource limits, autoscaling, and Prometheus annotations.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

autoscalingPrometheusSpring BootZero Downtimehealth checkRolling Update
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.