【问题标题】:How can I cache Maven dependencies and plugins in a Docker Multi Stage Build Layer?如何在 Docker 多阶段构建层中缓存 Maven 依赖项和插件?
【发布时间】:2018-06-06 18:04:52
【问题描述】:

我想在我的Docker Multi Stage Build 的构建阶段的一个层中缓存 Maven 依赖项。

我的 Dockerfile 如下所示:

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
...

```

我基于Docker Multi Stage Build blog post (also available on Github) 中提供的示例创建了这个 Dockerfile。

当我运行构建时,我看到的不是dependency:resolve 下载一次然后被package 重新使用的依赖项,而是看到两个步骤都下载了依赖项。

有人搞定这个吗?我在这里做错了什么?

【问题讨论】:

    标签: maven docker build dockerfile docker-multi-stage-build


    【解决方案1】:

    我遇到了同样的问题。我发现这是由于 Maven 目标之间的差异(例如 dependency:resolvedependency:resolve-plugin)。基本上,dependency:resolve 用于应用程序库,dependency:resolve-plugin 用于插件库。因此,库会在两个 RUN 步骤中下载。

    dependency:resolve 告诉 Maven 解决所有依赖项和 显示版本。 JAVA 9 注意:将显示模块名称时 使用 Java 9 运行。

    dependency:resolve-plugins 告诉 Maven 解析 插件及其依赖项。

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

    即使使用dependency:resolve-plugins,Maven 也不会下载所有必需的库,因为package 是一个内置目标,并且需要dependency:resolve-plugin 在第一次运行时无法解析的其他库。我也试过dependency:go-offline,但没有成功。

    一种解决方案是在将代码添加到构建映像之前和之后运行构建目标。这会将所有插件依赖项拉到较低层,从而允许它们被重用。

    将此解决方案应用于上述示例如下:

    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
    

    【讨论】:

    • 您是否有机会将 Dockerfile 中的构建 sn-p 添加到您的答案中?我已经尝试过dependency:resolve-plugins、dependency:go-offline 和dependency:resolve,但我仍然在每个构建中看到依赖项(不是插件)下载。
    • 由于公司政策,我不能在工作中分享那个。因此,我使用样本github.com/dockersamples/atsea-sample-shop-app 仅用于检查。请让我知道在这两个步骤中再次下载了哪个库(不是插件)。
    • 谢谢,我又看了一遍,只有插件。我被 jitpack.io 缓存的一些插件吓到了
    • 缓存插件问题的进展。我现在正在运行:'dependency:resolve-plugins dependency:resolve clean package',然后将我的代码复制到构建映像中,然后在复制代码后运行'clean package'。结果是所有必需的插件都由第一次 RUN 然后被第二次 RUN 重新使用。生成的 Dockerfile 在这里:github.com/trastle/haverland-smartwave-prometheus-exporter/blob/…
    • 感谢以上sn-p。唉,它不适用于最新的 Spring Boot 插件。 Maven 抛出以下错误:[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.0.3.RELEASE:repackage (default) on project core: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:2.0.3.RELEASE:repackage failed: Unable to find main class -> [Help 1] 这是因为 Spring Boot 插件尝试重新打包 JAR 文件并使其可执行。要修复该错误,您必须添加 -Dspring-boot.repackage.skip=true
    【解决方案2】:

    我愿意出两分钱买这个。

    我从这个 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
    

    目标是在构建步骤期间不下载任何依赖项(即mvn package)。

    我尝试添加@Apolozeus 的答案中提到的clean package 技巧,但这没有效果。就我而言,我在测试期间下载了肯定的下载,并在编译期间下载了 mapstruct 插件。

    我最终所做的就是在我的pom.xml 中明确添加这两个插件,以便尽早下载它们:

        <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>
    

    这可行,并且在构建步骤期间不会发生进一步的下载,从而加快了构建速度。

    【讨论】:

      猜你喜欢
      • 2020-03-19
      • 1970-01-01
      • 2022-11-25
      • 2019-06-30
      • 2019-05-10
      • 2022-12-18
      • 1970-01-01
      • 2019-03-12
      • 2020-07-07
      相关资源
      最近更新 更多