写点什么

Gitlab CI/CD 中的 Cache 机制

用户头像
Chong
关注
发布于: 2020 年 04 月 22 日
Gitlab CI/CD 中的 Cache 机制

Cache 的目的



在GitLab CI/CD 中,在 pipeline 中的一些 job 可能会产生一些结果文件,Cache 机制的引入就是为了加快 job 执行的时间。Cache 在使用时制定一系列的文件或者文件目录,使得其在不同的 job 之间被缓存下来。这样当某一个 job 需要依赖于之前步骤产生的一些文件结果,Cache 就帮助我们在上一个 job 将产生的结果缓存下来并且在当前的 job 进行使用。



Cache 的使用方法



首先 cache 的定义范围可以全局定义,这样所有的 job 都会采用这个全局定义的 cache 设置。当然,每个 job 内也可以定义自己特有的 cache 来覆盖全局的配置。



Cache 在使用上主要的配置有以下几种:



1. Cache:paths



paths主要是来指定需要被缓存的文件路径,需要特别指出的是这里的 paths 是相对路径,是相对于gitlab中项目目录的路径,也就是说被缓存的文件都是在项目目录之内的。



以如下配置为例:



rspec:
script: test
cache:
paths:
- binaries/*.apk
- .config



binaries 目录下以 .apk 结尾的所有文件以及 .config 文件会被缓存下来。



当然,如果如果在 job 内部也定义了 cache 配置,全局的配置就会被覆盖,例如:



cache:
paths:
- my/files
rspec:
script: test
cache:
paths:
- binaries/



在 job rspec 中仅 binaries 目录下的所有文件会被缓存,而不是binaries 目录下以 .apk 结尾的所有文件以及 .config 文件。



2. Cache:key



由于 cache 是被不同的 job 所共享,如果不同的 jobs采用了不同的 path 配置,那么 cache 会在每个 job 被执行的时候被覆盖。cache:key 就是为了解决这个问题,当我们给不同 job 定义了不同的 cache:key 时, 每个 job 都会有一个独立的 cache,不同的 key 下的缓存也不会相互影响。



cache:key 结合 GitLab CI/CD 中预定义的参数可以有不同的效果:



比如,不同的分支采用不同的 cache,防止分支之间相互影响:



cache:
key: ${CICOMMITREF_SLUG}



比如每个分支的每个 job 使用不同的 cache :



cache:
key: "$CIJOBNAME-$CICOMMITREF_SLUG"



再比如每个分支的每个 job 使用不同的 stage:



cache:
key: "$CIJOBSTAGE-$CICOMMITREF_SLUG"



比如不同的分支之间需要共享 cache,但是 pipeline 中的 job 之间的 cache 是相互独立的:



cache:
key: ${CIJOBNAME}



最后,当 key 没有被特别定义的时候,默认为 default,所有没定义 key 的 cache 使用的是同一份 cache,会随着 job 的执行一直被覆盖。



3. Cache:policy



在默认情况下,如果有 cache 的配置,那么每个 job 会在开始执行前将对应路径的文件下载下来,并在任务结束前重新上传,不管文件是否有变化都会如此操作。这个默认的配置是 cache:policy 中的 pull-push 策略。



但是如果我们已经知道,某个 job 只是使用的其他 job 改变的文件,自身并无改变对应路径的文件,那么就不需要进行文件上传操作,采用pull 策略即可。



反过来,某个 job 不依赖于其他 job 改变的文件,自身改变的文件被其他 job 所依赖,那么就不需要在 job 开始前进行文件下载操作,采用push 策略。这样减少了不必要的操作,在一定程度上节约了时间。



在以下配置中,job rspec使用了pull 策略,所以不会在 job 结束后进行文件的上传操作 :



rspec:
stage: test
cache:
paths:
- vendor/bundle
policy: pull
script:
- bundle exec rspec ...



4. Cache 的继承



如果在使用中,有 job 大部分配置跟全局配置是一样的,但是部分不同,就可以采用继承的方式,而不必全部重写。例如,仅需要覆盖 cache:policy的配置:



cache: &globalcache
key: ${CICOMMITREFSLUG}
paths:
- vendor/
policy: pull-push
job:
cache:
# 继承全局配置
<<: *global_cache
# 覆盖 policy
policy: pull



5. Cache 的禁用



如果整个 pipeline 配置全局的 cache,意味着每个 job 在没有特殊配置的情况下会使用全局的配置。但是如果某某个 job 并不使用到 cache,包括缓存文件的上传和下载,那么可以进行如下配置对整个 job 的 cache 禁用:



job:
cache: {}



分布式 Cache



在 GitLab CI/CD 中,我们所使用的 runner 是以 docker 的形式运行不同的任务。普通的 cache 机制,其 cache 均存储在本地,所有如果两个 job 实际运行的位置 是在不用宿主机上,其相互之间的缓存是无法共享的。



为了实现分布式 Cache,需要在配置 GitLab Runner 的 config.toml[runners.cache\]进行如下配置:



[[runners]]
limit = 10
executor = "docker"
[runners.cache]
Type = "s3"
Path = "path/to/prefix"
Shared = true
[runners.cache.s3]
ServerAddress = "s3.example.com"
AccessKey = "access-key"
SecretKey = "secret-key"
BucketName = "runner"
Insecure = false



在以上的配置中,对应的 cache 的存储路径如下:



http(s)://<ServerAddress>/<BucketName>/<Path>/project/<id>/<cache-key>



在配置,对应的存储 cache 服务器需要满足 s3 协议,当然也可以自建 cache 服务器。具体操作方法可以参考[自建cache服务器](https://docs.gitlab.com/runner/install/registryandcache_servers.html#install-your-own-cache-server)



Cache 小实践



1. .gitlab-ci.yml 配置



stages:
- test
- test2
- test3
cache:
key: "$CICOMMITREFSLUG"
paths:
- cattest.txt
job1:
stage: test
script:
- cat cattest.txt
- echo "aaaaaaaaaa" > cattest.txt
- cat cattest.txt
tags:
- base-runner
job2:
stage: test2
cache:
key: "$CICOMMITREFSLUG"
paths:
- cattest.txt
policy: pull
script:
- cat cattest.txt
- echo "bbb" >> cattest.txt
- cat cattest.txt
tags:
- base-runner
job3:
stage: test3
script:
- ls
- cat cattest.txt
- echo "ccc" >> cattest.txt
- cat cattest.txt
tags:
- base-runner



在以上配置中, job1 和 job3 使用了全局的 cache 配置,job2 独立定义了 ca che 配置,使用了 pull 策略。



2. 执行结果



  • job1 结果



Checking cache for test-wer-1...
Downloading cache.zip from http://192.168.12.139:9000/runner/cache-path/project/1242/test-wer-1 #下载 cache 路径
Successfully extracted cache
$ cat cattest.txt
aaaaaaaaaa
ccc
$ echo "aaaaaaaaaa" > cattest.txt
$ cat cattest.txt
aaaaaaaaaa
Creating cache test-wer-1...
cattest.txt: found 1 matching files
Uploading cache.zip to http://192.168.12.139:9000/runner/cache-path/project/1242/test-wer-1 #上传 cache 路径
Created cache
Job succeeded



  • job2 结果



Checking cache for test-wer-1...
cache.zip is up to date
Successfully extracted cache
$ cat cattest.txt
aaaaaaaaaa
$ echo "bbb" >> cattest.txt
$ cat cattest.txt
aaaaaaaaaa
bbb
Not uploading cache test-wer-1 due to policy # pull策略不上传缓存
Job succeeded



  • job3 结果



Checking cache for test-wer-1...
cache.zip is up to date
Successfully extracted cache
$ cat cattest.txt
aaaaaaaaaa
$ echo "ccc" >> cattest.txt
$ cat cattest.txt
aaaaaaaaaa
ccc
Creating cache test-wer-1...
cattest.txt: found 1 matching files
22.txt: found 1 matching files
Uploading cache.zip to http://192.168.12.139:9000/runner/cache-path/project/1242/test-wer-1 #上传 cache 路径
Created cache
Job succeeded



可以发现:



  • job2 获取到缓存文件 cattest.txt 的文件内容是 job1 执行后的结果,说明 job1 和 job2 之间实现了缓存共享

  • job3 获取到缓存文件 cattest.txt 的文件与 job1 执行后内容一致而非 j ob2,这是因为 job2 执行后的结果没有进行上传

  • 特别注意的是 job1 在执行任务前获取到的 cattest.txt 的文件与 job3 执行完的结果一致,这是因为这个 pipeline 我运行了多次,job1 获取的缓存是上一次 pipeline 中 job3 的执行后的缓存结果。说明 cache 在不同次 pipeline 之间也实现了共享



发布于: 2020 年 04 月 22 日阅读数: 140
用户头像

Chong

关注

还未添加个人签名 2018.08.24 加入

还未添加个人简介

评论

发布
暂无评论
Gitlab CI/CD 中的 Cache 机制