Spring Boot application with CRaC (Coordinated Restore at Checkpoint) support.
-
Run the
Dockerfile-crac-buildfiledocker build -f Dockerfile-crac-build -t my_app_on_crac . -
Inject secrets, e.g.
export ENV_SUPER_SECRET="flappy-bird"
-
Set up the JAR for snapshotting inside the crac-runner container, pulling in
ENV_SUPER_SECRETrm -rf crac-files/ && mkdir -p crac-files && docker run -d -e ENV_SUPER_SECRET=$ENV_SUPER_SECRET --cap-add=CHECKPOINT_RESTORE --cap-add=SYS_PTRACE --rm --name crac-runner -p 8080:8080 -v $PWD/crac-files:/opt/crac-files my_app_on_crac java -XX:CRaCCheckpointTo=/opt/crac-files -XX:+CRaCImageCompression -jar /opt/app/app.jar
-
While this Docker container is running, grab the PID of the running JAR file
docker exec crac-runner jcmd $(docker exec crac-runner jcmd | grep app.jar | cut -d' ' -f1) JDK.checkpoint
-
Now that we have a checkoint created, build the "runner" Docker image
docker build -f Dockerfile-crac-run -t my_app_crac_restore . -
Then, go ahead and run this in a named Docker container
docker run -d --rm --name crac-restore -p 8080:8080 my_app_crac_restore
-
Finally, let's test
curl --insecure localhost:8080/hello
You should see something like this:
{"message":"Hello, World! The secret word is: <whatever you injected>","timestamp":1743638777557}Additionally, the
Actuatorendpoint works as-expected:curl --insecure localhost:8080/actuator/health {"status":"UP","groups":["liveness","readiness"]}
Running from the fat-jar via Docker named container crac-runner
2025-04-02 20:33:19
2025-04-02 20:33:19 . ____ _ __ _ _
2025-04-02 20:33:19 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
2025-04-02 20:33:19 ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
2025-04-02 20:33:19 \\/ ___)| |_)| | | | | || (_| | ) ) ) )
2025-04-02 20:33:19 ' |____| .__|_| |_|_| |_\__, | / / / /
2025-04-02 20:33:19 =========|_|==============|___/=/_/_/_/
2025-04-02 20:33:19
2025-04-02 20:33:19 :: Spring Boot :: (v3.3.10)
2025-04-02 20:33:19
2025-04-02 20:33:19 2025-04-03T00:33:19.770Z INFO 129 --- [crac] [ main] c.b.crac.CracApplicationKt : Starting CracApplicationKt v0.0.1-SNAPSHOT using Java 21.0.6 with PID 129 (/opt/app/app.jar started by root in /)
2025-04-02 20:33:19 2025-04-03T00:33:19.771Z DEBUG 129 --- [crac] [ main] c.b.crac.CracApplicationKt : Running with Spring Boot v3.3.10, Spring v6.1.18
2025-04-02 20:33:19 2025-04-03T00:33:19.771Z INFO 129 --- [crac] [ main] c.b.crac.CracApplicationKt : No active profile set, falling back to 1 default profile: "default"
2025-04-02 20:33:20 2025-04-03T00:33:20.685Z INFO 129 --- [crac] [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint beneath base path '/actuator'
2025-04-02 20:33:20 2025-04-03T00:33:20.968Z INFO 129 --- [crac] [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080 (http)
2025-04-02 20:33:20 2025-04-03T00:33:20.981Z INFO 129 --- [crac] [ main] c.b.crac.CracApplicationKt : Started CracApplicationKt in 1.464 seconds (process running for 1.745)Running from named Docker container crac-restore
2025-04-02 20:34:49 Restoring from checkpoint...
2025-04-02 20:34:49 Restored from checkpoint
2025-04-02 20:34:49 2025-04-03T00:34:49.602Z INFO 129 --- [crac] [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore
2025-04-02 20:34:49 2025-04-03T00:34:49.616Z INFO 129 --- [crac] [Attach Listener] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080 (http)
2025-04-02 20:34:49 2025-04-03T00:34:49.618Z INFO 129 --- [crac] [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed (restored JVM running for 170 ms)- The checkpoint directory must exist and be writable
- Docker requires
--privilegedflag for CRaC capabilities (or other flags, as-specified above) - Checkpoint files are stored in ./crac-files