Reputation: 4886
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
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