当前位置: 首页 > 知识库问答 >
问题:

使用 maven 构建泊坞 - 如何防止重新下载依赖项

潘楚
2023-03-14

我希望基础映像 mavenDeps 下载依赖项并仅在依赖项更改时重新生成,而第二个映像 mavenBuild 将在代码更改时重新生成。但是,在 docker build .上,两个 maven 命令都会下载所有依赖项。我可能误解了堆叠的工作原理或在哪里复制什么。

我尝试过的:将第一个容器中的所有内容显式复制到第二个容器中:< code>COPY / /和各种更具体的< code>COPY目标,如< code>.m2,从maven基本映像构建第二个容器,如第一个容器,然后从第一个容器中复制所有内容。

Dockerfile:

FROM maven:3.5-jdk-8 as mavenDeps
COPY pom.xml pom.xml
RUN mvn dependency:resolve

FROM mavenDeps as mavenBuild
RUN mvn install

FROM java:8
COPY --from=mavenBuild ./target/*.jar ./
ENV JAVA_OPTS ""
CMD [ "bash", "-c", "java ${JAVA_OPTS} -jar *.jar -v"]

我在MacOS上使用Docker Desktop < code > 2 . 2 . 2 . 0 (引擎< code>19.03.5)进行构建。

编辑2020.03.04:

来自@gcallea的回复有效地防止了重新下载pom文件1中列出的依赖项。但是,安装步骤仍然会在代码更改触发的每个构建上拉取100个工件。这些是maven-resource-pluginmaven-compiler-plugin和其他几个没有明确列出的插件的瞬态依赖项。

我有时需要离线工作,并想预加载所有依赖项,因此代码更改后不会拉取依赖项。

共有2个答案

顾俊哲
2023-03-14

您不需要将构建阶段划分为两个不同的阶段:mavenDeps和mavenBuild。为了同样的目的,您可以使用Docker层来包含单个构建阶段。

您可以按照以下方式构建Dockerfile:

#----
# Build stage
#----
FROM maven:3.5-jdk-8 as buildstage
# Copy only pom.xml of your projects and download dependencies
COPY pom.xml .
RUN mvn -B -f pom.xml dependency:go-offline
# Copy all other project files and build project
COPY . .
RUN mvn -B install

#----
# Final stage
#----
FROM java:8
COPY --from=buildstage ./target/*.jar ./
ENV JAVA_OPTS ""
CMD [ "bash", "-c", "java ${JAVA_OPTS} -jar *.jar -v"]

仅当通过 pom 进行更改时才执行此操作.xml依赖项将被重新加载。否则,与命令 RUN mvn -B -f pom 相关的 Docker 层.xml依赖项:脱机将重用为缓存。

闾丘德业
2023-03-14

在告诉您如何处理之前,我将解释您遇到的问题。

您的Dockerfile依赖于构建多阶段功能
这里阶段被认为是中间层,而不是作为层保留在最终图像中。要在层之间保留文件/文件夹,您必须像这样显式复制它们。

具体来说,这意味着在下面的说明中:maven解析pom.xml中指定的所有依赖项,并将它们存储在位于该阶段层的本地存储库中:

FROM maven:3.5-jdk-8 as mavenDeps
COPY pom.xml pom.xml
RUN mvn dependency:resolve

但如前所述,默认情况下不会保留阶段内容。因此,本地maven存储库中所有下载的依赖项都将丢失,因为您永远不会在下一阶段复制它:

FROM mavenDeps as mavenBuild
RUN mvn install

由于该映像的本地存储库为空:mvn install重新下载所有依赖项。

如何处理?

你真的有很多很多的方法。
最佳选择取决于你的要求。
但是不管是什么方式,docker层的构建策略如下所示:

构建阶段(Maven映像) :

  • pom复制到图像
  • 依赖项和插件下载。
    关于这一点,mvn依赖关系:解析插件链接到mvn依赖项:解析可能会完成这项工作,但并非总是如此。
    为什么?因为这些插件和执行可能依赖于不同的工件/插件,甚至对于相同的工件/插件,这些可能仍然会拉取不同的版本。因此,一种更安全的方法虽然可能较慢,但通过精确执行mvn package命令(这将完全拉取您需要的依赖项)来解决依赖项,但通过跳过源编译并删除目标文件夹以使处理速度更快并防止对该步骤进行任何不需要的层更改检测。
  • 将源代码复制到图像
  • 打包应用程序

运行阶段(JDK或JRE映像):

    < li >复制上一阶段的jar文件

1) 没有针对maven依赖项的显式缓存:当pom频繁更改时,直接但恼人

如果在每个pom重新下载所有依赖项。xml更改是可以接受的。

从脚本开始的示例:

########build stage########
FROM maven:3.5-jdk-8 as maven_build
WORKDIR /app

COPY pom.xml .
# To resolve dependencies in a safe way (no re-download when the source code changes)
RUN mvn clean package -Dmaven.main.skip -Dmaven.test.skip && rm -r target

# To package the application
COPY src ./src
RUN mvn clean package -Dmaven.test.skip

########run stage########
FROM java:8
WORKDIR /app

COPY --from=maven_build /app/target/*.jar

#run the app
ENV JAVA_OPTS ""
CMD [ "bash", "-c", "java ${JAVA_OPTS} -jar *.jar -v"]

该解决方案的缺点?pom.xml中的任何更改都意味着重新创建下载和存储 maven 依赖项的整个层。
对于具有许多依赖项的应用程序,这通常是不可接受的,如果您在映像构建期间不使用 maven 存储库管理器,则总体上是不可接受的。

2)maven依赖项的显式缓存:需要更多的配置和使用timpekit,但这更有效,因为只下载了所需的依赖项

这里唯一改变的是maven依赖项下载缓存在docker builder缓存中:

# syntax=docker/dockerfile:experimental
########build stage########
FROM maven:3.5-jdk-8 as maven_build
WORKDIR /app

COPY pom.xml .    
COPY src ./src

RUN --mount=type=cache,target=/root/.m2 mvn clean package  -Dmaven.test.skip

########run stage########
FROM java:8
WORKDIR /app

COPY --from=maven_build /app/target/*.jar

#run the app
ENV JAVA_OPTS ""
CMD [ "bash", "-c", "java ${JAVA_OPTS} -jar *.jar -v"]

要启用buildkit,必须设置环境变量DOCKER_buildkit=1(您可以在需要的位置执行此操作:bashrc、命令行、DOCKER守护程序json文件…)

 类似资料:
  • 我在父母pom中有一个依赖管理部分,比如 还有一个孩子pom 我试图使用强制执行器插件防止这种在子pom中重写,只允许在父级中设置这些,但一直无法。我希望这会使构建失败。有可能吗,使用那个插件或其他方式? 还有DependencyConvergence,它强制所有版本都是相同的,但这太严格了,因为我不想控制所有可传递的依赖项,只想控制显式定义的依赖项。 如果我能阻止在子pom中引入任何新的依赖项,

  • 问题内容: 我想利用Maven提供的功能来管理项目中的依赖项。我对Maven的工作方式的简要了解是,它将获取所需的JAR,然后使用这些库来构建项目。 目前,我已经设置了一个简单的POM文件作为测试: 为了管理依赖关系,我通常将项目或JAR添加到构建路径中,然后就可以构建我的项目了。 但是,当使用 M2Eclipse时 ,依赖关系不会自动添加到构建路径中。是否有任何配置可以让Eclipse知道Mav

  • 问题内容: 我正在使用Apache Maven构建我的项目,并配置了一个自定义存储库,但是当它访问该存储库时,它会挂起很长时间 下载:http : //maven.mycompany.com/m2/org/springframework/spring/2.5.6/spring-2.5.6.pom 几分钟后,它就会从中央存储库下载 下载:http : //repo1.maven.org/maven2

  • 问题内容: 我是Maven和Checkstyle的新手,所以请保持礼貌:)。 我设法将maven与checkstyle插件一起使用,并且可以在代码上创建报告。但是我真正想要拥有的是,如果样式检查有任何错误,我可以停止Maven的构建过程。 到目前为止,我的pom.xml如下所示: 我如何在这里达到目标?我们的团队希望有严格的编码风格标准,所以我必须使用它。 问题答案: 为了实现所需的功能,除了报告

  • 我安装了cron和 登录docker镜像 没有正在运行 我想我必须做点什么来启动cron服务器。 我怎么能这样做??

  • 问题内容: 我创建了一个非常简单的默认应用程序,用于在Windows 7计算机上测试Eclipse Indigo / Maven v3.0.1设置。Hello World应用程序可以从Eclipse正常运行。 现在从命令行尝试进行测试。 在这一点上,我看到Maven下载了大量的依赖项。出于某种原因,尽管下载它会停滞不前,但只会部分停止。每次都不在同一时间,但是当前始终是相同的jar文件,例如… h