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

心已入冬 提交于 2019-12-06 02:38:06

问题


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?


回答1:


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



回答2:


I'd like to offer my two cents on this one.

I started with this Dockerfile:

FROM maven:3-jdk-10 AS build

RUN mkdir /src
WORKDIR /src
COPY pom.xml .
RUN mvn -B dependency:resolve-plugins dependency:resolve

COPY . .
RUN mvn package

The goal is to not have any dependencies downloaded during the build step (which is mvn package).

I tried to add the clean package trick that is mentioned in the answer by @Apolozeus but this does not have an effect. In my case, I have surefire being downloaded during test and a mapstruct plugin being downloaded during compilation.

What I did in the end is to explicitly add these two plugins in my pom.xml so that they will be downloaded early on:

    <dependency>
        <groupId>org.apache.maven.surefire</groupId>
        <artifactId>surefire-junit4</artifactId>
        <version>2.21.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.2.0.Final</version>
        <scope>compile</scope>
    </dependency>

This works and no further downloads happen during the build step, which speeds up the build.



来源:https://stackoverflow.com/questions/47969389/how-can-i-cache-maven-dependencies-and-plugins-in-a-docker-multi-stage-build-lay

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!