如何为 GitLab CI 运行器启用 Maven 工件缓存?

Posted

技术标签:

【中文标题】如何为 GitLab CI 运行器启用 Maven 工件缓存?【英文标题】:How to enable maven artifact caching for GitLab CI runner? 【发布时间】:2016-10-13 14:24:53 【问题描述】:

我们将 GitLab CI 与共享运行器一起使用来进行持续集成。对于每个构建,运行程序都会下载大量 maven 工件。

有没有办法配置 GitLab CI 来缓存这些工件,这样我们就可以通过防止一遍又一遍地下载相同的工件来加快构建过程?

【问题讨论】:

Maven 通常在$HOME/.m2/repository 下有一个缓存,或者可以通过mvn -Dmaven.local.repo=Path 进行配置? 【参考方案1】:

Gitlab CI 允许您根据每个作业或构建定义某些路径,其中包含应该在构建之间缓存的数据(有关更多详细信息,请参阅here)。结合khmarbaise的推荐,这可以用来缓存多个构建之间的依赖关系。

缓存构建中所有作业依赖项的示例:

cache:
  paths:
    - .m2/repository

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

maven_job:
  script:
    - mvn clean install

【讨论】:

这对我不起作用,直到我将 -Dmaven.repo.local=.m2 更改为 -Dmaven.repo.local=.m2/repository 现在是 2017 年,对于新来者来说:GitLab 维护 [一个不错的项目][1] 及其 CI 运行器的示例配置。 [示例 Maven 项目][2] 文件演示了如何缓存 Maven 工件。 [1]:gitlab.com/gitlab-org/gitlab-ci-yml/tree/master [2]:gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/… 项目之间是否可以共享缓存的工件? 更新到@zloster 链接。 Gitlab 在这些链接中弃用了该项目。更新链接为gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/… 更新到@antonkronaj 链接。项目 'gitlab-org/gitlab-ce' 已移至 'gitlab-org/gitlab-foss'。【参考方案2】:

根据GitLab's issue tracker 上的对话,我设法更改了 Maven 本地存储库路径并将其放入 ./.m2/repository/ 目录,然后我们将通过将此全局块添加到 CI 配置中来在运行之间保持:

cache:
  paths:
    - ./.m2/repository
  # keep cache across branch
  key: "$CI_BUILD_REF_NAME"

不幸的是,根据this *** answer,maven 本地存储库路径只能在每次运行时使用-Dmaven.repo.local 或通过编辑settings.xml 来设置,这是在 gitlab-ci 配置脚本中完成的一项繁琐的任务。一个选项是使用默认的 Maven 选项设置一个变量并将其传递给每次运行。

此外,本地 Maven 存储库是当前目录的子目录也很重要。出于某种原因,将其放入 /cache/builds 对我不起作用,尽管 GitLab 的某个人声称应该这样做。

适用于 Maven + Java 的 gitlab-ci.yml 配置文件示例:

image: maven:3-jdk-8

variables:
  MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=./.m2/repository"
  MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version"

cache:
  paths:
    - ./.m2/repository
  # keep cache across branch
  key: "$CI_BUILD_REF_NAME"

stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - "mvn clean compile $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

unittest-job:
  stage: test
  dependencies:
    - build-job
  script:
    - "mvn package $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

integrationtest-job:
  stage: test
  dependencies:
    - build-job
  script:
    - "mvn verify $MAVEN_CLI_OPTS"
  artifacts:
    paths:
      - target/

deploy-job:
  stage: deploy
  artifacts:
    paths:
      - "target/*.jar"

【讨论】:

是否可以在 Gitlab 中的项目之间共享缓存的工件? 有一个麻烦:你在哪里使用$MAVEN_OPTSvar ? @GGO MAVEN_OPTS 是 Maven 自动使用的众所周知的环境变量。【参考方案3】:

接受的答案对我没有用。

正如 zlobster 所提到的,GitLab 的人有这个惊人的 repository,您可以在其中找到用于 Maven 项目的 .gitlab-ci.yml 文件的适当示例。

基本上,您需要的是以下几行:

cache:
  paths:
    - .m2/repository

请记住,如果您决定为某个作业添加本地缓存,则上面添加的全局缓存将被替换。更多关于这个here。

【讨论】:

感谢您指出本地缓存会覆盖全局缓存。这导致每次运行时都会删除 .m2 文件夹,以便再次下载所有依赖项。【参考方案4】:

您可以将缓存文件夹添加到 gitlab-ci 运行器配置并将其传递给 maven。

/etc/gitlab-runner/config.toml

[[runners]]
...
  [runners.docker]
  ...
   volumes = ["/cache", "/.m2"]
  ...

.gitlab-ci.yml

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=/.m2"

build:
  script:
    - mvn package

【讨论】:

对我有用的唯一方法是按照答案中的建议在 config.toml 上添加第二卷【参考方案5】:

如果你使用 kubernetes 作为 gitlab-runner 的执行器,你也可以使用 maven 缓存。我选择在 NFS 上使用 k8s PV 进行持久缓存(但gitlab-runner 支持其他卷类型)。由于 NFS 提供的持久性,以下配置不使用 cache gitlab 功能。

1) 在您的集群上创建一个 PersistentVolume,例如这里使用 NFS(适应您的持久层和您的选项):

apiVersion: v1
kind: PersistentVolume
metadata:
  name: gitlabrunner-nfs-volume
spec:
  capacity:
    storage: 10Gi
  mountOptions:
    - nolock
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /gitlabrunner
    server: 1.2.3.4

2) 引用 PV 以在 runner pod 中以卷的形式获取声明:

[[runners.kubernetes.volumes.pvc]]
  name = "pvc-1"
  mount_path = "/path/to/mount/point1"

注意 (03/09/18):这些参数的命令行选项尚不存在。有一个开放的issue。

3) 为 gitlab-runner 缓存指定相同的路径:

[[runners]]
  executor = "kubernetes"
  # ...
  cache_dir = "/path/to/mount/point1"

--cache-dir "/path/to/mount/point1" 处于交互模式

4)使用-Dmaven.repo.local选项中的“/path/to/mount/point1”目录

【讨论】:

【参考方案6】:

我能够使用主机卷来共享我的.m2 存储库目录。这还具有共享我的settings.xml 文件的优势(不是每个人都可能想要的)。我发现这比使用提到的cache 解决方案要快。

[[runners]]
  [runners.docker]
    volumes = ["/home/<user>/.m2:/root/.m2"]

【讨论】:

【参考方案7】:

还有另一种方法。不要使用 gitlab 缓存并使用自定义(每个项目)docker 镜像。

一些细节:

首先,您需要创建一个 maven docker 映像,其中显示了您的项目依赖项所需的所有(或大部分)。将其发布到您的注册表(gitlab 有一个)并将其用于任何运行 maven 的作业。

要创建这样的图像,我通常会在 CI 中手动创建一个附加作业。您需要在初始阶段和项目依赖关系被大量修改时触发它。

工作示例可以在这里找到:

https://gitlab.com/alexej.vlasov/syncer/blob/master/.gitlab-ci.yml - 这个项目正在使用准备好的图像,并且它还有准备这个图像的工作。

https://gitlab.com/alexej.vlasov/maven/blob/master/Dockerfile - dockerfile 运行 maven 并下载依赖项一次。

优点:

不需要每次都下载依赖项——它们在一个 docker 镜像(和 docker 层缓存在 runner 上) 作业完成后无需上传工件 不使用 maven 的作业中未下载缓存

【讨论】:

嗨,Alexey,您答案中的链接似乎已关闭。您能否在答案中分享这些文件的内容? @Jodiug 这似乎是一些 GitLab 访问问题。这些项目是公开的,任何人都应该可以访问。可以再试一次吗? 第二个链接现在有效 - 第一个链接无效 (404)。也许存储库已变为私有? 不,它是公开的。我已更改为私有并将其备份给公众。请立即尝试。 @Jodiug【参考方案8】:

当您使用 CI_PROJECT_DIR 变量时,您不必在变量部分声明 MAVEN_OPTS(克隆存储库和运行作业的完整路径)

cache:
    key: maven-cache
    paths:
    - $CI_PROJECT_DIR/.m2/

【讨论】:

以上是关于如何为 GitLab CI 运行器启用 Maven 工件缓存?的主要内容,如果未能解决你的问题,请参考以下文章

Gitlab CI/CD 运行器:找不到 mvn 命令

如何为私有 GKE 集群启用 Gitlab CI/CD?

gitlab-ci 注册运行器 x509

如何使用彼此独立的不同运行器运行 Gitlab CI 作业?

gitlab-ci 运行器中具有不同到期时间的多条路径

如何在 Gitlab CI shell 运行器上构建失败