Speeding up the launch of Spring Boot applications in a container
Did you know that a Spring Boot application in a container can launch in milliseconds? At the same time, without compromising performance, memory, parity of development-production environments, without limiting the capabilities of the Java language, and almost without changing the application code. But how? Using Liberty 23.0.0.10-beta…
Liberty Instant On
Open Liberty’s InstantOn functionality uses IBM Semeru JDK and Linux technology Checkpoint/Restore in Userspace (CRIU), which allows you to take snapshots of the process state (snapshots, checkpoints) during execution. Subsequently, the condition is very quickly restored and work resumes. You can restore an application multiple times because Open Liberty and Semeru JDK preserve the uniqueness of each restored process in the container. Once the state is restored, the process does not need to initialize at startup, saving up to 90% of startup time (depending on your application). Using InstantOn requires minor changes to your Java application.
For more information about Liberty InstantOn, see the article How to package your cloud-native Java application for rapid startup and in the section Faster startup for containerized applications with Open Liberty InstantOn Open Liberty documentation.
Checkpoint/restore support in Spring Boot
Spring Framework 6.1 will integrate with JVM checkpoint/restore using the project org.crac, which will speed up the launch of applications. In Liberty InstantOn version 23.0.0.10-beta to get the implementation org.crac API you need to add the functional module (feature) crac-1.3. This will allow you to deploy Spring applications, including Spring Boot, using Liberty InstantOn.
Production-ready images of Liberty containers
Container images for all new Liberty releases are created based on Universal Base Image and uploaded to the repository IBM Container Registry. The Liberty UBI image as of Liberty 23.0.0.6 includes the necessary components to create application checkpoints using Liberty InstantOn. And from version 23.0.0.10-beta – also for Spring Boot 3.2.
Liberty images make it easy to develop InstantOn applications ready for production deployment. An important advantage of Liberty InstantOn is the ability to create application process checkpoints inside a container without the need to run the application in the container as root, which is important from a security point of view. This also allows deploy your InstantOn images in Kubernetes cloud services such as AWS EKS and Azure EKS.
Sample application on Spring Boot 3.2.0 using Liberty InstantOn
This example uses materials from the tutorial Containerizing, packaging, and running a Spring Boot application. The easiest way to get started is to clone the cracSpringBoot branch from the github repository with an example:
git clone --branch cracSpringBoot https://github.com/openliberty/guide-spring-boot.git
cd guide-spring-boot/finish
In the thread cracSpringBoot
newer versions of Open Liberty and Spring Boot are used that support org.crac
for Spring Boot applications. You will need Java 17 or later.
To build the application, let’s run mvnw
in folder finish
.
./mvnw package
Next we will containerize our application. We will only focus on the containerization changes associated with Liberty InstantOn. For more information on best practices for containerizing Spring Boot applications with Open Liberty, see the guide Containerizing, packaging, and running a Spring Boot application.
To create an image of an application that uses InstantOn, you must either run a privileged container or provide the image build tool with the necessary Linux capabilitiesallowing you to create control points.
Enabling crac-1.3 in Liberty
At Liberty, we can select only the components we need. For use org.crac
in Liberty, you need to add it to the Liberty configuration crac-1.3
. In this case, you can copy the file src/main/liberty/config/crac.xml
into the container image using the following command in the Dockerfile:
COPY src/main/liberty/config/crac.xml /config/configDropins/defaults
Enable crac-1.3 in the Liberty configuration crac.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<server description="Enable the org.crac API">
<featureManager>
<feature>crac-1.3</feature>
</featureManager>
</server>
Building an image using Podman
Podman allows you, when building an image, to specify the Linux capabilities necessary to create an application checkpoint, which will allow you to run checkpoint.sh using the command RUN
in Dockerfile. This is the last instruction in Dockerfile.podman
:
...
RUN configure.sh
RUN checkpoint.sh afterAppStart
To build the image, use the following command indicating the required capabilities:
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 also run the script scripts/build-instanton-podman.sh
from examples.
The last stage of image assembly is launch checkpoint.sh with parameter afterAppStart
. As a result, a checkpoint is created after the application starts. For other options for creating a control point, see documentation.
When you run the application, you will see the following result:
[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 logs show that the application was stopped to create a checkpoint. You now have an application container image called springboot
.
Building an image using Docker
Currently, Docker does not allow you to specify Linux capabilities
. For this reason we cannot run checkpoint.sh by doing docker build
. Instead we will use three-stage image build:
Let’s assemble the image without the InstantOn layer.
Let’s launch a container from the resulting image and create an application checkpoint.
Let’s save the container with the checkpoint into a new InstantOn image using commit.
Complete these three build steps by running the script scripts/build-instanton-docker.sh. The output when building via Docker is similar to that of Podman. In the log you will see messages from lifecycle beans.
Launching the application
Both Podman and Docker use the same startup options:
Files run-instanton-podman.sh And run-instanton-docker.sh:
[sudo podman or docker] run \
--rm \
-p 9080:9080 \
--cap-add=CHECKPOINT_RESTORE \
--cap-add=SETPCAP \
--security-opt seccomp=unconfined \
springboot
To start, you can use this command or one of the scripts: scripts/run-instanton-podman.sh
or scripts/run-instanton-docker.sh
.
When you run it, you will see the following output:
[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.
Please note the last message “… server started in 0.277 seconds
“. The startup time of 0.277 seconds includes both the time required criu
to restore the Java process, and the time required for Liberty to properly restore the runtime state to safely launch the application after restoration. As a result, we received more than ten times faster startup compared to the original 5.5+ seconds. without using InstantOn.
Summary
Open Liberty InstantOn provides a single runtime environment for deploying cloud-native applications with instant startup. Liberty InstantOn can be used with applications that use open standards such as Jakarta EE and MicroProfile, as well as Spring applications that use the latest versions of Spring Boot and the Spring Framework that support org.crac
.
Open Liberty has the following advantages:
Access the full Java SE platform without any compromises. To launch quickly, there is no need to change the application code to suit the environment, as, for example, with native compilation.
Optimized Liberty runtime provides high performance and uses less memory compared to other runtimes.
Enhanced JIT compilation capabilities for cloud deployments (Semeru Cloud Compiler).
Run in a runtime environment that contains only the required components, allowing you to reduce the size of the container image.
Using production-ready Open Liberty images allows you to adhere to best practices for container optimization and security, such as not running the application in the container as root and avoiding privileged containers.
InstantOn application images are ready for deployment in public clouds such as AWS EKS and Azure AKS. The fast startup time provided by Liberty InstantOn makes it an ideal platform for building serverless applications, including those based on SpringBoot.
In conclusion, we invite everyone to the open lesson “Development of REST clients in Spring”, which will be held on November 14. You can sign up on the Spring course page.