Gitlab-CI Include and Extends

Include

Func: 用于引入.yml.yaml结尾的YAML文件,其他类型的文件不能引入。我们可以利用include让.gitlab-ci.yml文件的结构更清晰,同时也可以把一些需要集中管理维护的job写在一个YAML文件中,放在一个公共仓库,让其他项目的CI来引入该文件。
举个例子,假如每个团队都需要执行一个report的job,用于报告版本发布的相关信息,那么我们可以把这个job写在report.yml文件,放在一个公共的仓库,然后每个团队的.gitlab-ci.yml文件引入report.yml。假如以后需要在report中添加一些需要上报的内容,只需要修改公共项目的report.yml即可。
当然,由于report.yml会被多个项目引用,所以必须通用且拥有较好的扩展性与兼容性,如果改一点东西都需要每个团队去配合你改,那就比较糟糕了。

include注意要点
假设模板文件 example.yml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
variables:
POSTGRES_USER: user
POSTGRES_PASSWORD: testing_password
POSTGRES_DB: $CI_ENVIRONMENT_SLUG

production:
stage: production
script:
- install_dependencies
- deploy
environment:
name: production
url: https://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
only:
- master

.gitlab-ci.yml 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
include: 'example.yml'

image: alpine:latest

variables:
POSTGRES_USER: root
POSTGRES_PASSWORD: secure_password

stages:
- build
- test
- production

production:
environment:
url: https://domain.com
  • include的文件和.gitlab-ci.ymlvariable中定义了同一个变量,则该变量被.gitlab-ci.yml中定义的变量覆盖。如上例,最终example.yml中变量的取值为:
    • POSTGRES_USER:root
    • POSTGRES_PASSWORD:secure_password
    • POSTGRES_DB: $CI_ENVIRONMENT_SLUG
  • include的文件和.gitlab-ci.yml都定义了同一个job,则会将两个job进行合并。上例中example.yml中production job的enviroment url取值为https://domain.com

此外,include还可以使用关键字template去引入.gitlab-ci.yml模板,更为详细的信息可以阅读官方文档

Extends

Func:extends替代了YAML Anchors,可读性好,而且更加灵活。它定义一个可以让job去继承的模板,这样可以让我们把一些共同的key进行抽象,方便以后的维护与扩展。

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
.tests:
script: rake test
stage: test
only:
refs:
- branches

rspec:
extends: .tests
script: rake rspec
only:
variables:
- $RSPEC

Result:

1
2
3
4
5
6
7
8
rspec:
script: rake rspec
stage: test
only:
refs:
- branches
variables:
- $RSPEC

以上是官方给的例子:tests作为模板,rspec去继承它,如果二者都有相同的key,则使用子类的value覆盖父类。

extend相关详细的信息请阅读:gitlab-ci extends

include and extends

includeextends支持一起使用。如果只有include,仅能让某个项目引用某个YAML文件,然后根据调解触发对应的job,而加入extend后,我们可以把一些公共属性或者方法(主要是Script)也进行统一管理。这让我们可以更好地去抽象与统一维护。

Example:

  • B.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    variables:
    TEST_VAR: B

    .template:
    stage: test
    only:
    - master
    script:
    - echo_hello
    - echo "VAR1 = ${VAR1}"
    - echo "VAR2 = ${VAR2}"
    - echo "TEST_VAR = ${TEST_VAR}"
  • .gitlab-ci.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    variables:
    TEST_VAR: A

    include:
    - B.yml

    job_a:
    before_script:
    - |
    function echo_hello(){
    echo "hello world!"
    }
    - VAR1="hello"
    - VAR2="world"
    extends: .template
    only:
    variables:
    - $A

master分支更新或定义了A变量时,触发CI,执行结果:

1
2
3
4
hello world!
VAR1 = hello
VAR2 = world
TEST_VAR = A

以上结果表明:

  1. .gitlab-ci.yml中执行的job,使用的环境变量是.gitlab-ci.yml文件定义的变量,故输出TEST_VAR = A
  2. extends的动作早于before_script

Summary

我们在做持续集成的时候应该仔细思考哪些东西可以用到includeextends,这样可以提高CI/CD的扩展性与可维护性。