I have a Docker file like the following:
FROM openjdk:8
ADD . /usr/share/app-name-tmp
WORKDIR /usr/share/app-name-tmp
RUN ./gradlew build \
mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar
WORKDIR /usr/share/app-name
RUN rm -rf /usr/share/app-name-tmp
EXPOSE 8080
RUN chmod +x ./docker-entry.sh
ENTRYPOINT [ "./docker-entry.sh" ]
The problem is that the final image size is 1.1GB, I know it happens because gradle downloads and stores all the dependencies. What is the best way to remove those unnecessary files and just keep the jar?
With Docker 17.05+ you can use multi-stage builds.
"With multi-stage builds, you use multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artifacts from one stage to another, leaving behind everything you don’t want in the final image."
So your Dockerfile could look like this:
#
# first stage (build)
#
FROM openjdk:8 as build
ADD . /usr/share/app-name-tmp
WORKDIR /usr/share/app-name-tmp
RUN ./gradlew build && \
mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar
#
# second stage. use alpine to reduce the image size
#
FROM openjdk:8-jre-alpine
WORKDIR /usr/share/app-name
COPY --from=build /usr/share/app-name/app-name.jar .
EXPOSE 8080
RUN chmod +x ./docker-entry.sh
ENTRYPOINT [ "./docker-entry.sh" ]
This way you only keep the jar and all the unnecessary files are not included in the final image.
Each RUN instruction creates a new layer on top of the existing file system. So the new layer after RUN instruction that deletes you app-name-tmp
directory just masks the previous layer containing the downloaded libraries. Hence your docker image still has that size from all the layers built.
Remove the separate RUN rm -rf /usr/share/app-name-tmp
instruction and include it in the same RUN instruction that does gradle build as shown below.
RUN ./gradlew build \
mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \
rm -rf /usr/share/app-name-tmp/*
So, your final Dockerfile would be
FROM openjdk:8
ADD . /usr/share/app-name-tmp
WORKDIR /usr/share/app-name-tmp
RUN ./gradlew build \
mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \
rm -rf /usr/share/app-name-tmp/*
WORKDIR /usr/share/app-name
EXPOSE 8080
RUN chmod +x ./docker-entry.sh
ENTRYPOINT [ "./docker-entry.sh" ]
The image built will still add up size from the directory /usr/share/app-name-tmp.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With