Build Docker images in Spring Boot 3

Build Docker images in Spring Boot 3

New versions of Spring Boot provide easy ways to build Docker images without using any third-party libraries or services such as Spotify Maven plugin or Jib. In this tutorial, we cover how to build Docker images in Spring Boot 3.

The good old dockerfile approach

The most common approach to building a Docker image is using a Dockerfile as below,

FROM amazoncorretto:11
EXPOSE 8080
ARG JAR_FILE=target/app.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Then run,

$ docker build -t app:latest .

However, this approach has some disadvantages:

  • The image size is larger
  • The application startup time is slower

Buildpacks for Spring Boot 3

Starting from Spring Boot 2.3, one can build a Docker image for a Spring Boot app without using any dockerfile or external libraries with a single command.

$ mvn spring-boot:build-image

For Gradle projects,

$ gradle bootBuildImage

Despite being simple and straightforward, this approach does not have much flexibility. For instance, one cannot add an environment variable easily with or customize the Docker image. It is suitable for vanilla Spring Boot projects.

Layered Jars with custom dockerfile for Spring Boot 3

We can still take advantage of faster startup time and smaller image size by using the Layered Jars approach. Spring Boot 2.3 and newer versions (including Spring Boot 3.x) provide a new type of “fat jar” format called LAYERED_JAR in which the lib and classes directories have been split up and categorized into layers.

This approach empowers us to create a dockerfile that extracts and copies each layer of the fat jar to a Docker image while giving us ultimate flexibility.

To achieve that, first, we need to enable the layered jar as follows,

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layers>
            <enabled>true</enabled>
        </layers>
    </configuration>
</plugin>

Now we can create a dockerfile that takes advantage of the layered jar and customize it to our needs,

FROM amazoncorretto:17 as builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM amazoncorretto:17
COPY --from=builder dependencies/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder application/ ./

ENV API_SECRET_KEY=place_holder

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Finally, we can build the image,

$ mvn spring-boot:build-image -Dspring-boot.build-image.imageName="app":"1.2.3"

Spring Boot doesn’t provide an approach to push the image to Docker Hub. Instead, we need to use the docker command as follows,

$ docker login -u "username" --password-stdin <<< "password"
$ docker push "app" --all-tags &&

Conclusion

In this tutorial, we covered how to build Docker images with Spring Boot 3. Starting with Spring Boot 2.3, one can utilize the tools, namely buildpacks and layered jars for creating Docker images without using any third-party libraries.

For simple use cases, the recommended approach is buildpacks since one can build the image only with a single command.

For complex cases, one can combine a custom dockerfile with the layered jar approach that provides faster startup time and a smaller image size.

The fully functional demo project is available on GitHub at the link below,

https://github.com/kasramp/spring-data-redis-example-kotlin

Inline/featured images credits