From a8d204559fabac052682db31c229527e3ff75266 Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Mon, 27 Nov 2023 16:17:31 +0900 Subject: [PATCH 1/2] Add Dockerfile --- Dockerfile | 22 +++++++++++++++++ README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ entrypoint.sh | 24 +++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 Dockerfile create mode 100755 entrypoint.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..610a089 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM azul/zulu-openjdk:21-jdk-crac-latest as builder +WORKDIR application + +ADD ./.mvn .mvn/ +ADD ./mvnw mvnw +ADD ./pom.xml pom.xml +ADD ./src src/ +ADD ./.git .git/ +RUN ./mvnw -V clean package -DskipTests --no-transfer-progress && \ + cp target/*.jar application.jar && \ + java -Djarmode=layertools -jar application.jar extract + +FROM azul/zulu-openjdk:21-jdk-crac-latest +WORKDIR application + +COPY --from=builder application/dependencies/ ./ +COPY --from=builder application/spring-boot-loader/ ./ +COPY --from=builder application/snapshot-dependencies/ ./ +COPY --from=builder application/application/ ./ +COPY entrypoint.sh ./ + +ENTRYPOINT ["/application/entrypoint.sh"] diff --git a/README.md b/README.md index 1dbf7b9..5b7727e 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,68 @@ jcmd target/example-spring-boot-0.0.1-SNAPSHOT.jar JDK.checkpoint ``` $JAVA_HOME/bin/java -XX:CRaCRestoreFrom=cr ``` + +## Docker image + +### Building + +Create a Docker image using the provided [`Dockerfile`](./Dockerfile) with the following command: + +``` +docker build -t example-spring-boot . +``` + +### Running + +Run the built Docker image with the following command: + +``` +docker run -p 8080:8080 \ + --cap-add CHECKPOINT_RESTORE \ + --cap-add NET_ADMIN \ + --cap-add SYS_PTRACE \ + --cap-add SYS_ADMIN \ + -v /tmp/crac:/var/crac \ + -e CHECKPOINT_RESTORE_FILES_DIR=/var/crac \ + --rm \ + example-spring-boot +``` + +The following logs will be outputted. A Checkpoint is created 10 seconds after the application starts. This time can be changed with the `SLEEP_BEFORE_CHECKPOINT` environment variable in [`entrypoint.sh`](./entrypoint.sh). + +``` + . ____ _ __ _ _ + /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ +( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ + \\/ ___)| |_)| | | | | || (_| | ) ) ) ) + ' |____| .__|_| |_|_| |_\__, | / / / / + =========|_|==============|___/=/_/_/_/ + :: Spring Boot :: (v3.2.0) + +2023-11-27T07:51:47.375Z INFO 8 --- [ main] com.example.springboot.Application : Starting Application v0.0.1-SNAPSHOT using Java 21.0.1 with PID 8 (/application/BOOT-INF/classes started by root in /application) +2023-11-27T07:51:47.378Z INFO 8 --- [ main] com.example.springboot.Application : No active profile set, falling back to 1 default profile: "default" +2023-11-27T07:51:48.138Z INFO 8 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2023-11-27T07:51:48.146Z INFO 8 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2023-11-27T07:51:48.146Z INFO 8 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.16] +2023-11-27T07:51:48.176Z INFO 8 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2023-11-27T07:51:48.177Z INFO 8 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 747 ms +2023-11-27T07:51:48.459Z INFO 8 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '' +2023-11-27T07:51:48.471Z INFO 8 --- [ main] com.example.springboot.Application : Started Application in 1.433 seconds (process running for 1.673) +Picked up JAVA_TOOL_OPTIONS: -XX:+ExitOnOutOfMemoryError +8: +2023-11-27T07:51:57.048Z INFO 8 --- [Attach Listener] jdk.crac : Starting checkpoint +CR: Checkpoint ... +/application/entrypoint.sh: line 13: 8 Killed java -XX:CRaCCheckpointTo=$CHECKPOINT_RESTORE_FILES_DIR org.springframework.boot.loader.launch.JarLauncher +2023-11-27T07:52:00.491Z INFO 8 --- [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore +2023-11-27T07:52:00.494Z INFO 8 --- [Attach Listener] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '' +2023-11-27T07:52:00.495Z INFO 8 --- [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed (restored JVM running for 30 ms) +``` + +Stop the docker with Ctrl+C, and run the same image again with the same command. This time, logs like the following will be outputted due to the restore. You can see that the JVM starts very quickly. + +``` +Restore checkpoint from /var/crac +2023-11-27T07:52:19.196Z INFO 8 --- [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore +2023-11-27T07:52:19.199Z INFO 8 --- [Attach Listener] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '' +2023-11-27T07:52:19.200Z INFO 8 --- [Attach Listener] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed (restored JVM running for 32 ms) +``` diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..fb27708 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,24 @@ +#!/bin/bash +mkdir -p $CHECKPOINT_RESTORE_FILES_DIR +export JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS} -XX:+ExitOnOutOfMemoryError" + +if [ ! -f "$CHECKPOINT_RESTORE_FILES_DIR/files.img" ]; then + echo "Save checkpoint to $CHECKPOINT_RESTORE_FILES_DIR" 1>&2 + java -XX:CRaCCheckpointTo=$CHECKPOINT_RESTORE_FILES_DIR org.springframework.boot.loader.launch.JarLauncher & + sleep ${SLEEP_BEFORE_CHECKPOINT:-10} + jcmd org.springframework.boot.loader.launch.JarLauncher JDK.checkpoint + sleep ${SLEEP_AFTER_CHECKPOINT:-3} +else + echo "Restore checkpoint from $CHECKPOINT_RESTORE_FILES_DIR" 1>&2 +fi + +(echo 128 > /proc/sys/kernel/ns_last_pid) 2>/dev/null || while [ $(cat /proc/sys/kernel/ns_last_pid) -lt 128 ]; do :; done +java -XX:CRaCRestoreFrom=$CHECKPOINT_RESTORE_FILES_DIR & +JAVA_PID=$! + +stop_java_app() { + kill -SIGTERM $JAVA_PID +} + +trap stop_java_app SIGINT +wait $JAVA_PID From 85184d31533bf957c330d60fc70fd50b392214cd Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Mon, 27 Nov 2023 17:12:01 +0900 Subject: [PATCH 2/2] Tweak --- entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entrypoint.sh b/entrypoint.sh index fb27708..53f2359 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,7 +2,7 @@ mkdir -p $CHECKPOINT_RESTORE_FILES_DIR export JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS} -XX:+ExitOnOutOfMemoryError" -if [ ! -f "$CHECKPOINT_RESTORE_FILES_DIR/files.img" ]; then +if [ -z "$(ls $CHECKPOINT_RESTORE_FILES_DIR/core-*.img 2>/dev/null)" ]; then echo "Save checkpoint to $CHECKPOINT_RESTORE_FILES_DIR" 1>&2 java -XX:CRaCCheckpointTo=$CHECKPOINT_RESTORE_FILES_DIR org.springframework.boot.loader.launch.JarLauncher & sleep ${SLEEP_BEFORE_CHECKPOINT:-10}