How can I cache Maven dependencies and plugins in a Docker Multi Stage Build Layer?

Trastle picture Trastle · Dec 25, 2017 · Viewed 7.8k times · Source

I want to cache Maven dependencies in a layer of the build stage of my Docker Multi Stage Build.

My Dockerfile looks as follows:

FROM maven:3-jdk-8 as mvnbuild
RUN mkdir -p /opt/workspace
WORKDIR /opt/workspace
COPY pom.xml .
RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml dependency:resolve
COPY . .
RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml package

FROM openjdk:8-jre-alpine
...

```

I based this Dockerfile on the example provided in the Docker Multi Stage Build blog post (also available on Github).

When I run the build, instead of seeing the dependencies downloaded once by dependency:resolve and then re-used by package, I am seeing the dependencies downloaded by both steps.

Has anyone got this working? What am I doing wrong here?

Answer

sayboras picture sayboras · Dec 25, 2017

I came across the same question. I found out it's due to differences between Maven targets (e.g. dependency:resolve vs dependency:resolve-plugin). Basically, dependency:resolve is for application libraries, dependency:resolve-plugin is for plugin libraries. Hence, libraries are downloaded in both RUN steps.

dependency:resolve tells Maven to resolve all dependencies and displays the version. JAVA 9 NOTE: will display the module name when running with Java 9.

dependency:resolve-plugins tells Maven to resolve plugins and their dependencies.

https://maven.apache.org/plugins/maven-dependency-plugin/index.html

Even with dependency:resolve-plugins, Maven will not download all required libraries as package is a built-in target and requires additional libraries which dependency:resolve-plugin won't know to resolve in the first RUN. I also tried dependency:go-offline without success.

One solution is to run your build targets before and after adding your code to the build image. This will pull all the plugin dependencies into the lower layer allowing them to be re-used.

Applying this solution to your example above is as follows:

FROM maven:3-jdk-8 as mvnbuild
RUN mkdir -p /opt/workspace
WORKDIR /opt/workspace
COPY pom.xml .
RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml dependency:resolve-plugins dependency:resolve clean package
COPY . .
RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml clean package

FROM openjdk:8-jre-alpine