Maven docker缓存依赖项

Dan*_*ous 28 java maven docker dockerfile

我正在尝试使用docker自动化maven构建.我想要构建的项目花了将近20分钟来下载所有依赖项,所以我尝试构建一个可以缓存这些依赖项的docker镜像,但它似乎并没有保存它.我的Dockerfile是

FROM maven:alpine
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD pom.xml /usr/src/app
RUN mvn dependency:go-offline
Run Code Online (Sandbox Code Playgroud)

图像构建,它确实下载了所有内容.但是,生成的图像与基本maven:alpine图像的大小相同,因此它似乎没有缓存图像中的依赖项.当我尝试使用图像时,mvn compile它会经历整整20分钟的重新下载所有内容.

是否可以构建一个缓存我的依赖项的maven图像,这样每次我使用图像执行构建时都不必下载它们?

我正在运行以下命令:

docker build -t my-maven .

docker run -it --rm --name my-maven-project -v "$PWD":/usr/src/mymaven -w /usr/src/mymaven my-maven mvn compile
Run Code Online (Sandbox Code Playgroud)

我的理解是,RUN在docker构建过程中的任何内容都会成为生成的图像的一部分.

Kim*_*Kim 27

通常,pom.xml文件没有变化,但是当您尝试启动docker映像构建时,其他src代码会发生变化.在这种情况下,你可以这样做:

供参考:

FROM maven:3-jdk-8

ENV HOME=/home/usr/app

RUN mkdir -p $HOME

WORKDIR $HOME

# 1. add pom.xml only here

ADD pom.xml $HOME

# 2. start downloading dependencies

RUN ["/usr/local/bin/mvn-entrypoint.sh", "mvn", "verify", "clean", "--fail-never"]

# 3. add all source code and start compiling

ADD . $HOME

RUN ["mvn", "package"]

EXPOSE 8005

CMD ["java", "-jar", "./target/dist.jar"]
Run Code Online (Sandbox Code Playgroud)

所以关键是:

  1. 添加pom.xml文件.

  2. 然后mvn verify --fail-never它,它将下载maven依赖项.

  3. 然后添加所有源文件,并开始编译(mvn package).

当您的更改pom.xml或您第一次运行此脚本时,docker将执行1 - > 2 - > 3.当pom.xml文件中没有更改时,docker将跳过步骤1,2并直接执行3.

这个简单的技巧可以用在许多其他包管理环境中.

  • 尼斯,写了一篇关于这种方法以及使用壁球的文章,以减小最终图像的大小:https://medium.com/pismolabs/reducing-image-sizes-and-caching-maven-dependencies-in-docker-builds- b388d3f7aa88 (2认同)
  • 这是一个出色而优雅的解决方案,谢谢。这个答案应该被接受。来到这里期待某种 hacky 解决方案,但是这个解决方案与 docker 缓存一起工作,以准确地给出预期的行为。惊人的。 (2认同)
  • @AndrewTFinnell 因此,使用 `dependency:go-offline` (2认同)

Far*_*igo 9

使用 BuildKit

从那时Docker v18.03起,您可以使用BuildKit而不是其他答案中提到的卷。它允许挂载可以在构建之间持续存在的缓存,并且您可以避免.m2/repository每次都下载相应的内容。

假设 Dockerfile 位于项目的根目录中:

# syntax = docker/dockerfile:1.0-experimental

FROM maven:3.6.0-jdk-11-slim AS build
COPY . /home/build
RUN mkdir /home/.m2
WORKDIR /home/.m2
USER root
RUN --mount=type=cache,target=/root/.m2 mvn -f /home/build/pom.xml clean compile
Run Code Online (Sandbox Code Playgroud)

target=/root/.m2将缓存挂载到 Maven 镜像 Dockerfile docs 中的指定位置。

对于构建,您可以运行以下命令:

DOCKER_BUILDKIT=1 docker build --rm --no-cache  .   
Run Code Online (Sandbox Code Playgroud)

可以在此处找到有关 BuildKit 的更多信息。


Krz*_*iak 8

我不认为这里的其他答案是最佳的。例如,mvn verifyanswer 执行以下阶段,并且不仅仅是解决依赖关系:

验证 - 验证项目是否正确并且所有必要的信息都可用

compile - 编译项目的源代码

测试 - 使用合适的单元测试框架测试编译的源代码。这些测试不应该要求打包或部署代码

包 - 获取编译后的代码并将其打包为其可分发格式,例如 JAR。

验证 - 对集成测试的结果进行任何检查,以确保满足质量标准

如果您只想解决依赖关系,则不需要运行所有这些阶段及其相关目标。

如果只想解决依赖关系,可以使用dependency:go-offline目标:

FROM maven:3-jdk-12
WORKDIR /tmp/example/

COPY pom.xml .
RUN mvn dependency:go-offline

COPY src/ src/
RUN mvn package
Run Code Online (Sandbox Code Playgroud)


Dan*_*ous 7

事实证明,我用作基础的图像具有定义的父图像

VOLUME "$USER_HOME_DIR/.m2"
Run Code Online (Sandbox Code Playgroud)

请参阅:https://github.com/carlossg/docker-maven/blob/322d0dff5d0531ccaf47bf49338cb3e294fd66c8/jdk-8/Dockerfile

结果是在构建期间,所有文件都被写入$USER_HOME_DIR/.m2,但由于它应该是卷,因此这些文件都不会与容器映像一起保留.

目前在Docker中没有任何方法可以取消注册该卷定义,因此有必要构建一个单独的maven图像,而不是使用官方的maven图像.

  • 我使用Docker卷并告诉maven为我的maven存储库缓存使用不同的路径,例如`-Dmaven.repo.local =/mvn/.m2nrepo/repository` (4认同)

Fil*_*zka 7

@Kim 最接近,但还没有完全到位。我不认为添加--fail-never是正确的,即使通过它完成了工作。

verify命令会导致执行很多插件,这是一个问题(对我而言) - 我认为当我只想安装依赖项时,它们不应该执行!我还有一个多模块构建和一个 javascript 子构建,因此这进一步使设置复杂化。

但是只运行verify是不够的,因为如果你install在下面的命令中运行,将会使用更多的插件——这意味着需要下载更多的依赖——否则 maven 拒绝下载它们。相关阅读:Maven:构建生命周期简介

您基本上必须找到禁用每个插件的属性并一个一个地添加它们,这样它们就不会破坏您的构建。

WORKDIR /srv

# cache Maven dependencies
ADD cli/pom.xml /srv/cli/
ADD core/pom.xml /srv/core/
ADD parent/pom.xml /srv/parent/
ADD rest-api/pom.xml /srv/rest-api/
ADD web-admin/pom.xml /srv/web-admin/
ADD pom.xml /srv/
RUN mvn -B clean install -DskipTests -Dcheckstyle.skip -Dasciidoctor.skip -Djacoco.skip -Dmaven.gitcommitid.skip -Dspring-boot.repackage.skip -Dmaven.exec.skip=true -Dmaven.install.skip -Dmaven.resources.skip

# cache YARN dependencies
ADD ./web-admin/package.json ./web-admin/yarn.lock /srv/web-admin/
RUN yarn --non-interactive --frozen-lockfile --no-progress --cwd /srv/web-admin install

# build the project
ADD . /srv
RUN mvn -B clean install
Run Code Online (Sandbox Code Playgroud)

但是有些插件不是那么容易跳过 - 我不是 Maven 专家(所以我不知道为什么它忽略了 cli 选项 - 它可能是一个错误),但以下内容按预期工作 org.codehaus.mojo:exec-maven-plugin

<project>
    <properties>
        <maven.exec.skip>false</maven.exec.skip>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.3.2</version>
                <executions>
                    <execution>
                        <id>yarn install</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>initialize</phase>
                        <configuration>
                            <executable>yarn</executable>
                            <arguments>
                                <argument>install</argument>
                            </arguments>
                            <skip>${maven.exec.skip}</skip>
                        </configuration>
                    </execution>
                    <execution>
                        <id>yarn run build</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                        <configuration>
                            <executable>yarn</executable>
                            <arguments>
                                <argument>run</argument>
                                <argument>build</argument>
                            </arguments>
                            <skip>${maven.exec.skip}</skip>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
Run Code Online (Sandbox Code Playgroud)

请注意明确<skip>${maven.exec.skip}</skip>-其他插件(既不接从CLI PARAMS这件事,但没有这一项-Dmaven.exec.skip=true,也不-Dexec.skip=true由本身的工作)

希望这可以帮助


Omr*_*tor 6

缓存maven依赖有两种方式:

  1. 执行“mvn verify”作为容器执行的一部分,而不是构建,并确保从卷挂载 .m2。

    这是有效的,但它不适用于云构建和多个构建从属

  2. 使用“依赖项缓存容器”,并定期更新它。方法如下:

    一种。创建一个 Dockerfile 来复制 pom 并构建离线依赖项:

    FROM maven:3.5.3-jdk-8-alpine
    WORKDIR /build
    COPY pom.xml .
    RUN mvn dependency:go-offline
    
    Run Code Online (Sandbox Code Playgroud)

    湾 定期(例如每晚)将其构建为“Deps:latest”

    C。创建另一个 Dockerfile 以在每次提交时实际构建系统(最好使用多阶段) - 并确保它是 FROM Deps。

使用此系统,您将拥有快速、可重构的构建,并且具有足够好的缓存。


小智 -2

如果在容器启动后下载依赖项,则需要在此容器上提交更改并使用下载的工件创建新映像。