back to all blogsSee all blog posts

How to containerize your Spring Boot application for rapid startup

image of author
Thomas Watson on Sep 26, 2023
Post available in languages:

Did 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 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.

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 the Liberty InstantOn 23.0.0.10-beta version, 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 crac-1.3 feature, along with the Spring Framework version 6.1 support for org.crac, 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 be running 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 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 orc.crac 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 mvnw 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.crac, you must enable the crac-1.3 feature in the Liberty configuration. For this example, we can do that by copying in the src/main/liberty/config/crac.xml file into the container image with the following Dockerfile command:

Dockerfile
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:

crac.xml
<?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.podman file. This is the last instruction of the Dockerfile.podman file, as shown in the following example:

Dockerfile.podman
...
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:

build-instanton-podman.sh
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-podman.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. See when to make a checkpoint for more information on the checkpoint options.

You see the following output when the application has started:

InstantOn checkpoint output
[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:

  1. Build the application container image without the InstantOn layer.

  2. Run the application container to perform a checkpoint of the application.

  3. 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:

run-instanton-podman.sh or 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

You can run the previous command or run the provided scripts/run-instanton-podman.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:

InstantOn restore 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.

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 properly 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 the original startup time of 5.5+ seconds when not using InstantOn.

Summary

Open Liberty InstantOn provides a holistic runtime for deploying cloud-native applications with rapid startup. 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.crac. Applications continue to benefit from the other advantages that the Open Liberty runtime provides, such as:

  • Access to the full Java SE platform without compromise. No need to adjust application code to fit into environments, like native compilation, to achieve rapid startup.

  • An optimized Liberty runtime that continues to provide top-performing throughput for applications, while also using less memory compared to other runtimes.

  • Advanced JIT compilation features provided by the JVM, such as the Semeru Cloud Compiler when deploying to the cloud.

  • Running on a fit-for-purpose runtime that allows you to use only what you need in order to reduce the container image size.

  • Using the production-ready Open Liberty container images, an InstantOn application image can be built using the best practices for building optimized and secure application images, such as not running as root in the container or running a privileged container.

InstantOn application images will be ready to deploy into existing public clouds, such as AWS EKS and Azure AKS platforms. The rapid startup times that Liberty InstantOn provides make it an ideal platform for building your serverless applications, including those based on SpringBoot.