shorts
How to dockerize a Spring Boot app with the smallest base image

How to dockerize a Spring Boot app with the smallest base image

Mar 9, 2023
Dmitry Chuyko
8.2

In one of our previous articles, we discussed buildpacks and how they accelerate development and simplify developers’ lives because 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!

By the way, another way to optimize Spring Boot footprint in the cloud is to use Java with CRaC support: Alpaquita Containers with CRaC help to create 1.1 smaller images!

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 --from=builder /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

Alpaquita buildpacks now available!

What if you want to enjoy the convenience of buildpacks that automate containerization and reduce the image size? Meet Alpaquita buildpacks based on Liberica JDK Lite and Alpaquita Linux that will enable you to facilitate development and optimize memory footprint of your Spring Boot microservices.

Discover Alpaquita buildpacks 

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? Head to Alpaquita Documentation for install guides, feature overview, and tuning recommendations or download the white paper with detailed technical characteristics and performance measurements.

Get Alpaquita Linux white paper

Subcribe to our newsletter

figure

Read the industry news, receive solutions to your problems, and find the ways to save money.

Further reading