Alex Man
Alex Man

Reputation: 4886

Building docker image for Spring Boot app using Dockerfile and running using JarLauncher

I was using a DockerFile for building a spring boot jar file, uploads to artifactory and deploys to K8S. For doing this I wrote a standard Dockerfile like as shown below

FROM maven:3.6.6-jdk-11 AS build
WORKDIR source
COPY . source
RUN mvn -q clean package -DskipTests


FROM maven:3.6.6-jdk-11
COPY --from=build source/app-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
RUN chmod +x app.jar
ENTRYPOINT ["java","-jar","app.jar"]

But I have seen a different project where they have mentioned like as shown below

FROM maven:3.8.4-jdk-11 AS builder
WORKDIR source
COPY . .
RUN mvn -q clean package -DskipTests
RUN cp target/cdacapp-0.0.1-RELEASE.jar ./cdacapp.jar
RUN java -Djarmode=layertools -jar cdacapp.jar extract

FROM openjdk:11-jre-slim
WORKDIR application
COPY --from=builder source/dependencies/ ./
COPY --from=builder source/spring-boot-loader/ ./
COPY --from=builder source/webjars/ ./
COPY --from=builder source/application/ ./
ENTRYPOINT [ "java", "org.springframework.boot.loader.JarLauncher"]

I would like to know what benefit we will get by running the application using JarLauncher

Upvotes: 0

Views: 1514

Answers (1)

David Maze
David Maze

Reputation: 158647

This setup produces an image that is smaller to download when you deploy an updated version of the image with just changed code, but not any of the changed dependencies.

A Docker image is made of layers, and in the setup you show here, each COPY command is a separate layer. In the first form, the COPY with the fat jar produces a single layer, and if you change anything in the application you have to download that entire layer again (including all of the unchanged dependencies). In the second form, though, if the dependencies and spring-boot-loader trees haven't changed (which is probably the common case) then only the later layers will need to be downloaded.

For a more practical example, let's say you're labeling your Docker images with a date stamp, and the most recent build was registry.example.com/your-image:20220722. Now if you rebuild with the second Dockerfile

docker build -t registry.example.com/your-image:20220725 .
docker push registry.example.com/your-image:20220725

Docker will recognize that the registry already contains the "dependencies" layer and not push it again. Similarly, if you update a Kubernetes manifest

image: registry.example.com/your-image:20220725 # was 20220722

the cluster will download a piece of data called the image manifest and realize it already has the base layers, so it only needs to download the updated application layer at the end.

If you're working totally locally, there's not especially a benefit to one approach over the other.

The Spring Boot documentation has a section on Container Images which discusses this specific approach further.

Upvotes: 3

Related Questions