In one of our previous articles, we dockerized a Spring Boot application using Paketo buildpacks (if you want to know more about using and configuring JVM via buildpacks, refer to our guide). Buildpacks accelerate development and simplify developers’ lives, as there’s no need to write Dockerfiles. But simultaneously, you don’t have control over the size of the resulting container because buildpacks don’t use a lightweight base OS image. And a Spring Boot app can demand a lot of memory!
If the container size is crucial, you must build it yourself. So in this article, we will learn to dockerize a Spring Boot app using a microcontainer with Liberica Lite and Alpaquita Linux. We will have to write an old-school Dockerfile, but you will see that the result is worth the trouble!
Table of Contents
Spring Boot container with Paketo buildpack
Build a Spring Boot app
First, let us write a basic Spring Boot application to have something to work with. Go to Spring Initializr. Select Maven, Java, jar, version 17. After that, change the name to docker-image-demo. We don’t need any dependencies. Download the project and unzip it in a separate “demo” folder (we will require that later).
Open the project in your favorite IDE (we are using IntelliJ IDEA) and configure the application in the following way:
@SpringBootApplication
@RestController
public class DockerImageDemoApplication {
@RequestMapping("/")
public String home() {
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(DockerImageDemoApplication.class, args);
}
}
Containerize the app
Before building a container with Paketo buildpack, we need to perform some housekeeping tasks.
Install pack, one of the tools facilitating work with buildpacks.
Make Paketo Base builder the default builder:
pack config default-builder paketobuildpacks/builder:base
BellSoft Liberica is the default JVM with Paketo buildpacks. It provides a JDK at build time and JRE at runtime, so the resulting container will be smaller.
To build an image from the source with Maven, run
pack build demo-image --env BP_JVM_VERSION=17
Check the images with
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-image latest fba8b6bec92a 30 seconds ago 267MB
Let’s build a container with Oracle JVM, which provides JDK only, to see how significant is the size reduction we achieved with Liberica JRE.
To use an alternative JVM, use the following command:
pack build demo-image-oracle --buildpack paketo-buildpacks/oracle --buildpack paketo-buildpacks/java --env BP_JVM_VERSION=17
Check the image size:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-image-oracle latest f5e09233237a 27 seconds ago 426MB
As you can see, the container we built with Liberica is 1.5 smaller than that with Oracle, thanks to the usage of JRE. But what if the reduction is insufficient? We can create even smaller containers by choosing another base OS image.
Spring Boot containers with Dockerfile
Let’s take the same project we developed in the previous section.
Write a Dockerfile
We will use a Liberica Runtime Container, which includes a lightweight musl-based Alpaquita Linux and Liberica Lite optimized for Cloud deployment.
There are two ways to build containers with Dockerfile.
The first method is to build a runnable jar:
mvn package
And then write the following Dockerfile:
FROM bellsoft/liberica-runtime-container:jre-17-stream-musl
COPY target/docker-image-demo-0.0.1-SNAPSHOT.jar dockerimage.jar
CMD ["java", "-jar", "/dockerimage.jar"]
We import a base image from the BellSoft’s repository in the first line. In the second line, we copy our jar (docker-image-demo-0.0.1-SNAPSHOT.jar) from the target folder into the root folder of our container and name it dockerimage.jar. In the third line, we run the dockerimage.jar with java -jar command.
The second method involves building a project with Liberica JDK in a container, then copying this image into another one with Liberica JRE.
Put the following Dockerfile into the demo
folder, which already contains our docker-image-demo project:
FROM bellsoft/liberica-runtime-container:jdk-17-stream-musl as builder
WORKDIR /home/myapp
ADD docker-image-demo /home/myapp/docker-image-demo
RUN cd docker-image-demo && ./mvnw package
FROM bellsoft/alpaquita-linux-base:stream-musl-230404
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
VOLUME /tmp
WORKDIR /home/myapp
COPY /home/myapp/docker-image-demo/target .
EXPOSE 8080
CMD ["java", "-jar", "docker-image-demo-0.0.1-SNAPSHOT.jar"]
Here, we build a project inside Docker and then copy it into another container, where we can run the application. You need the EXPOSE 8080 line if you have a web application.
Build a Docker container image
Run
docker build . -t dockerimagealpaquita
Check the image size:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dockerimagealpaquita latest 0ec8e8cc5f6a 12 seconds ago 136MB
Java container size comparison
We now have three containers with the same Java application, and the size difference is striking. Our container based on Alpaquita and Liberica JRE Lite is 136MB, almost twice as small as the container we built with Liberica JRE via a buildpack and three times the size of the Oracle JDK container.
Alpaquita + Liberica Lite |
Liberica JRE via the Paketo buildpack |
Oracle JDK via the Paketo buildpack |
136MB |
267MB |
426MB |
Java container size comparison
Run the Spring Boot Docker image
To run the Docker image from the command line, use the following command:
docker run dockerimagealpsaquita
Conclusion
As you can see, switching to a lightweight base OS image makes a drastic difference regarding container size. But migration to Alpaquita gives you additional benefits:
- Two libc implementations available, optimized musl and glibc;
- Enhanced performance compared to other popular Linux distributions;
- The only Linux optimized for Java development;
- LTS versions as part of commercial support;
- 100% compatibility with Liberica JDK and Liberica NIK, products used and recommended by the Spring team.
Want to know more about Alpaquita? Download the white paper with detailed technical characteristics and performance measurements.