Building Spring Boot Docker Images

Table of Contents

Pre-Requirements

  • Developer Environment ready with Docker, JDK, IDE
  • A Java Spring Boot Project with a h2 in-memory DB
  • Docker Hub account

Create Docker File

Create a Dockerfile with the following content:

FROM openjdk:11-jre-slim
ENV JAVA_OPTS " -Xms512m -Xmx512m -Djava.security.egd=file:///dev/./urandom"
WORKDIR application
COPY target/myapp-0.0.1-SNAPSHOT.jar ./
ENTRYPOINT ["java", "-jar", "myapp-0.0.1-SNAPSHOT.jar"]
make sure the Paths where the .jar files are stored matches with your environment.

Build and Run the Docker Image

Build the image with this command:

docker build -f ./src/main/Dockerfile -t myapp .

Run the image with this command:

docker run -p 8080:8080 -d myapp

The Spring Application-Context should now be loaded and started inside the Container. You can verify this with the docker ps -a and docker logs -f <containername> commands.

Add Layer Tool in Maven

Make sure that you have enabled the Layer Tool with having this content in the pom.xml file:

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layers>
                        <enabled>true</enabled>
                        <includeLayerTools>true</includeLayerTools>
                    </layers>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>

Enabling the layer tool in a Java Spring project that runs in a Docker container can help reduce the size of the Docker image, which can be especially important in a production environment. The layer tool feature allows the Spring Boot application to be broken down into layers, where each layer contains a subset of the application's dependencies and resources. This makes it possible to separate the application's core functionality from its dependencies, such as external libraries and resources.

By separating the application's dependencies into separate layers, Docker can cache each layer independently, making it easier to reuse existing layers when building new Docker images. This can significantly reduce the amount of time it takes to build and deploy new versions of the application.

Enabling the layer tool also allows you to take advantage of other features, such as layer analysis, which can help you optimize your Docker image even further by identifying potential areas for improvement.

In summary, enabling the layer tool in a Java Spring project that runs in a Docker container can help reduce the size of the Docker image, improve the speed of deployment, and optimize resource usage.

Enable Multi-Stage Dockerfile

Now we want to create a example of a Multi-Stage Dockerfile, like so:

FROM openjdk:11-jre-slim as builder
WORKDIR application
ADD target/myapp-0.0.1-SNAPSHOT.jar ./
RUN java -Djarmode=layertools -jar myapp-0.0.1-SNAPSHOT.jar extract

FROM openjdk:11-jre-slim

WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "-Djava.security.egd=file:///dev/./urandom", "org.springframework.boot.loader.JarLauncher"]

now we can recreate the image like so: docker build -f ./src/main/docker/Dockerfile -t myapp .

Build the Docker Image with Maven

So far it's very uncomfortable to have the Version of the .jar Artifact in the Dockerfile. This way we would need to change this after every new release. There is a better way: we can use the Docker Maven plugin. Add this dependency to your pom.xml:

<plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.42.1</version>
                <configuration>
                    <verbose>true</verbose>
                    <images>
                        <image>
                            <name>yourdockeraccount/myapp</name>
                            <build>
                                <assembly>
                                    <descriptorRef>artifact</descriptorRef>
                                </assembly>
                                <dockerFile>Dockerfile</dockerFile>
                                <tags>
                                    <tag>latest</tag>
                                    <tag>${project.version}</tag>
                                </tags>
                            </build>
                        </image>
                    </images>
                </configuration>
            </plugin>

make sure you add your image name!

Also you need to replace the Artifact Name of "myapp-0.0.1-SNAPSHOT.jar" with 

"${project.build.finalName}.jar" in the Dockerfile.
 
Now you can build the docker image with the maven plugin using a dynamic version.

Push your Docker Image to Docker Hub

Last step is to push your Application to the docker hub. But first lets build the image with:

mvn clean package docker:build docker:push