优化 GitLab CI/CD 配置文件
- 层级:Free、Premium、Ultimate
- 提供:GitLab.com、GitLab 自托管、GitLab Dedicated
你可以通过使用以下方法减少 GitLab CI/CD 配置文件的复杂性和重复配置:
- YAML 特定功能,如 锚点 (
&)、别名 (*) 和映射合并 (<<)。阅读更多关于各种 YAML 功能。 extends关键字,它更灵活且可读性更强。你应该尽可能使用extends。
锚点
YAML 有一个名为“锚点”的功能,你可以用它来在文档中复制内容。
使用锚点来复制或继承属性。将锚点与 隐藏作业 结合使用,为你的作业提供模板。当存在重复键时,最新包含的键会覆盖其他键。
在某些情况下(参见 脚本用的 YAML 锚点),你可以使用 YAML 锚点来构建由其他地方定义的多个组件组成的数组。例如:
.default_scripts: &default_scripts
- ./default-script1.sh
- ./default-script2.sh
job1:
script:
- *default_scripts
- ./job-script.sh当你使用 include 关键字时,不能跨多个文件使用 YAML 锚点。锚点仅在定义它们的文件中有效。要从不同的 YAML 文件重用配置,请使用 !reference 标签 或 extends 关键字。
下面的示例使用了锚点和映射合并。它创建了两个作业 test1 和 test2,它们继承了 .job_template 配置,每个作业都有自己自定义的 script 定义:
.job_template: &job_configuration # 隐藏的 YAML 配置,定义了一个名为 'job_configuration' 的锚点
image: ruby:2.6
services:
- postgres
- redis
test1:
<<: *job_configuration # 添加 'job_configuration' 别名的内容
script:
- test1 project
test2:
<<: *job_configuration # 添加 'job_configuration' 别名的内容
script:
- test2 project& 设置了锚点的名称(job_configuration),<< 表示“将给定的哈希合并到当前哈希中”,而 * 包含命名的锚点(再次是 job_configuration)。此示例的 展开版 如下:
.job_template:
image: ruby:2.6
services:
- postgres
- redis
test1:
image: ruby:2.6
services:
- postgres
- redis
script:
- test1 project
test2:
image: ruby:2.6
services:
- postgres
- redis
script:
- test2 project你可以使用锚点来定义两组服务。例如,test:postgres 和 test:mysql 共享 .job_template 中定义的 script,但使用不同的 services,分别定义在 .postgres_services 和 .mysql_services 中:
.job_template: &job_configuration
script:
- test project
tags:
- dev
.postgres_services:
services: &postgres_configuration
- postgres
- ruby
.mysql_services:
services: &mysql_configuration
- mysql
- ruby
test:postgres:
<<: *job_configuration
services: *postgres_configuration
tags:
- postgres
test:mysql:
<<: *job_configuration
services: *mysql_configuration展开版 如下:
.job_template:
script:
- test project
tags:
- dev
.postgres_services:
services:
- postgres
- ruby
.mysql_services:
services:
- mysql
- ruby
test:postgres:
script:
- test project
services:
- postgres
- ruby
tags:
- postgres
test:mysql:
script:
- test project
services:
- mysql
- ruby
tags:
- dev你可以看到隐藏作业被方便地用作模板,并且 tags: [postgres] 覆盖了 tags: [dev]。
脚本用的 YAML 锚点
你可以将 YAML 锚点 与 script、before_script 和 after_script 结合使用,以在多个作业中使用预定义命令:
.some-script-before: &some-script-before
- echo "先执行这个脚本"
.some-script: &some-script
- echo "接着执行这个脚本"
- echo "也执行这个脚本"
.some-script-after: &some-script-after
- echo "最后执行这个脚本"
job1:
before_script:
- *some-script-before
script:
- *some-script
- echo "仅为此作业执行某些操作"
after_script:
- *some-script-after
job2:
script:
- *some-script-before
- *some-script
- echo "为另一个作业执行其他操作"
- *some-script-after使用 extends 关键字重用配置部分
你可以使用 extends 关键字 在多个作业中重用配置。它与 YAML 锚点 类似,但更简单,并且你可以 结合 extends 和 include 使用。
extends 支持多级继承。由于额外的复杂性,你应该避免使用超过三级,但最多可以使用十一级。以下示例有两级继承:
.tests:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
.rspec:
extends: .tests
script: rake rspec
rspec 1:
variables:
RSPEC_SUITE: '1'
extends: .rspec
rspec 2:
variables:
RSPEC_SUITE: '2'
extends: .rspec
spinach:
extends: .tests
script: rake spinach从 extends 中排除某个键
要从扩展内容中排除某个键,你必须将其赋值为 null,例如:
.base:
script: test
variables:
VAR1: 基础变量 1
test1:
extends: .base
variables:
VAR1: 测试1变量 1
VAR2: 测试2变量 2
test2:
extends: .base
variables:
VAR2: 测试2变量 2
test3:
extends: .base
variables: {}
test4:
extends: .base
variables: null合并后的配置:
test1:
script: test
variables:
VAR1: 测试1变量 1
VAR2: 测试2变量 2
test2:
script: test
variables:
VAR1: 基础变量 1
VAR2: 测试2变量 2
test3:
script: test
variables:
VAR1: 基础变量 1
test4:
script: test
variables: null结合使用 extends 和 include
要从不同的配置文件重用配置,请结合使用 extends 和 include。
在以下示例中,script 在 included.yml 文件中定义。然后在 .gitlab-ci.yml 文件中,extends 引用了 script 的内容:
-
included.yml:.template: script: - echo Hello! -
.gitlab-ci.yml:include: included.yml useTemplate: image: alpine extends: .template
合并细节
你可以使用 extends 来合并哈希但不能合并数组。当存在重复键时,GitLab 会基于键进行反向深度合并。来自最后一个成员的键总是覆盖其他级别定义的内容。例如:
.only-important:
variables:
URL: "http://my-url.internal"
IMPORTANT_VAR: "详细信息"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == "stable"
tags:
- production
script:
- echo "Hello world!"
.in-docker:
variables:
URL: "http://docker-url.internal"
tags:
- docker
image: alpine
rspec:
variables:
GITLAB: "很棒"
extends:
- .only-important
- .in-docker
script:
- rake rspec结果是这个 rspec 作业:
rspec:
variables:
URL: "http://docker-url.internal"
IMPORTANT_VAR: "详细信息"
GITLAB: "很棒"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == "stable"
tags:
- docker
image: alpine
script:
- rake rspec在此示例中:
variables部分合并,但URL: "http://docker-url.internal"覆盖了URL: "http://my-url.internal"。tags: ['docker']覆盖了tags: ['production']。script不合并,但script: ['rake rspec']覆盖了script: ['echo "Hello world!"']。你可以使用 YAML 锚点 来合并数组。
!reference 标签
使用自定义 YAML 标签 !reference 来选择其他作业部分的配置并将其重用在当前部分。与 YAML 锚点 不同,你可以使用 !reference 标签来重用 included 配置文件中的配置。
在以下示例中,test 作业重用了来自两个不同位置的 script 和 after_script:
-
configs.yml:.setup: script: - echo 创建环境 -
.gitlab-ci.yml:include: - local: configs.yml .teardown: after_script: - echo 删除环境 test: script: - !reference [.setup, script] - echo 执行我自己的命令 after_script: - !reference [.teardown, after_script]
在以下示例中,test-vars-1 重用了 .vars 中的所有变量,而 test-vars-2 选择了一个特定的变量并将其作为新的 MY_VAR 变量重用。
.vars:
variables:
URL: "http://my-url.internal"
IMPORTANT_VAR: "详细信息"
test-vars-1:
variables: !reference [.vars, variables]
script:
- printenv
test-vars-2:
variables:
MY_VAR: !reference [.vars, variables, IMPORTANT_VAR]
script:
- printenv在使用 !reference 标签和 parallel:matrix 关键字 时,有一个 已知问题。
在 script、before_script 和 after_script 中嵌套 !reference 标签
你可以在 script、before_script 和 after_script 部分中将 !reference 标签嵌套多达 10 级。使用嵌套标签在构建更复杂的脚本时定义可重用部分。例如:
.snippets:
one:
- echo "一!"
two:
- !reference [.snippets, one]
- echo "二!"
three:
- !reference [.snippets, two]
- echo "三!"
nested-references:
script:
- !reference [.snippets, three]在此示例中,nested-references 作业运行所有三个 echo 命令。
配置你的 IDE 以支持 !reference 标签
pipeline editor 支持 !reference 标签。但是,自定义 YAML 标签(如 !reference)的架构规则默认可能会被你的编辑器视为无效。
你可以配置一些编辑器以接受 !reference 标签。例如:
-
在 VS Code 中,你可以在
settings.json文件中将vscode-yaml设置为解析customTags:"yaml.customTags": [ "!reference sequence" ] -
在 Sublime Text 中,如果你使用的是
LSP-yaml包,你可以在LSP-yaml用户设置中设置customTags:{ "settings": { "yaml.customTags": ["!reference sequence"] } }