Cloud Native 11 min read

How to Accelerate Spring Boot Startup on Kubernetes Using CRaC

This guide walks through enabling CRaC in a Spring Boot application, building a CRaC‑compatible Docker image, creating a checkpoint job in Kubernetes, restoring the snapshot at pod start, and comparing the startup speed with GraalVM native compilation.

Linyb Geek Road
Linyb Geek Road
Linyb Geek Road
How to Accelerate Spring Boot Startup on Kubernetes Using CRaC

In this article you will learn how to use Checkpoint/Restore (CRaC) to dramatically reduce Java startup time for a Spring Boot service running on Kubernetes.

What is CRaC?

CRaC (Checkpoint/Restore) is an OpenJDK project introduced by Azul in 2020. It takes a memory snapshot of a running Java process and later restores it, leveraging the Linux CRIU feature. It currently works only on Linux.

Prerequisites

Assume Azul Zulu OpenJDK 17 with built‑in CRaC support is installed on a Linux host.

Creating a checkpoint

Run the application with the checkpoint flag:

$ java -XX:CRaCCheckpointTo=/crac-files -jar target/sample-app.jar

Then trigger the checkpoint from another terminal: $ jcmd target/sample-app.jar JDK.checkpoint The command creates a snapshot in /crac-files. A log file dump4.log records the operation.

Restoring the snapshot

Start the application from the snapshot: $ java -XX:CRaCRestoreFrom=/crac-files The startup time drops from seconds to a few milliseconds.

Enabling CRaC for Spring Boot

Spring Boot does not support CRaC out of the box. By replacing the default Tomcat embed with a CRaC‑compatible version, the checkpoint can succeed. Add the following Maven dependencies and exclude the original Tomcat core:

<dependency>
  <groupId>io.github.crac.org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-core</artifactId>
  <version>10.1.7</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Rebuild the application with the CRaC profile:

$ mvn clean package -Pcrac

Building a CRaC‑compatible Docker image

Create a Dockerfile that uses the Azul Zulu OpenJDK 17 image with CRaC support and copies the built uber‑JAR and an entrypoint script:

FROM azul/zulu-openjdk:17-jdk-crac-latest
COPY target/callme-service-1.1.0.jar /app/callme-service-1.1.0.jar
COPY src/scripts/entrypoint.sh /app/entrypoint.sh
RUN chmod 755 /app/entrypoint.sh

The entrypoint.sh script starts the JVM, waits, runs jcmd to create the checkpoint, and then sleeps:

#!/bin/bash
java -XX:CRaCCheckpointTo=/crac -jar /app/callme-service-1.1.0.jar &
sleep 10
jcmd /app/callme-service-1.1.0.jar JDK.checkpoint
sleep 10

Persisting the checkpoint in Kubernetes

Create a PersistentVolumeClaim to store the snapshot:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: crac-store
  namespace: crac
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 10Gi

Define a Kubernetes Job that runs the image, executes the entrypoint script, and mounts the PVC. The job needs privileged security context because CRaC requires elevated permissions:

apiVersion: batch/v1
kind: Job
metadata:
  name: callme-service-snapshot-job
  namespace: crac
spec:
  template:
    spec:
      containers:
        - name: callme-service
          image: callme-service:1.1.0
          env:
            - name: VERSION
              value: "v1"
          command: ["/bin/sh", "-c", "/app/entrypoint.sh"]
          volumeMounts:
            - mountPath: /crac
              name: crac
          securityContext:
            privileged: true
      volumes:
        - persistentVolumeClaim:
            claimName: crac-store
          name: crac
      restartPolicy: Never
      backoffLimit: 3

Apply the job with kubectl apply -f job.yaml. When the pod reaches Completed, the checkpoint is ready.

Deploying the restored service

Deploy three replicas that start the JVM with the restore flag and mount the same PVC:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: callme-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: callme-service
  template:
    metadata:
      labels:
        app: callme-service
    spec:
      containers:
        - name: callme-service
          image: callme-service:1.1.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
          env:
            - name: VERSION
              value: "v1"
          command: ["java"]
          args: ["-XX:CRaCRestoreFrom=/crac"]
          volumeMounts:
            - mountPath: /crac
              name: crac
          readinessProbe:
            initialDelaySeconds: 0
            periodSeconds: 1
            httpGet:
              path: /actuator/health/readiness
              port: 8080
          securityContext:
            privileged: true
          resources:
            limits:
              cpu: '1'
      volumes:
        - name: crac
          persistentVolumeClaim:
            claimName: crac-store

Apply with kubectl apply -f deployment-crac.yaml and observe the pods become ready quickly, allowing a direct comparison of startup latency with and without CRaC.

Comparison with GraalVM

Unlike GraalVM native images, which reduce startup time but increase memory usage and impose stricter limitations, CRaC offers fast startup without a full native compilation step. However, CRaC requires managing snapshot images and mounting persistent volumes for each pod.

Conclusion

CRaC provides a viable alternative to GraalVM for achieving near‑instant Java startup in Kubernetes. It adds operational steps—creating and persisting snapshots—but gives developers another tool for optimizing cold‑start latency.

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.

DockerKubernetesSpring BootGraalVMCRaCAzul ZuluJava startup
Linyb Geek Road
Written by

Linyb Geek Road

Tech notes

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.