GitLab CI/CD提供了一种缓存机制,可用于在作业运行时节省时间。

缓存是指通过重用先前作业的相同内容来加快执行作业的时间。当您开发依赖于在构建期间通过Internet获取的其他库的软件时,此功能特别有用。

如果启用了缓存,则默认情况下,从GitLab 9.0开始,它在项目级别的作业之间共享。缓存不在项目之间共享。

[info]不要使用缓存在阶段之间传递工件,因为缓存旨在存储编译项目所需的运行时依赖项。另外,缓存定义的路径是相对于项目目录,并且无法链接到其外部的文件。

在管道中使用同一 Runner,是将该缓存传递到后续阶段或管道的最简单,最有效的方法。

从Runner 的角度来看,为了使缓存有效运行,必须满足以下条件之一:

  • 使用同一个 Runner
  • 使用分布式缓存的Runner(缓存存储在 S3 存储桶中)
  • 使用相同体系结构的多个Runner 使用 NFS 共享存储缓存

1. Java 项目缓存示例

  1. stages:
  2. - build
  3. build:
  4. stage: build
  5. image: harbor.xiodi.cn/tools/openjdk:11.0.6
  6. tags:
  7. - docker
  8. - host20133-docker
  9. variables:
  10. MAVEN_OPTS: "-Dmaven.repo.local=.m2"
  11. script:
  12. - chmod +x ./mvnw && ./mvnw package
  13. cache:
  14. paths:
  15. - .m2

2. 在特定作业上禁用缓存

如果已全局定义了缓存,则意味着每个作业将使用相同的定义。如果要想对某个作业禁用缓存,可以使用空哈希

  1. job:
  2. cache: {}

3. 缓存的可用性

缓存是一种优化,但不能保证始终有效,因此您需要准备好在需要它们的每个作业中重新生成所有缓存的文件。

3.1 缓存的存储位置

GitLab Runner 执行器 缓存的默认路径
Shell 在本地,存储在 gitlab-runner 用户的主目录下: /home/gitlab-runner/cache/<user>/<project>/<cache-key>/cache.zip
Docker 在本地,存储在 docker 卷: /var/lib/docker/volumes/<volume-id>/_data/<user>/<project>/<cache-key>/cache.zip
  1. $ ls /var/lib/docker/volumes/runner-6fzqvskx-project-1-concurrent-0-cache-3c3f060a0374fc8bc39395164f415a70/_data/edu-java-demo/edu-java-spring/
  2. default
  3. $ ls /var/lib/docker/volumes/runner-6fzqvskx-project-1-concurrent-0-cache-3c3f060a0374fc8bc39395164f415a70/_data/edu-java-demo/edu-java-spring/default/
  4. cache.zip

3.2 缓存的压缩和解压

在最简单的情况下,请考虑仅使用安装了Runner的一台计算机,并且项目的所有作业都在同一主机上运行。缓存默认压缩为 cache.zip。

  1. stages:
  2. - test
  3. - build
  4. test:
  5. stage: test
  6. image: harbor.xiodi.cn/tools/openjdk:11.0.6
  7. tags:
  8. - docker
  9. - host20133-docker
  10. variables:
  11. MAVEN_OPTS: "-Dmaven.repo.local=.m2"
  12. script:
  13. - chmod +x ./mvnw && ./mvnw test
  14. cache:
  15. key: maven-repo-cache
  16. paths:
  17. - .m2
  18. build:
  19. stage: build
  20. image: harbor.xiodi.cn/tools/openjdk:11.0.6
  21. tags:
  22. - docker
  23. - host20133-docker
  24. variables:
  25. MAVEN_OPTS: "-Dmaven.repo.local=.m2"
  26. script:
  27. - chmod +x ./mvnw && ./mvnw package
  28. cache:
  29. key: maven-repo-cache
  30. paths:
  31. - .m2

通过在单台主机上使用的单个 Runner,确保了缓存的可用性,否则,可能就没有可用的缓存。

在缓存的过程中,还需要考虑以下几点:

  • 具有相同缓存 key 的作业其缓存将会被覆盖,不管路径是否相同。
  • 从缓存压缩包中提取到作业的工作目录中,而 Runner 不在乎缓存是否被覆盖。

3.3 缓存不匹配

下表列举出了缓存不匹配的一些原因和一些解决方法。

缓存不匹配的原因 如何修复
多个独立的执行器(不在自动缩放模式下)附加到一个项目,而没有共享缓存 使用一个 Runner 或启用分布式缓存的多个 Runner
未启用分布式缓存的自动缩放模式下的 Runner 配置自动缩放执行器使用分布式缓存
磁盘空间不足 清除一些空间。当前,没有自动的方法可以做到这一点。
相同的 key 的作业用于缓存不同路径 使用不同的缓存 key,保证不会覆盖缓存

//例1:

  1. stages:
  2. - build
  3. - test
  4. job A:
  5. stage: build
  6. tags:
  7. - docker
  8. script:
  9. - ls -a
  10. - if [ ! -d public ]; then mkdir public && echo `date` > public/public.txt; fi
  11. cache:
  12. key: keyA
  13. paths:
  14. - public/
  15. job B:
  16. stage: test
  17. tags:
  18. - docker
  19. script:
  20. - ls -a
  21. - if [ ! -d vendor ]; then mkdir vendor && echo `date` > vendor/vendor.txt; fi
  22. cache:
  23. key: keyA
  24. paths:
  25. - vendor/

运行的流程:

  • job A 运行
  • public/ 目录被缓存为 cache.zip
  • job B 运行
  • 如果先前有缓存,则解压
  • vendor/ 被缓存为 ceche.zip 并覆盖前一个
  • 下次 job A 运行时,它将使用 job B 的缓存,因此缓存无效

要解决此问题,请设置相同的路径和 key

在另一种情况下,如果您为项目分配了多个执行器,但又没有启用分布式缓存,即使使用相同的 key,也不会进行覆盖。

4. 清除缓存

清除缓存的方法有两种:

  • 通过更改清除缓存
  • 手动清除缓存

4.1 通过更改清除缓存

在 .gitlab-ci.yml 中设置一个 cache.key,进行覆盖清除

4.2 手动清除缓存

4.3 使用缓存加速构建 - 图1