我们使用 GitLab CI 和共享运行器来进行持续集成。对于每个构建,运行程序都会下载大量 Maven 工件。
有没有办法配置 GitLab CI 来缓存这些工件,以便我们可以通过防止一遍又一遍地下载相同的工件来加快构建过程?
Gitlab CI 允许您定义某些路径,其中包含应在每个作业或构建的基础上在构建之间缓存的数据(有关更多详细信息,请参阅此处)。结合 khmarbaise 的建议,这可以用于缓存多个构建之间的依赖关系。
缓存构建中所有作业依赖项的示例:
cache:
paths:
- .m2/repository
variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
maven_job:
script:
- mvn clean install
根据 GitLab 问题跟踪器上的对话,我设法更改 Maven 本地存储库路径并将其放入
./.m2/repository/
目录中,然后我们将通过将此全局块添加到 CI 配置来在运行之间保持不变:
cache:
paths:
- ./.m2/repository
# keep cache across branch
key: "$CI_BUILD_REF_NAME"
不幸的是,根据this StackOverflow回答,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-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
如果您使用kubernetes作为gitlab-runner的执行器,您还可以使用maven缓存。我选择使用 k8s PV 在 NFS 上建立持久缓存(但 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):这些参数的命令行选项尚不存在。有一个未解决的问题。
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”目录
我能够使用主机卷来共享我的
.m2
存储库目录。这还有一个优点是可以共享我的 settings.xml
文件(不是每个人都想要)。我发现这比使用提到的 cache
解决方案更快。
[[runners]]
[runners.docker]
volumes = ["/home/<user>/.m2:/root/.m2"]
还有另一种方法。不要使用 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 并下载一次依赖项。
优点:
使用 CI_PROJECT_DIR 变量时,不必在变量部分声明 MAVEN_OPTS(克隆存储库和运行作业的完整路径)
cache:
key: maven-cache
paths:
- $CI_PROJECT_DIR/.m2/