优化 GitLab CI/CD 配置文件
您可以使用以下方法降低 GitLab CI/CD 配置文件中的复杂性和重复配置:
- 特定于 YAML 的功能,例如 anchors (
&
)、别名 (*
) 和 map merging (<<
)。阅读有关各种 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 # Hidden yaml configuration that defines an anchor named 'job_configuration'
image: ruby:2.6
services:
- postgres
- redis
test1:
<<: *job_configuration # Add the contents of the 'job_configuration' alias
script:
- test1 project
test2:
<<: *job_configuration # Add the contents of the 'job_configuration' alias
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 锚点与脚本、before_script
和 after_script
结合使用:
.some-script-before: &some-script-before
- echo "Execute this script first"
.some-script: &some-script
- echo "Execute this script second"
- echo "Execute this script too"
.some-script-after: &some-script-after
- echo "Execute this script last"
job1:
before_script:
- *some-script-before
script:
- *some-script
- echo "Execute something, for this job only"
after_script:
- *some-script-after
job2:
script:
- *some-script-before
- *some-script
- echo "Execute something else, for this job only"
- *some-script-after
使用 extends
来重用配置部分
您可以使用 extends
关键字 在多个作业中重用配置。它类似于 YAML 锚点,但更简单,您可以使用 extends
和 includes
。
extends
支持多级继承。您应该避免使用三个以上的级别,但您可以使用多达 11 个级别。以下示例具有两个继承级别:
.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: base var 1
test1:
extends: .base
variables:
VAR1: test1 var 1
VAR2: test2 var 2
test2:
extends: .base
variables:
VAR2: test2 var 2
test3:
extends: .base
variables: {}
test4:
extends: .base
variables: null
合并配置:
test1:
script: test
variables:
VAR1: test1 var 1
VAR2: test2 var 2
test2:
script: test
variables:
VAR1: base var 1
VAR2: test2 var 2
test3:
script: test
variables:
VAR1: base var 1
test4:
script: test
variables: null
extends
和 include
一起使用
要重用来自不同配置文件的配置,请结合使用 extends
和 include
。
在以下示例中,在 included.yml
文件中定义了一个 script
。
然后,在 .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: "the details"
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: "is-awesome"
extends:
- .only-important
- .in-docker
script:
- rake rspec
结果是这个 rspec
作业:
rspec:
variables:
URL: "http://docker-url.internal"
IMPORTANT_VAR: "the details"
GITLAB: "is-awesome"
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
标签
- 引入于 13.9 版本
rules
关键字的支持引入于 14.3 版本。
使用 !reference
自定义 YAML 标签从其他作业部分选择关键字配置,并在当前部分中重用它。与 YAML 锚点不同,您也可以使用 !reference
标签来重用来自 included 配置文件的配置。
在以下示例中,来自两个不同位置的 script
和一个 after_script
在 test
作业中被重用:
-
setup.yml
:.setup: script: - echo creating environment
-
.gitlab-ci.yml
:include: - local: setup.yml .teardown: after_script: - echo deleting environment test: script: - !reference [.setup, script] - echo running my own command after_script: - !reference [.teardown, after_script]
在下面的例子中,test-vars-1
重用了 .vars
中的所有变量,而 test-vars-2
选择了一个特定的变量并将其作为一个新的 MY_VAR
变量重用。
.vars:
variables:
URL: "http://my-url.internal"
IMPORTANT_VAR: "the details"
test-vars-1:
variables: !reference [.vars, variables]
script:
- printenv
test-vars-2:
variables:
MY_VAR: !reference [.vars, variables, IMPORTANT_VAR]
script:
- printenv
在 script
、before_script
和 after_script
中嵌套 !reference
标签
引入于 14.8 版本。
您可以在 script
、before_script
和 after_script
部分中嵌套最多 10 层的 !reference
标签。在构建更复杂的脚本时,使用嵌套标签来定义可重用的部分。例如:
.snippets:
one:
- echo "ONE!"
two:
- !reference [.snippets, one]
- echo "TWO!"
three:
- !reference [.snippets, two]
- echo "THREE!"
nested-references:
script:
- !reference [.snippets, three]
在这个例子中,nested-references
作业运行所有三个 echo
命令。
配置您的 IDE 支持 !reference
标签
流水线编辑器支持 !reference
标签。但是,默认情况下,您的编辑器可能会将自定义 YAML 标签(如 !reference
)的架构规则视为无效。您可以配置一些编辑器来接受 !reference
标签。例如:
-
在 VS Code 中,您可以设置
vscode-yaml
来解析settings.json
文件中的customTags
:"yaml.customTags": [ "!reference sequence" ]
-
在 Sublime Text 中,如果您使用的是
LSP-yaml
包,则可以在LSP-yaml
用户设置中设置customTags
:{ "settings": { "yaml.customTags": ["!reference sequence"] } }