How to Containerize Your Spring Boot Application for Rapid Startup
Containerize Spring Boot apps to start up in milliseconds, without compromise and with little or no refactoring of your code.
Join the DZone community and get the full member experience.
Join For FreeDid you know you can containerize your Spring Boot applications to start up in milliseconds, without compromising on throughput, memory, development-production parity, or Java language features? And with little or no refactoring of the application code? Here’s how with Open Liberty 23.0.0.10-beta.
Liberty Instanton
The InstantOn capability in the Open Liberty runtime uses the IBM Semeru JDK and a Linux technology called Checkpoint/Restore in Userspace (CRIU) to take a checkpoint, or a point-in-time snapshot, of the application process. This checkpoint can then be restored very quickly to bring the application process back into the state it was in when the checkpoint was taken. The application can be restored multiple times because Open Liberty and the Semeru JDK preserve the uniqueness of each restored process in containers. Each restored application process runs without first having to go through the whole startup sequence, saving up to 90% of startup time (depending on your application). InstantOn requires very little modification of your Java application to make this improvement happen.
For more information about Liberty InstantOn, see the How to package your cloud-native Java application for rapid Startup blog and Faster startup for containerized applications with Open Liberty InstantOn in the Open Liberty docs.
Spring Boot Support for Checkpoint/Restore
The Spring Framework version 6.1 release will integrate with JVM checkpoint/restore by using the org. crac project to allow capable systems to reduce the startup times of Spring-based Java applications. With Liberty InstantOn 23.0.0.10-beta, you can configure a new crac-1.3 feature to provide an implementation of the org. crac API that integrates with Liberty InstantOn. This allows Spring-based applications, including Spring Boot applications, to be deployed with Liberty InstantOn to achieve rapid startup times.
Production-Ready Liberty Container Images
New Universal Base Image container images are uploaded to the IBM Container Registry for each new release of Liberty. Starting with the 23.0.0.6 Liberty release, the Liberty UBI container images include the necessary prerequisites to checkpoint your applications with Liberty InstantOn. And now, starting with the 23.0.0.10-beta release, the UBI beta container image also includes the prerequisites to checkpoint your Spring Boot 3.2-based applications.
This beta release includes an implementation of the org. crac APIs with the Liberty beta feature crac-1.3. The crack-1.3 feature, along with the Spring Framework version 6.1 support for org. crack, allows you to checkpoint your Spring-based applications with Liberty InstantOn to achieve rapid startup times.
The Liberty container images make it easy to develop InstantOn applications that are ready to deploy into production. An important benefit of using Liberty InstantOn is the ability to do a checkpoint of the application process inside the container without requiring the root user to run the application process in the container. It is important, from a security perspective, to avoid running the application process in the container as the root user. This allows you to deploy your InstantOn container images to existing Kubernetes services like AWS EKS and Azure EKS.
Spring Boot 3.2.0 Example Using Liberty Instanton
This example uses the Containerizing, packaging, and running of a Spring Boot application Open Liberty guide to demonstrate using Liberty InstantOn with a Spring Boot 3.2.0-based application. The fastest way to get up and running is to clone the cracSpringBoot branch from the guide's GitHub repository:
git clone --branch cracSpringBoot https://github.com/openliberty/guide-spring-boot.git
cd guide-spring-boot/finish
The cracSpringBoot branch updates the guide to use the Open Liberty beta and Spring Boot version 3.2.0-M1, which contains the initial support of org. crack for Spring Boot applications. To build and run the example Spring Boot application, you must be using Java 17 or higher.
After cloning the cracSpringBoot branch of the guide's repository, the first step is to build the Spring Boot application. Build the application by running the mine command provided with the project finish/ folder:
./mvnw package
After building the Spring Boot application, the next step is to containerize it. We focus here on changes to containerize the application with Liberty InstantOn. If you want more information about how to best containerize Spring Boot applications with Open Liberty, read through the Containerizing, packaging, and Running a Spring Boot application guide.
To build the application container image with InstantOn, you must be able to either run a privileged container or grant the container image build engine the necessary Linux capabilities to do the checkpoint.
Enabling the crac-1.3 Liberty Feature
Liberty is composed of features that you enable according to the requirements of your application. To use Liberty's implementation of org. crack, you must enable the crac-1.3 feature in the Liberty configuration. For this example, we can do that by copying the src/main/liberty/config/crac.xml file into the container image with the following Dockerfile command:
COPY src/main/liberty/config/crac.xml /config/configDropins/defaults
The crac.xml Liberty configuration file enables the crac-1.3 feature with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<server description="Enable the org.crac API">
<featureManager>
<feature>crac-1.3</feature>
</featureManager>
</server>
Building With Podman
With Podman, the container image build engine can be granted the necessary Linux capabilities to checkpoint the application during the container image build. This allows you to run the checkpoint.sh script as a RUN instruction, as specified in the Dockerfile. postman file. This is the last instruction of the Dockerfile. postman file, as shown in the following example:
...
RUN configure.sh
RUN checkpoint.sh afterAppStart
To grant the necessary capabilities to the Podman container image build engine, run the following command as root or with sudo:
sudo podman build \
-f Dockerfile.podman \
-t springboot \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=SYS_PTRACE\
--cap-add=SETPCAP \
--security-opt seccomp=unconfined .
You can run the previous command or run the provided scripts/build-instanton-postman.sh script to build the application container image.
During the build, the last thing done is to run the checkpoint.sh script by using the afterAppStart option. This causes the checkpoint to happen after the application is started.
You see the following output when the application has started:
[AUDIT ] CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 3.880 seconds.
[AUDIT ] CWWKC0451I: A server checkpoint "afterAppStart" was requested. When the checkpoint completes, the server stops.
2023-09-06T21:06:18.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping Spring-managed lifecycle beans before JVM checkpoint
2023-09-06T21:06:18.767Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2023-09-06T21:06:18.768Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Bean 'applicationTaskExecutor' completed its stop procedure
2023-09-06T21:06:18.769Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147482623
2023-09-06T21:06:18.771Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Bean 'webServerGracefulShutdown' completed its stop procedure
2023-09-06T21:06:18.771Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147481599
2023-09-06T21:06:18.796Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Bean 'webServerStartStop' completed its stop procedure
2023-09-06T21:06:18.796Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase -2147483647
2023-09-06T21:06:18.797Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Bean 'springBootLoggingLifecycle' completed its stop procedure
[2/2] COMMIT springboot
The debug output from the Spring Framework shows the Lifecycle beans in the application were stopped to prepare for the checkpoint. At this point, you have an application container image called springboot that can be run to restore the application process.
Building With Docker
At this time, Docker does not allow you to grant the container image build engine the Linux capabilities necessary to perform an application checkpoint. This prevents you from running the checkpoint.sh script doing the docker build command. Instead, you need to use a three-step approach:
- Build the application container image without the InstantOn layer.
- Run the application container to perform a checkpoint of the application.
- Commit the stopped container with the checkpoint process data into an InstantOn application container image.
Complete these three build steps by running the scripts/build-instanton-docker.sh script. The resulting output is similar to the checkpoint during the Podman build. You will notice some debug output from the Spring Framework for the lifecycle beans. At this point, you have an application container image called springboot that can be run to restore the application process.
Run the Instanton Spring Boot Application
Both Podman and Docker can use the same options to run the Springboot InstantOn application:
[sudo podman or docker] run \
--rm \
-p 9080:9080 \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=SETPCAP \
--security-opt seccomp=unconfined \
springboot
You can run the previous command or run the provided scripts/run-instanton-postman.sh or scripts/run-instanton-docker.sh script to run the application container image.
You see the following output when the application process is restored:
[AUDIT ] Launching defaultServer (Open Liberty 23.0.0.10-beta/wlp-1.0.81.cl230920230904-1158) on Eclipse OpenJ9 VM, version 17.0.7+7 (en_US)
2023-09-07T15:22:52.683Z INFO 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Restarting Spring-managed lifecycle beans after JVM restore
2023-09-07T15:22:52.684Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147483647
2023-09-07T15:22:52.684Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'springBootLoggingLifecycle'
2023-09-07T15:22:52.685Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147481599
[AUDIT ] CWWKT0016I: Web application available (default_host): http://e93ebe585ce3:9080/
2023-09-07T15:22:52.759Z INFO 118 --- [ecutor-thread-1] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 106109 ms
2023-09-07T15:22:52.762Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'webServerStartStop'
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147482623
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'webServerGracefulShutdown'
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2023-09-07T15:22:52.763Z DEBUG 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'applicationTaskExecutor'
2023-09-07T15:22:52.764Z INFO 118 --- [ecutor-thread-1] o.s.c.support.DefaultLifecycleProcessor : Spring-managed lifecycle restart completed in 80 ms
[AUDIT ] CWWKC0452I: The Liberty server process resumed operation from a checkpoint in 0.263 seconds.
[AUDIT ] CWWKZ0001I: Application thin-guide-spring-boot-0.1.0 started in 0.265 seconds.
[AUDIT ] CWWKF0012I: The server installed the following features: [crac-1.3, expressionLanguage-5.0, pages-3.1, servlet-6.0, springBoot-3.0, ssl-1.0, transportSecurity-1.0, websocket-2.1].
[AUDIT ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 0.277 seconds.
Notice the last message ... server started in 0.277 seconds. The 0.277-second startup time includes the time it took for Criu to restore the Java process as well as the Liberty runtime to restore the runtime state such that it can safely run the application once restored. Additional debug messages are enabled for the Spring Framework to show the default Spring lifecycle processor restoring the lifecycle beans in the application. This is a greater than 10x improvement in startup time when compared to the original startup time of 5.5+ seconds when not using InstantOn.
Summary
Liberty InstantOn can be applied to applications using open standards, such as Jakarta EE and MicroProfile, as well as Spring-based applications using the latest versions of Spring Boot and Spring Framework that have support for org. crack.
InstantOn application images will be ready to deploy into existing public clouds, such as AWS EKS and Azure AKS platforms.
Published at DZone with permission of Thomas Watson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments