优化极狐GitLab CI/CD 配置文件
- Tier: 基础版, 专业版, 旗舰版
- Offering: JihuLab.com, 私有化部署
你可以通过使用以下功能减少极狐GitLab CI/CD 配置文件中的复杂性和重复配置:
- YAML 特定功能如 anchors (&), aliases (*), 和 map merging (<<)。
- 使用更灵活和可读的 extends 关键字。你应该尽可能使用 extends。
锚点
YAML 有一个称为“锚点”的功能,可以用来在文档中复制内容。
使用锚点来复制或继承属性。将锚点与 隐藏的任务 一起使用,为你的任务提供模板。当有重复的键时,最新包含的键将覆盖其他键。
在某些情况下(见 YAML 锚点的脚本),你可以使用 YAML 锚点来构建具有多组件的数组,这些组件在其他地方定义。例如:
yaml1.default_scripts: &default_scripts 2 - ./default-script1.sh 3 - ./default-script2.sh 4 5job1: 6 script: 7 - *default_scripts 8 - ./job-script.sh
当使用 include 关键字时,你不能跨多个文件使用 YAML 锚点。锚点仅在它们定义的文件中有效。要重用来自不同 YAML 文件的配置,请使用 !reference 标签 或 extends 关键字。
以下示例使用锚点和 map 合并。它创建了两个任务,test1 和 test2,继承了 .job_template 配置,每个都有其自定义的 script 定义:
yaml1.job_template: &job_configuration # 隐藏的 yaml 配置,定义了一个名为 'job_configuration' 的锚点 2 image: ruby:2.6 3 services: 4 - postgres 5 - redis 6 7test1: 8 <<: *job_configuration # 添加 'job_configuration' 别名的内容 9 script: 10 - test1 project 11 12test2: 13 <<: *job_configuration # 添加 'job_configuration' 别名的内容 14 script: 15 - test2 project
& 设置锚点的名称(job_configuration),<< 意味着“将给定的哈希合并到当前的哈希中”,而 * 包含命名的锚点(再次是 job_configuration)。此示例的 扩展版 是:
yaml1.job_template: 2 image: ruby:2.6 3 services: 4 - postgres 5 - redis 6 7test1: 8 image: ruby:2.6 9 services: 10 - postgres 11 - redis 12 script: 13 - test1 project 14 15test2: 16 image: ruby:2.6 17 services: 18 - postgres 19 - redis 20 script: 21 - test2 project
你可以使用锚点定义两组服务。例如,test:postgres 和 test:mysql 共享在 .job_template 中定义的 script,但使用不同的 services,分别在 .postgres_services 和 .mysql_services 中定义:
yaml1.job_template: &job_configuration 2 script: 3 - test project 4 tags: 5 - dev 6 7.postgres_services: 8 services: &postgres_configuration 9 - postgres 10 - ruby 11 12.mysql_services: 13 services: &mysql_configuration 14 - mysql 15 - ruby 16 17test:postgres: 18 <<: *job_configuration 19 services: *postgres_configuration 20 tags: 21 - postgres 22 23test:mysql: 24 <<: *job_configuration 25 services: *mysql_configuration
扩展版 是:
yaml1.job_template: 2 script: 3 - test project 4 tags: 5 - dev 6 7.postgres_services: 8 services: 9 - postgres 10 - ruby 11 12.mysql_services: 13 services: 14 - mysql 15 - ruby 16 17test:postgres: 18 script: 19 - test project 20 services: 21 - postgres 22 - ruby 23 tags: 24 - postgres 25 26test:mysql: 27 script: 28 - test project 29 services: 30 - mysql 31 - ruby 32 tags: 33 - dev
你可以看到隐藏的任务被方便地用作模板,并且 tags: [postgres] 覆盖了 tags: [dev]。
YAML 锚点的脚本
History
- 在极狐GitLab 16.9 中,引入了对 stages 关键字的锚点支持。
你可以在 script、before_script 和 after_script 中使用 YAML 锚点,以在多个任务中使用预定义命令:
yaml1.some-script-before: &some-script-before 2 - echo "Execute this script first" 3 4.some-script: &some-script 5 - echo "Execute this script second" 6 - echo "Execute this script too" 7 8.some-script-after: &some-script-after 9 - echo "Execute this script last" 10 11job1: 12 before_script: 13 - *some-script-before 14 script: 15 - *some-script 16 - echo "Execute something, for this job only" 17 after_script: 18 - *some-script-after 19 20job2: 21 script: 22 - *some-script-before 23 - *some-script 24 - echo "Execute something else, for this job only" 25 - *some-script-after
使用 extends 复用配置部分
你可以使用 extends 关键字 在多个任务中重用配置。它类似于 YAML 锚点,但更简单,并且你可以 将 extends 与 includes 一起使用。
extends 支持多级继承。由于额外的复杂性,你应该避免使用超过三级的继承,但最多可以使用十一级。以下示例有两级继承:
yaml1.tests: 2 rules: 3 - if: $CI_PIPELINE_SOURCE == "push" 4 5.rspec: 6 extends: .tests 7 script: rake rspec 8 9rspec 1: 10 variables: 11 RSPEC_SUITE: '1' 12 extends: .rspec 13 14rspec 2: 15 variables: 16 RSPEC_SUITE: '2' 17 extends: .rspec 18 19spinach: 20 extends: .tests 21 script: rake spinach
从 extends 中排除一个键
要从扩展内容中排除一个键,你必须将其分配为 null,例如:
yaml1.base: 2 script: test 3 variables: 4 VAR1: base var 1 5 6test1: 7 extends: .base 8 variables: 9 VAR1: test1 var 1 10 VAR2: test2 var 2 11 12test2: 13 extends: .base 14 variables: 15 VAR2: test2 var 2 16 17test3: 18 extends: .base 19 variables: {} 20 21test4: 22 extends: .base 23 variables: null
合并后的配置:
yaml1test1: 2 script: test 3 variables: 4 VAR1: test1 var 1 5 VAR2: test2 var 2 6 7test2: 8 script: test 9 variables: 10 VAR1: base var 1 11 VAR2: test2 var 2 12 13test3: 14 script: test 15 variables: 16 VAR1: base var 1 17 18test4: 19 script: test 20 variables: null
一起使用 extends 和 include
要重用不同配置文件中的配置,结合使用 extends 和 include。
在以下示例中,一个 script 在 included.yml 文件中定义。然后,在 .gitlab-ci.yml 文件中,extends 引用 script 的内容:
-
included.yml:
yaml.template: script: - echo Hello!
-
.gitlab-ci.yml:
yamlinclude: included.yml useTemplate: image: alpine extends: .template
合并细节
你可以使用 extends 合并哈希,但不能合并数组。用于合并的算法是“最接近的范围获胜”。当有重复的键时,极狐GitLab 基于键进行反向深度合并。最后一个成员的键总是覆盖在其他层次上定义的任何东西。例如:
yaml1.only-important: 2 variables: 3 URL: "http://my-url.internal" 4 IMPORTANT_VAR: "the details" 5 rules: 6 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 7 - if: $CI_COMMIT_BRANCH == "stable" 8 tags: 9 - production 10 script: 11 - echo "Hello world!" 12 13.in-docker: 14 variables: 15 URL: "http://docker-url.internal" 16 tags: 17 - docker 18 image: alpine 19 20rspec: 21 variables: 22 GITLAB: "is-awesome" 23 extends: 24 - .only-important 25 - .in-docker 26 script: 27 - rake rspec
结果是这个 rspec 任务:
yaml1rspec: 2 variables: 3 URL: "http://docker-url.internal" 4 IMPORTANT_VAR: "the details" 5 GITLAB: "is-awesome" 6 rules: 7 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 8 - if: $CI_COMMIT_BRANCH == "stable" 9 tags: 10 - docker 11 image: alpine 12 script: 13 - 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 标签
使用 !reference 自定义 YAML 标签从其他任务部分选择关键字配置,并在当前部分中重用它。与 YAML 锚点 不同,你还可以使用 !reference 标签重用来自 包含的 配置文件的配置。
在以下示例中,test 任务中重用了来自两个不同位置的 script 和 after_script:
-
configs.yml:
yaml.setup: script: - echo creating environment
-
.gitlab-ci.yml:
yaml1include: 2 - local: configs.yml 3 4.teardown: 5 after_script: 6 - echo deleting environment 7 8test: 9 script: 10 - !reference [.setup, script] 11 - echo running my own command 12 after_script: 13 - !reference [.teardown, after_script]
在以下示例中,test-vars-1 重用了 .vars 中的所有变量,而 test-vars-2 选择了一个特定变量,并将其重用为新的 MY_VAR 变量。
yaml1.vars: 2 variables: 3 URL: "http://my-url.internal" 4 IMPORTANT_VAR: "the details" 5 6test-vars-1: 7 variables: !reference [.vars, variables] 8 script: 9 - printenv 10 11test-vars-2: 12 variables: 13 MY_VAR: !reference [.vars, variables, IMPORTANT_VAR] 14 script: 15 - printenv
在使用 !reference 标签与 parallel:matrix 关键字 时,存在一个 已知问题。
在 script、before_script 和 after_script 中嵌套 !reference 标签
History
- 在极狐GitLab 16.9 中,引入了对 stages 关键字的 !reference 支持。
你可以在 script、before_script 和 after_script 部分中嵌套 !reference 标签多达 10 级。使用嵌套标签在构建更复杂的脚本时定义可重用的部分。例如:
yaml1.snippets: 2 one: 3 - echo "ONE!" 4 two: 5 - !reference [.snippets, one] 6 - echo "TWO!" 7 three: 8 - !reference [.snippets, two] 9 - echo "THREE!" 10 11nested-references: 12 script: 13 - !reference [.snippets, three]
在这个例子中,nested-references 任务运行所有三个 echo 命令。
配置你的 IDE 支持 !reference 标签
流水线编辑器 支持 !reference 标签。然而,像 !reference 这样的自定义 YAML 标签的模式规则可能会被你的编辑器默认视为无效。你可以配置一些编辑器以接受 !reference 标签。例如:
-
在 VS Code 中,你可以在 settings.json 文件中设置 vscode-yaml 以解析 customTags:
json"yaml.customTags": [ "!reference sequence" ]
-
在 Sublime Text 中,如果你正在使用 LSP-yaml 包,你可以在你的 LSP-yaml 用户设置中设置 customTags:
json{ "settings": { "yaml.customTags": ["!reference sequence"] } }