【问题标题】:Caching Maven parent in offline build在离线构建中缓存 Maven 父级
【发布时间】:2016-11-30 21:32:01
【问题描述】:

TL/DR:如何缓存 pom.xml 文件的 <parent> 以便我的构建可以在离线模式下运行?

我正在使用 Docker 构建一个 maven 项目。我的目标是在构建中添加两个步骤:一个是下载所有依赖项,另一个是构建项目。这是我的 Dockerfile 到目前为止的样子:

FROM maven:3.3-jdk-8

# Download the project dependencies (so they can be cached by Docker)
ADD pom.xml /runtime/
WORKDIR /runtime
RUN mvn dependency:go-offline
RUN mvn dependency:resolve-plugins

# Mount the local repository
ADD . /runtime

# Build the service
RUN mvn clean package -o -DskipTests

这似乎适用于插件。我检查了/root/.m2/repository,一切似乎都正常。

编辑:当仔细检查/root/.m2/repository 目录时,它不再存在。出于某种原因,Maven 没有将任何依赖项保存到此位置。

编辑 2:构建 Docker 映像后,没有 /root/.m2/repository 目录。但是,如果我在 Docker 容器内的 shell 中运行 mvn dependency:go-offline,则目录创建没有问题。

当我尝试构建我的应用程序时,我收到以下错误:

[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[FATAL] Non-resolvable parent POM for com.example:service:1.2: Cannot access central (http://jcenter.bintray.com) in offline mode and the artifact org.springframework.boot:spring-boot-starter-parent:pom:1.4.0.M3 has not been downloaded from it before. and 'parent.relativePath' points at wrong local POM @ line 14, column 13
 @
[ERROR] The build could not read 1 project -> [Help 1]
[ERROR]
[ERROR]   The project com.sample:service:1.2 (/runtime/pom.xml) has 1 error
[ERROR]     Non-resolvable parent POM for com.oe:graph-service:1.2: Cannot access central (http://jcenter.bintray.com) in offline mode and the artifact org.springframework.boot:spring-boot-starter-parent:pom:1.4.0.M3 has not been downloaded from it before. and 'parent.relativePath' points at wrong local POM @ line 14, column 13 -> [Help 2]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException
[ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/UnresolvableModelException

问题似乎是mvn dependency:go-offline 没有解决父问题。当我在离线模式下运行构建时,它会中断。

这是我的pom.xml 文件的相关部分:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    ...

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.M3</version>
    </parent>

    ...

    <repositories>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>bintray</name>
            <url>http://jcenter.bintray.com</url>
        </repository>

        <repository>
            <id>repository.springsource.snapshot</id>
            <name>SpringSource Snapshot Repository</name>
            <url>http://repo.springsource.org/snapshot</url>
        </repository>

        <repository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    <dependencies>
       ...

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.scala</groupId>
            <artifactId>spring-scala_2.11</artifactId>
            <version>1.0.0.BUILD-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- disabling Spring cloud AWS until proper testing harnesses can be set up -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-aws-autoconfigure</artifactId>
            <version>1.1.0.RELEASE</version>
        </dependency>

        ...
    </dependencies>

    ...
</project>

【问题讨论】:

  • 附带说明,这是我第一次使用 Maven。我继承了这个 repo 并没有写 pom.xml 文件。如果您发现pom.xml 文件或我的方法有任何其他问题或问题,请随时指出!
  • mvn dependency:go-offline 应该已经下载了父级的 POM 文件并将其安装在本地存储库中。我用 Maven 3.3.9 进行了测试,它确实做到了(所以在离线模式下运行之后可以工作)。您使用的是哪个版本?您能否验证父 POM 是否存在于本地存储库中 ~/.m2/repository/org/springframework/boot/spring-boot-starter-parent/1.4.0.M3
  • 我也遇到了这个问题。 Maven 依赖树显示我的 pom 的父级没有解析。
  • @Tunaki 查看repository 目录很好。在仔细检查之后,这个目录似乎不再存在。我已对我的问题进行了编辑。
  • Maven 必须使用另一个本地存储库,然后将依赖项放在另一个存储库中。借助这个问题stackoverflow.com/questions/5916157/…,尝试获取它正在使用的那个。

标签: java maven docker


【解决方案1】:

如果您自定义 maven 的 settings.xml 文件,您可以将存储库文件保存在映像上。

创建settings.xml 的自定义版本,修改localRepository 设置,如下所示:

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   |
   | Default: ${user.home}/.m2/repository -->
  <localRepository>/usr/share/maven/repo</localRepository>
...

然后在构建镜像时覆盖默认配置:

FROM maven:3-jdk-8

COPY settings.xml /usr/share/maven/conf/settings.xml

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ADD . /usr/src/app

RUN mvn dependency:go-offline

RUN mvn clean package

现在您的存储库存储在/usr/share/maven/repo

使用 onbuild

您还可以使用ONBUILD 创建基础镜像,这将允许为每个 maven 项目自定义配置镜像。

像这样:

FROM maven:3-jdk-8

COPY settings.xml /usr/share/maven/conf/settings.xml

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ONBUILD ADD . /usr/src/app

ONBUILD RUN mvn dependency:go-offline

ONBUILD RUN mvn clean package

然后构建镜像:

docker build -t mvn_bldr .

这将为其他 maven 图像创建一个 模板。然后您可以使用以下命令创建自定义下游图像:

FROM mvn_bldr

如果您想进一步自定义您的图像,您可以添加更多指令,模板的每条指令都将在FROM mvn_bldr 命令之后触发,如文档中所述:

触发器将在下游构建的上下文中执行, 就好像它是在 FROM 指令之后立即插入的一样 下游 Dockerfile。

【讨论】:

  • 太棒了!感谢您的建议。我认为这很好地解决了我们的问题。
【解决方案2】:

在 Docker 中使用 RUN 似乎就像在 shell 脚本中执行命令一样,但事实并非如此。 RUN 的每个实例都会应用到一个新容器,该容器是由上一个命令创建的更改产生的。所以每个命令都在一个新的容器上下文中执行。

Dockerifles 可以包含一个 VOLUME 引用,它在 Docker 容器内挂载一个外部目录。如果卷内有任何文件,则这些文件将被清除。如果您没有明确指定卷,Docker 很乐意创建一个空文件夹。

虽然我的 Dockerfile 不包含对 VOLUME 的显式引用,但它的父级包含。因此,即使我的mvn dependency:go-offline 命令正在运行,这些文件也会在下一步被docker-maven Dockerfile 中指定的VOLUME 清除。

最后,我找不到让maven Docker 镜像工作的好方法,所以我切换到openjdk 镜像并通过apt-get 安装了maven

【讨论】:

    猜你喜欢
    • 2018-02-12
    • 1970-01-01
    • 2019-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 2010-11-15
    • 2018-08-06
    相关资源
    最近更新 更多