[TOC]

0x00 简述

Q:什么是.gitlab-ci.yaml?它有什么作用?
答:gitlab-ci全称是gitlab continuous integration的意思就是持续集成;gitlab-ci.yaml是Gitlab-CI做持续集成和发布的执配置文件,里面定义了如何测试、编译、以及部署阶段执行的脚本,该文件的配置高度依赖于项目本身,以及 CI/CD 流水线的需求。即每次在我们push到gitlab的时候,都会触发此脚本

WeiyiGeek.CI/CD流程概览

WeiyiGeek.CI/CD流程概览

gitlab-ci.yml 其配置文件主要由以下部分组成:

  • 1.Pipeline
    描述:一次 Pipeline 其实相当于一次构建任务,里面可以包含很多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。任何提交或者 Merge Request 的合并都可以触发 Pipeline 构建,如下图所示

    1
    2
    3
    4
    5
    +----------------+           +----------+
    | | trigger | |
    | Commit / Merge +---------->+ Pipeline |
    | | | |
    +----------------+ +----------+
  • 2.Stages
    描述:Stages 表示一个构建阶段,也就是上面提到的一个流程。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages会有以下特点:

    • 1) 所有 Stages 会按照顺序运行,即当一个 Stage 完成后下一个 Stage 才会开始
    • 2) 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
    • 3) 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败
      Stages 和 Pipeline 的关系如下所示:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      +--------------------------------------------------------+
      | |
      | Pipeline |
      | |
      | +-----------+ +------------+ +------------+ |
      | | Stage 1 |->| Stage 2 |->| Stage 3 | |
      | +-----------+ +------------+ +------------+ |
      | |
      +--------------------------------------------------------+
  • 3.Jobs
    描述:Jobs 表示构建工作,表示某个 Stage 里面执行的工作。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:
  • 1) 相同 Stage 中的 Jobs 会并行执行
  • 2) 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
  • 3) 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败, 但是可以通过参数设置allow_failure进行跳过

Jobs 和 Stage 的关系如下所示:

1
2
3
4
5
6
7
8
9
+------------------------------------------+
| |
| Stage 1 |
| |
| +---------+ +---------+ +---------+ |
| | Job 1 | | Job 2 | | Job 3 | |
| +---------+ +---------+ +---------+ |
| |
+------------------------------------------+

.gitlab-ci.yml 基础实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#构建阶段-任务
stages:
- analytics
- test
- build
- package
- deploy

#构建工作job名称
build_analytics:
#该工作执行阶段
stage: analytics
#设置只对master分支有效
only:
- master
- tags
tags:
- runner-tag-snoreqube
script:
- echo "=============== 开始代码质量检测 ==============="
- echo "=============== 结束代码质量检测 ==============="

build_test:
stage: test
only:
- master
- tags
tags:
- runner-tag
script:
- echo "=============== 开始测试任务 ==============="
- echo "=============== 结束测试任务 ==============="


build:
stage: build
only:
- master
- tags
tags:
- runner-tag
script:
- echo "=============== 开始编译任务 ==============="
- echo "=============== 结束编译任务 ==============="

package:
stage: package
tags:
- runner-tag
script:
- echo "=============== 开始打包任务 ==============="
- echo "=============== 结束打包任务 ==============="

deploy_test:
stage: deploy
tags:
- runner-tag
#输出在gitlab-ci中设置的变量
script:
- echo "=============== 自动部署到测试服务器 ==============="
- echo "测试服务器:" ${SERVER_TEST}
#环境变量
environment:
name: test
url: https://staging.example.com

deploy_test_manual:
stage: deploy
tags:
- runner-tag
script:
- echo "=============== 手动部署到测试服务器 ==============="
environment:
name: test
url: https://staging.example.com
#设置条件 manual 允许失败
when: manual

deploy_production_manual:
stage: deploy
tags:
- runner-tag
script:
- echo "=============== 手动部署到生产服务器 ==============="
- echo "测试服务器:" ${SERVER_TEST}
environment:
name: production
url: https://staging.example.com
when: manual


0x01 配置文档

描述:本章主要用于描述 .gitlab-ci.yml 的语法,. gitlab-ci.yml 文件被用来管理项目的 runner 任务。
任务是由Runners接管并且由服务器中runner执行。更重要的是每一个任务的执行过程都是独立运行的,这将意味着上个脚本产生的变量是无法在下一个任务脚本中进行使用。

下面列出保留字段,这些保留字段不能被定义为 job 名称:

1
2
3
4
5
6
7
8
9
关键字 是否必须   描述
image 否 用于docker镜像,查看docker文档
services 否 用于docker服务,查看docker文档
stages 否 定义构建阶段
types 否 stages 的别名(已废除)
before_script 否 定义在每个job之前运行的命令
after_script 否 定义在每个job之后运行的命令
variable 否 定义构建变量
cache 否 定义一组文件列表,可在后续运行中使用

开始构建之前YAML文件定义了一系列带有约束说明的任务,用下面这个例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
image: ruby:2.1
services:
- postgres

before_script:
- bundle install

after_script:
- rm secrets

stages:
- build
- test
- deploy

job1:
stage: build
script:
- execute-script-for-job1
only:
- master
tags:
- docker

job2:
stage: deploy
script: "execute-script-for-job2"

上面这个例子就是带有四个独立任务的CI配置,每个任务分别执行不同的命令,可以看出这些任务都是以任务名开始并且至少要包含 script 部分,并且script 可以直接执行系统命令(例如:./configure;make;make install)或者是直接执行脚本(test.sh)需要注意其执行权限;


gitlab-ci.yml指令约束说明

  • image和services

    这两个关键字允许使用一个自定义的Docker镜像和一系列的服务,并且可以用于整个job周期。详细配置文档请查看:https://docs.gitlab.com/ce/ci/docker/README.html

  • before_script

    用来定义所有job之前运行的命令,包括deploy(部署) jobs,但是在修复artifacts之后。它可以是一个 数组或者是多行字符串。

  • after_script

    用来定义所有job之后运行的命令。它必须是一个数组或者是多行字符串

  • stages

    前面简述了stages与pipelins之键的关系,它用来定义可以被job调用的stages。stages的规范允许 有灵活的多级pipelines,stages中的元素顺序决定了对应job的执行顺序。

    • 1.相同stage的job可以平行执行。
    • 2.下一个stage的job会在前一个stage的job成功后开始执行。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      #例如上面stages构建阶段任务的例子
      1. 首先,所有 build 的jobs都是并行执行的。
      2. 所有 build 的jobs执行成功后, testjobs才会开始并行执行。
      3. 所有 testjobs执行成功, deploy 的jobs才会开始并行执行。
      4. 所有的 deploy 的jobs执行成功,commit才会标记为 success
      5. 任何一个前置的jobs失败了,commit会标记为 failed 并且下一个stages的jobs都不会执行

      #有两个特殊的例子值得一提:
      1. 如果 .gitlab-ci.yml 中没有定义 stages ,那么job's stages 会默认定义为 build , test 和 deploy 。
      2. 如果一个job没有指定 stage ,那么这个任务会分配到 test stage。
  • variables
    GItLab CI 允许在 .gitlab-ci.yml 文件中添加变量,并在job环境中起作用。因为这些配置是存储在git仓库中,所以最好是存储项目的非敏感配置,例如:

    1
    2
    variables:
    DATABASE_URL:"postgres://postgres@postgres/WeiyiGeek"

    这些变量可以被后续的命令和脚本使用。服务容器也可以使用YAML中定义的变量,因此我们可以很好的调控服务容
    器。变量也可以定义成job level。除了用户自定义的变量外,Runner也可以定义它自己的变量例如 CI_COMMIT_REG_NAME 它的值表示用于构建项目的分支或tag名称。除了在 .gitlab-ci.yml 中设置变量外,还有可以通过GitLab的CI/CD界面上设置私有变量

  • cache
    用来指定需要在job之间缓存的文件或目录。只能使用该项目工作空间内的路径,从GitLab 9.0开始,pipelines和job就默认开启了缓存,如果 cache 定义在jobs的作用域之外,那么它就是全局缓存,所有jobs都可以使用该缓存。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #局部缓存
    #缓存 binaries 和 .config 中的所有文件:
    rspec:
    script: test
    cache:
    paths:
    - binaries/
    - .config

    #缓存git中没有被跟踪的文件:
    rspec:
    script: test
    cache:
    untracked: true

    #全局缓存
    #job中优先级高于全局的。下面这个 rspec job中将只会缓存 binaries/ 下的文件:
    cache:
    paths:
    - my/files

    rspec:
    script: test
    cache:
    key: rspec
    paths:
    - binaries/

如果你不同的jobs缓存不同的文件路径,必须设置不同的cache:key,否则缓存
内容将被重写。
缓存key指令允许我们定义缓存的作用域(亲和性),可以是所有jobs的单个缓存,也可以是每个job,也可以是每个分支或
者是任何你认为合适的地方,并且cache:key 可以使用任何的预定义变量
默认key是默认设置的这个项目缓存,因此默认情况下,每个pipelines和jobs中可以共享一切,从GitLab 9.0开始。
配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#缓存每个job:
cache:
key: "$CI_JOB_NAME"
untracked: true

#缓存每个分支:
cache:
key: "$CI_COMMIT_REF_NAME"
untracked: true

#缓存每个job且每个分支:
cache:
key: "$CI_JOB_NAME/$CI_COMMIT_REF_NAME"
untracked: true

#缓存每个分支且每个stage:
cache:
key: "$CI_JOB_STAGE/$CI_COMMIT_REF_NAME"
untracked: true

#如果使用的Windows Batch(windows批处理)来跑脚本需要用 % 替代 $ :
cache:
key: "%CI_JOB_STAGE%/%CI_COMMIT_REF_NAME%"
untracked: true

_注意_:缓存是在jobs之前进行共享的。缓存只是尽力而为之,所以别期望缓存会一直存在。查看更多详细内容,请查阅GitLab Runner。

  • Jobs
    .gitlab-ci.yml 允许指定无限量jobs。每个jobs必须有一个唯一的名字,而且不能是上面提到的关键字。job由一列
    参数来定义jobs的行为。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    job_name:
    script:
    - rake spec
    - coverage
    stage: test
    only:
    - master
    except:
    - develop
    tags:
    - ruby
    - postgres
    allow_failure: true

    #指令说明
    script yes #Runner执行的命令或脚本
    image no #所使用的docker镜像,查阅使用docker镜像
    services no #所使用的docker服务,查阅使用docker镜像
    stage no #定义job stage(默认: test )
    type no #stage 的别名(已弃用)
    variables #no 定义job级别的变量
    only no #定义一列git分支,并为其创建job
    except no #定义一列git分支,不创建job
    tags no #定义一列tags用来指定选择哪个Gitlab-Runner(同时Runner也要设置tags)
    allow_failure no #允许job失败。失败的job不影响commit状态
    when no #定义何时开始job 可以是 on_success , on_failure , always 或者 manual
    dependencies no #定义job依赖关系,这样他们就可以互相传递artifacts
    cache no #定义应在后续运行之间缓存的文件列表
    before_script no #重写一组在作业前执行的命令
    after_script no #重写一组在作业后执行的命令
    environment no #定义此作业完成部署的环境名称
    coverage no #定义给定作业的代码覆盖率设置
  • script
    是Runner执行的脚本,该参数也可以用数组包含多个命令:

    1
    2
    3
    4
    job:
    script:
    - uname -a
    - bundle exec rspec

    有时候 script 命令需要被单引号或者是双引号包裹起来。举个例子,当命令中包含冒号( : )时,script需要被包
    在双引号中,这样YAML解析器才可以正确解析为一个字符串而不是一个键值对(key:value)。使用这些特殊字符的时候一定
    要注意:: , { , } , [ , ] , , , & , * , # , ? , | , - , < , > , = , !

  • stage
    stage 允许一组jobs进入不同的stages。jobs在相同的 stage 时会 parallel 同时进行。查阅 stages 更多的用法请查看stages

  • only and except
    only 和 except是两个参数用分支策略来限制jobs构建:

    • 1.only 定义哪些分支和标签的git项目将会被job执行。
    • 2.except 定义哪些分支和标签的git项目将不会被job执行。
      下面是refs策略的使用规则:
    • only 和 except 可同时使用,如果 only 和 except 在一个job配置中同时存在,则以 only 为准,跳过except (从下面示例中得出)。
    • only 和 except 可以使用正则表达式。
    • only 和 except 允许使用特殊的关键字:branches , tags 和 triggers 。
    • only 和 except 允许使用指定仓库地址但不是forks的仓库(查看示例3)。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      #(1)在下面这个例子中, job 将只会运行以 issue- 开始的refs(分支),然而except中设置将被跳过。
      job:
      # use regexp
      only:
      - /^issue-.*$/
      # use special keyword
      except:
      - branches

      #(2)在下面这个例子中, job 将只会执行有tags的refs,或者通过API触发器明确地请求构建。
      job:
      # use special keywords
      only:
      - tags
      - triggers

      #(3)仓库路径只能用于父级仓库执行jobs而不是forks,将会为所有的分支执行 job ,但master分支除外。
      job:
      only:
      - branches@gitlab-org/gitlab-ce
      except:
      - master@gitlab-org/gitlab-ce
  • Job variables
    在job中是可以使用关键字 variables 来定义job变量。它的运行原理跟global-level是一样的,但是它允许设置特殊的job变量, Job变量的优先级关系可查看附录的variables文档说明
    当设置了job级别的关键字 variables ,它会覆盖全局YAML和预定义中的job变量。想要关闭全局变量可以在job中设置一个空数组:

    1
    2
    job_name:
    variables: []
  • tags
    tags 可以从允许运行分配给此项目的所有Gitlab-Runners中选择特定的Runners来执行jobs,tags 可通过tags来指定特殊的Runners来运行jobs:
    在注册Runner的过程中,我们可以设置Runner的标签,比如 ruby , postgres , development

    1
    2
    3
    4
    job:
    tags:
    - ruby
    - postgres

    上面这个示例中,需要确保构建此 job 的Runner必须定义了 ruby 和 postgres 这两个tags,否则报错此作业被卡住,因为没有任何该项目指定标签的 runner 在线

  • allow_failure
    allow_failure 可以用于当你想设置一个job失败的之后并不影响后续的CI组件的时候。失败的jobs不会影响到
    commit状态。
    当开启了允许job失败,所有的intents和purposes里的pipeline都是成功/绿色,但是也会有一个"CI build passed with warnings"信息显示在merge request或commit或job page。这被允许失败的作业使用,但是如果失败表示其他地方应采取其他(手动)步骤。
    下面的这个例子中:job1 和 job2 将会并列进行,如果 job1 失败了,它也不会影响进行中的下一个stage,因为
    这里有设置了 allow_failure: true 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    job1:
    stage: test
    script:
    - execute_script_that_will_fail
    allow_failure: true
    job2:
    stage: test
    script:
    - execute_script_that_will_succeed
    job3:
    stage: deploy
    script:
    - deploy_to_staging
  • when
    when 用于实现在发生故障或尽管发生故障仍在运行的作业,可以设置以下值:

    • 1.on_success - 只有前面stages的所有工作成功时才执行(默认值)
    • 2.on_failure - 当前面stages中任意一个jobs失败后执行。
    • 3.always - 无论前面stages中jobs状态如何都执行。
    • 4.manual - 手动执行(GitLab8.10增加)。更多请查看手动操作。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      stages:
      - build
      - cleanup_build
      - test
      - deploy
      - cleanup

      build_job:
      stage: build
      script:
      - make build

      cleanup_build_job:
      stage: cleanup_build
      script:
      - cleanup build when failed
      when: on_failure #

      test_job:
      stage: test
      script:
      - make test

      deploy_job:
      stage: deploy
      script:
      - make deploy
      when: manual #手动执行

      cleanup_job:
      stage: cleanup
      script:
      - cleanup after jobs
      when: always #始终执行
      脚本说明:
      1.只有当build_job失败的时候才会执行 cleanup_build_job
      2.不管前一个job执行失败还是成功都会执行 cleanup_job
      3.可以从GitLab界面中手动执行 deploy_jobs

补充说明:Manual actions手动操作指令是不自动执行的特殊类型的job, 它们必须要人为启动。手动操作指令可以从pipeline,build,environment和deployment视图中启动。部署到生产环境是手动操作指令的一个很好示例。

  • 手动操作指令可以是可选的或阻塞。在定义了手动执行的那个stage中,手动操作指令将会停止pipline中的自动执行指令。当有人通过点击play按钮来执行需要手动执行的job时,可以来恢复pipeline的执行。

  • 当pipeline被阻塞时,即使是pipeline是成功状态也不会merge。被阻塞的pipelines也有一个特殊的状态,叫
    manual 。

  • 手动操作指令默认是不阻塞的。如果你想要手动操作指令产生阻塞,首先需要在job的配置文件 .gitlab-ci.yml 中添加 allow_failure:false ,可选的手动操作指令默认设置allow_failure:true 。可选动作的状态不影响整个pipeline的状态,手动操作指令被认为是写操作,所以当前用户触发操作时,必须拥有操作保护分支的权限。换句话说,为了触发一个手动操作指令到pipeline中正在运行的指定分支,当前用户必须拥有推送到这分支的权限。

  • enviroment
    environment 用于定义job部署到特殊的环境中。如果指定了 environment ,并且没有该名称下的环境,则会自动创建新环境。
    在最简单的格式中,环境关键字可以定义为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    deploy to production:
    stage: deploy
    script: git push production HEAD:master
    environment:
    name: production
    ```
    - environment:name 名称可以包含: `英文字母( letters ), 数字( digits ) ,空格( spaces ) ,- ,_ ,/ ,$ , { , }`
    常用的名称有 qa , staging ,和 production ,当然你可以在你的工作流中使用任意名字。
    除了在 environment 关键字右边紧跟name定义方法外,也是可以为环境名称单独设定一个值。例如,用 name 关键字在 environment 下面设置:
    ```yaml
    deploy to production:
    stage: deploy
    script: git push production HEAD:master
    environment:
    name: production
    • environment:url 这是设置一个可选值,它会显示在按钮中,点击它可以跳转到设置的URL页面。
      在下面这个例子中,如果job都成功完成了,在environment/deployments页面中将会创建一个合并请求的按钮,它将指向 https://prod.example.com
      1
      2
      3
      4
      5
      6
      deploy to production:
      stage: deploy
      script: git push production HEAD:master
      environment:
      name: production
      url: https://prod.example.com
    • environment:on_stop: 关闭(停止)environments可以通过在 environment 下定义关键字 on_stop 来实现。它定义了一个不同的job,用于关闭environment。
    • environment:action: action 和 on_stop 联合使用,定义在job中,用来关闭environment。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      review_app:
      stage: deploy
      script: make deploy-app
      environment:
      name: review
      on_stop: stop_review_app

      stop_review_app:
      stage: deploy
      script: make delete-app
      when: manual
      environment:
      name: review
      action: stop
      上面这个例子中,我们定义了 review_app job来部署到 review 环境中,同时我们也定义了一个新stop_review_app job在 on_stop 中。一旦 review_app job执行完成并且成功,它将触发定义在 when 中的stop_review_app job。在这种情况下,我们设置为 manual ,需要通过GitLab’s web界面来允许manual action。

    stop_review_app job需要定义下面这些关键字:
    when - 说明
    environment:name
    environment:action
    stage 需要和 review_app 相同,以便分支删除被删除的时候自动执行停止。

    • dynamic environment : 也可以是代表配置项,其中包含 name 和 url 。这些参数可以使用任何的CI variables(包括预定义、安全变量和 .gitlab-ci.yml 中的变量)。

      1
      2
      3
      4
      5
      6
      deploy as review app:
      stage: deploy
      script: make deploy
      environment:
      name: review/$CI_COMMIT_REF_NAME
      url: https://$CI_ENVIRONMENT_SLUG.example.com/

      当 $CI_COMMIT_REF_NAME 被Runner设置为environment variable时, deply as review app job将会被指定部署到动
      态创建 revuew/$CI_COMMIT_REF_NAME 的环境中。 $CI_ENVIRONMENT_SLUG 变量是基于环境名称的,最终组合成完整的URLs。在这种情况下,如果 deploy as review app job是运行在名称为 pow 的分支下,那么可以通过URL https”//review-pw.example.com/ 来访问这个环境。
      这当然意味着托管应用程序的底层服务器已经正确配置。

      常见的做法是为分支创建动态环境,并讲它们作为Review Apps。可以通过https://gitlab.com/gitlab-examples/reviewapps-nginx/上查看使用Review Apps的简单示例。


  • artifacts
    artifacts 用于指定成功后应附加到job的文件和目录的列表。只能使用项目工作间内的文件或目录路径。如果想要在不通的job之间传递artifacts,请查阅依赖关系。以下是一些例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #发送 binaries 和 .config 中的所有文件:
    artifacts:
    paths:
    - binaries/
    - .config

    #发送所有没有被Git跟踪的文件:
    artifacts:
    untracked: true

    #发送没有被Git跟踪和 binaries 中的所有文件:
    artifacts:
    untracked: true
    paths:
    - binaries/

    #定义一个空的dependencies可以禁用artifact传递:
    job:
    stage: build
    script: make build
    dependencies: []

    #有时候只需要为标签为releases创建artifacts,以避免将临时构建的artifacts传递到生产服务器中。
    #只为tags创建artifacts( default-job 将不会创建artifacts):
    default-job:
    script:
    - mvn test -U
    except:
    - tags

    release-job:
    script:
    - mvn package -U
    artifacts:
    paths:
    - target/*.war
    only:
    - tags

    在job成功完成后artifacts将会发送到GitLab中,同时也会在GitLab UI中提供下载。

    • artifacts:name 允许定义创建的artifacts存档的名称。这样一来,我们可以为每个存档提供一个唯一的名称,当需要从GitLab中下载是才不会混乱。 artifacts:name 可以使用任何的预定义变量(predefined variables)。它的默认名称为 artifacts ,当下载是就变成了 artifacts.zip 。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      #通过使用当前job的名字作为存档名称:
      job:
      artifacts:
      name: "$CI_JOB_NAME"

      #使用当前分支名称或者是tag作为存到名称,只存档没有被Git跟踪的文件:
      job:
      artifacts:
      name: "$CI_COMMIT_REF_NAME"
      untracked: true

      #使用当前job名称和当前分支名称或者是tag作为存档名称,只存档没有被Git跟踪的文件:
      job:
      artifacts:
      name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}"
      untracked: true

      #使用当前stage和分支名称作为存档名称:
      job:
      artifacts:
      name: "${CI_JOB_STAGE}_${CI_COMMIT_REF_NAME}"
      untracked: true

      #如果是使用Windows批处理来运行yaml脚本,需要用 % 替换 $ :
      job:
      artifacts:
      name: "%CI_JOB_STAGE%_%CI_COMMIT_REF_NAME%"
      untracked: true
    • artifacts:when 在job失败的时候, artifacts:when 用来上传artifacts或者忽略失败。
      artifacts:when 可以设置一下值:

      • 1.on_success - 当job成功的时候上传artifacts。默认值。
      • 2.on_failure - 当job失败的时候上传artifacts。
      • 3.always - 不论job失败还是成功都上传artifacts。
      1
      2
      3
      4
      #只在job失败的时候上传artifacts。
      job:
      artifacts:
      when: on_failure
    • artifacts:expire_in 用于过期后删除邮件上传的artifacts。默认情况下,artifacts都是在GitLab中永久保存。expire_in 允许设置设置artifacts的存储时间,从它们被上传存储到GitLab开始计算。
      可以通过job页面的Keep来修改有效期。过期后artifacts会被通过一个默认每小时执行一次的定时job删除,所以在过期后无法访问artifacts。
      expire_in 是一个时间区间。下面可设置的值:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      '3 mins 4 sec'
      '2 hrs 20 min'
      '2h20min'
      '6 mos 1 day'
      '47 yrs 6 mos and 4d'
      '3 weeks and 2 days'

      #设置artifacts的有效期为一个星期:
      job:
      artifacts:
      expire_in: 1 week
  • dependencies
    这个功能应该与 artifacts 一起使用,并允许定义在不同jobs之间传递artifacts。注意:所有之前的stages都是默认设置通过。
    如果要使用此功能,应该在上下文的job中定义 dependencies ,并且列出之前都已经通过的jobs和可下载的artifacts。你只能在当前执行的stages前定义jobs。你如果在当前stages或者后续的stages中定义了jobs,它将会报错。可以通过定义一个空数组是当前job跳过下载artifacts。
    在接下来的例子中,我们定义两个带artifacts的jobs, build:osx 和 build:linux 。当 test:osx 开始执行的时候, build:osx 的 artifacts就会开始下载并且会在build的stages下执行。同样的会发生在 test:linux ,从build:linux 中下载artifacts
    因为stages的优先级关系deploy job将会下载之前jobs的所有artifacts:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     build:osx:
    stage: build
    script: make build:osx
    artifacts:
    paths:
    - binaries/

    build:linux:
    stage: build
    script: make build:linux
    artifacts:
    paths:
    - binaries/

    test:osx:
    stage: test
    script: make test:osx
    dependencies:
    - build:osx #从build:osx 中下载artifacts

    test:linux:
    stage: test
    script: make test:linux
    dependencies:
    - build:linux #从build:linux 中下载artifacts

    deploy:
    stage: deploy
    script: make deploy

  • before_script 和 after_script
    它可能会覆盖全局定义的 before_script 和 after_script ,他可以在全局或者阶段工作中使用;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #每个job都将执行
    before_script:
    - global before script
    after_script:
    - global after script

    job:
    before_script:
    - execute this instead of global before script
    script:
    - my command
    after_script:
    - execute this after my script

  • coverage :允许你配置代码覆盖率将会从该job中提取输出。
    在这里正则表达式是唯一有效的值。因此,字符串的前后必须使用 / 包含来表明一个正确的正则表达式规则。特殊字符串需要转义。一个简单的例子:
    1
    2
    job1:
    coverage: '/Code coverage: \d+\.\d+/'

0x02 仓库相关

  • Git Strategy
    你可以通过设置 GIT_STRATEGY 用于获取最新的代码,可以再全局 variables 或者是在单个job的 variables 模块中设置。如果没有设置,将从项目中使用默认值。
    可以设置的值有: clone , fetch ,和 none

    1
    2
    3
    4
    5
    6
    7
    8
    variables:
    #clone 是最慢的选项。它会从头开始克隆整个仓库,包含每一个job,以确保项目工作区是最原始的。
    GIT_STRATEGY: clone
    #当它重新使用项目工作区是, fetch 是更快(如果不存在则返回克隆)。 git clean 用于撤销上一个job做的任何改变, git fetch 用于获取上一个job到现在的的commit。
    GIT_STRATEGY: fetch
    #none 也是重新使用项目工作区,但是它会跳过所有的Git操作(包括GitLab Runner前的克隆脚本,如果存在的话)。它主要用在操作job的artifacts(例如: deploy )。
    #Git数据仓库肯定是存在的,但是他肯定不是最新的,所以你只能依赖于从项目工作区的缓存或者是artifacts带来的文件。
    GIT_STRATEGY: none
  • Git Checout
    当 GIT_STRATEGY 设置为 clone 或 fetch 时,可以使用 GIT_CHECKOUT 变量来指定是否应该运行 git checkout 。如果没有指定,它默认为true。就像 GIT_STRATEGY 一样,它可以设置在全局 variables 或者是单个job的 variables 中设置。如果设置为 false时Runner就会:

    • fetch - 更新仓库并在当前版本中保留工作副本,
    • clone - 克隆仓库并在默认分支中保留工作副本。
      【如果设置这个为 true 将意味着 clone 和 fetch 策略都会让Runner执行项目工作区更新到最新:】
      1
      2
      3
      4
      5
      6
      variables:
      GIT_STRATEGY: clone
      GIT_CHECKOUT: false
      script:
      - git checkout master
      - git merge $CI_BUILD_REF_NAME
  • Git Submodule Strategy
    GIT_SUBMODULE_STRATEGY 变量用于在构建之前拉取代码时,Git子模块是否或者如何被引入。就像 GIT_STRATEGY 一样,它可在全局 variables 或者是单个job的 variables 模块中设置
    它的可用值有: none , normal 和 recursive :

    1
    2
    3
    4
    5
    6
    7
    none 意味着在拉取项目代码时,子模块将不会被引入。这个是默认值,与v1.10之前相同的。
    normal 意味着在只有顶级子模块会被引入。它相当于:
    git submodule sync
    git submodule update --init
    recursive 意味着所有的子模块(包括子模块的子模块)都会被引入,他相当于:
    git submodule sync --recursive
    git submodule update --init --recursive

    注意:如果想要此功能正常工作,子模块必须配置(在 .gitmodules )下面中任意一个:

    • 可访问的公共仓库http(s)地址,
    • 在同一个GitLab服务器上有一个可访问到另外的仓库的真实地址。更多查看Git 子模块文档。
  • Job stages attempts
    正在执行的job将会按照你设置尝试次数依次执行下面的stages(默认是一次尝试):

    1
    2
    3
    4
    5
    6
    7
    GET_SOURCES_ATTEMPTS       获取job源的尝试次数
    ARTIFACT_DOWNLOAD_ATTEMPTS 下载artifacts的尝试次数
    RESTORE_CACHE_ATTEMPTS 重建缓存的尝试次数

    #基础实例
    variables:
    GET_SOURCES_ATTEMPTS: 3

    你可以在全局 variables 模块中设置,也可以在单个job的 variables 模块中设置。

  • Shallow cloning
    你可以通过 GIT_DEPTH 来指定抓取或克隆的深度。它可浅层的克隆仓库,这可以显著加速具有大量提交和旧的大型二进制文件的仓库的克隆。这个设置的值会传递给 git fetch 和 git clone 。

    注意:如果设置depth=1,并且有一个jobs队列或者是重试jobs,则jobs可能会失败。

    由于Git抓取和克隆是基于一个REF,例如分支的名称,所以Runner不能指定克隆一个commit SHA。如果队列中有多个jobs,或者您正在重试旧的job,则需要测试的提交应该在克隆的Git历史记录中存在。设置 GIT_DEPTH 太小的值可能会导致无法运行哪些旧的commits。在job日志中可以查看 unresolved reference 。你应该考虑设置 GIT_DEPTH 为一个更大的值。
    当 GIT_DEPTH 只置了部分存在的记录时,哪些依赖于 git describe 的jobs也许不能正确的工作。只抓取或克隆最后的3次commits:

    1
    2
    variables:
    GIT_DEPTH: "3"
  • Hidden keys
    Key 是以 . 开始的,GitLab CI 将不会处理它。你可以使用这个功能来忽略jobs,或者用Special YAML features 转换隐藏键为模版。在下面这个例子中 .key_name 将会被忽略:

    1
    2
    3
    .key_name:
    script:
    - rake spec

    Hidden keys 可以是像普通CI jobs一样的哈希值,但你也可以利用special YAMLfeatures来使用不同类型的结构。使用special YAML features 像anchors( & ),aliases( * )和map merging( << ),这将使您可以大大降低 .gitlabci.yml 的复杂性。

  • Anchors
    YAML有个方便的功能称为”锚”,它可以让你轻松的在文档中复制内容。Anchors可用于复制/继承属性,并且是使用hidden keys来提供模版的完美示例。
    下面这个例子使用了anchors和map merging。它将会创建两个jobs, test1 和 test2 ,该jobs将集成 .job_template 的参数,每个job都自定义脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .job_template: &job_definition # Hidden key that defines an anchor named 'job_definition'
    image: ruby:2.1
    services:
    - postgres
    - redis

    test1:
    <<: *job_definition # Merge the contents of the 'job_definition' alias
    script:
    - test1 project

    test2:
    <<: *job_definition # Merge the contents of the 'job_definition' alias
    script:
    - test2 project

    & 在anchor的名称( job_definition )前设置, << 表示"merge the given hash into the current one", * 包括命名的anchor( job_definition )。扩展版本如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    .job_template:
    image: ruby:2.1
    services:
    - postgres
    - redis

    test1:
    #'job_definition' alias (别名效果如下)
    image: ruby:2.1
    services:
    - postgres
    - redis
    script:
    - test1 project

    test2:
    image: ruby:2.1
    services:
    - postgres
    - redis
    script:
    - test2 project

    让我们来看另外一个例子。这一次我们将用anchors来定义两个服务。两个服务会创建两个job, test:postgres 和 test:mysql ,他们会在 .job_template 中共享定义的 script 指令,以及分别在 postgres_services 和 .mysql_services 中定义的 service 指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    .job_template: &job_definition
    script:
    - test project

    .postgres_services:
    services: &postgres_definition
    - postgres
    - ruby

    test:postgres:
    <<: *job_definition
    services: *postgres_definition

    #扩展版本如下:
    .job_template:
    script:
    - test project

    .postgres_services:
    services:
    - postgres
    - ruby

    test:postgres:
    script:
    - test project
    services:
    - postgres
    - ruby
  • Triggers:可用于强制使用API调用重建特定分支,tag或commits。

  • pages:是一个特殊的job,用于将静态的内容上传到GitLab,可用于为您的网站提供服务。它有特殊的语法,因此必须满足以下两个要求:
  • 1.任何静态内容必须放在 public/ 目录下
  • 2.artifacts 必须定义在 public/ 目录下
    下面的这个例子是将所有文件从项目根目录移动到 public/ 目录。.public 工作流是 cp ,并且它不会循环复制public/ 本身。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    pages:
    stage: deploy
    script:
    - mkdir .public
    - cp -r * .public
    - mv .public public
    artifacts:
    paths:
    - public
    only:
    - master
  • Skipping jobs:如果你的commit信息中包含 [ci skip] 或者 [skip ci],不论大小写,那么这个commit将会创建但是jobs也会跳过;

0x03 管道介绍

管道是持续集成、交付和部署的顶级组件是一组分阶段(批处理)执行的工作。同一个阶段中的所有工作都是并行执行的(如果有足够的并发Runners),如果它们全部成功,管道就进入下一个阶段。如果其中一个jobs失败,则下一个阶段不(通常)执行。您可以访问项目的Pipeline选项卡中的管道页面。
在下图中,您可以看到管道由4个阶段组成(build(构建) , test(测试) , staging(分级) , production(生产) ),每个阶段都有一个或多个工作。

1.管道类型

描述:管道分三种,但是通常都使用单一的“管道”来代替所有。人们经常谈论他们,就好像每个都是“管道”一样,但实际上他们只是综合管道的一部分。

  1. CI Pipeline: 在 gitlab-ci.yml 中定义的构建和测试阶段。
  2. Deploy Pipeline: 在 .gitlab-ci.yml 中定义的部署阶段,用来通过各种各样的方式将代码部署到服务器:
    例如,将代码发布到生成环境
  3. Project Pipeline:通过API触发跨项目CI依赖关系,尤其是针对微服务,但也适用于复杂的构建依赖关系:
    例如,api-> front-end,ce / ee-> omnibus

开发工作流程:

1
2
3
1. Branch Flow(例如,dev,qa,分期,生产等不同分支)
2. Trunk-based Flow (例如,功能分支、单一的主分支和可能带有标签的发布)
3. 基于分叉的流程(例如,来自fork的合并请求)

2.名词介绍
  • 工作:可以在 .gitlab-ci.yml 文件中定义。不要与 build 工作或 build 阶段混淆。
  • 定义管道:在 .gitlab-ci.yml 中通过指定阶段运行的作业来定义管道。
  • 查看管道状态: 您可以在项目的 Pipeline选项卡下找到当前和历史运行的管道 。点击管道将显示为该管道运行的作业。
  • 查看工作状态: 当您访问单个管道时,您可以看到该管道的相关作业。点击单个作业会显示该作业运行历史,并允许您取消作业,重试作业或清除作业运行日志。
  • 查看工作失败的原因: 当管道发生故障或允许失败时,有几个地方可以快速检查失败的原因:
    • 在管道图中 出现在管道图中。
    • 在管道小部件中 出现在合并请求和提交页面中。
    • 在工作视图中 出现在全局和详细的工作视图中。
  • 管道图:管道可以是复杂的结构,具有许多顺序和平行的作业。为了让您更容易看到发生了什么,它可以查看单个管道及其状态。
    • 管道图可以通过两种不同的方式显示,具体取决于您所处的页面。
    • 当您在单个管道页面上时,可以找到显示每个阶段作业名称的常规管道图。
    • 其次有管道迷你图,占用更少的空间,并且可以快速浏览所有作业是成果还是失败。管道迷你图可以在您访问以下,页面时找到: 管道索引页面 / 提交页面 /合并请求页面
  • 将相似的工作分组: 如果你有许多类似的工作,你的管道图会变得很长,很难阅读。出于这个原因,类似的工作可以自动组合在一起。如果作业名称以某种格式命名,则它们将在常规管线图(非迷你图)中折叠为一个组。如果您没有看到重试或取消按钮,您就知道管道将作业已经合并分组了。将鼠标悬停在上面会显示分组作业的数量。可以点击展开它们。
    • 基本要求是需使用以下方式的一种将两个数字分隔开(可以互换使用)(查看下面的示例):空间 / 斜线( / ) / 冒号( : ) 注意: 更准确地说,它使用这个正则表达式: \d+[\s:\/\]+\d+\s* 。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #这些工作将通过从左到右比较这两个数字来进行排序。通常第一个是索引,第二个是总数。
      #例如,以下作业将被分组在一个名为的作业下 test :
      test 0 3 => test
      test 1 3 => test
      test 2 3 => test
      #以下作业将被分组在下列作业中 test ruby :
      test 1:2 ruby => test ruby
      test 2:2 ruby => test ruby
      #下列作业也将被归类在一个作业中 test ruby :
      1/3 test ruby => test ruby
      2/3 test ruby => test ruby
      3/3 test ruby => test ruby
  • 手动操作:手动操作允许您在使用CI中的指定作业之前需要手动操作。整个管道可以自动运行,但实际部署到生产需要点击。(在GitLab 8.15中引入)
  • 作业排序:常规管道图在单个管道页面中,作业按名称排序。
  • 多项目管道图:可在GitLab Premium 、GitLab Sliver或更高级版本中使用。
  • 徽章:管道状态和测试范围内报告徽章可用。您可以在管道设置页面找到它们各自的链接。
  • 受保护分行的安全:管道在受保护的分支上执行时,将执行严格的安全模型,只有在允许用户合并或推送 特定分支时,才允许在受保护的分支上执行以下操作 :
    • 运行手动管道(使用Web UI或Pipelines API)
    • 运行预定的管道
    • 使用触发器运行管道
    • 在现有管线上触发手动操作
    • 重试/取消现有作业(使用Web UI或Pipelines API)
    • 标记为受保护的变量仅适用于在受保护分支上运行的作业,从而避免不受信任的用户无意中访问敏感信息,如部署凭证和令牌。
    • 标记为受保护的Runners只能保护分支机构运行的作业,避免不受信任的代码要在保护runner和保存部署键被意外地触发或其他凭证执行。为了确保打算在受保护的跑步者上执行的工作不会使用常规runner,必须对其进行相应标记。

Q:如何计算管道持续时间?

管道的总运行时间将排除重试和待处理(排队)时间。我们可以将这个问题缩减为寻找周期的联合。
所以每个工作都会被表示为 Period ,其中包括 Period#first 工作开始 Period#last 时和工作完成时。一个简单的例子是:

1
2
3
A(1,3)
B(2,4)
C(6,7)

这里A从1开始,到3结束。B从2开始,并到4结束。C从6开始,到7结束。视觉上它可以被看作:

1
2
3
4
5
6
0 1 2 3 4 5 6 7
AAAAAAA
BBBBBBB
CCCC
#A,B和C的联合将是(1,4)和(6,7),因此总运行时间应该是:
(4 - 1) + (7 - 6) => 4


0x04 Variables

描述:当GitLab CI 中接受到一个job后,Runner就开始准备构建环境。开始设置预定义的变量(环境变量)和用户自定义的变量。
官方文档:https://docs.gitlab.com/ce/ci/variables/README.html

variables 的执行顺序

变量可以被重写,并且是按照下面的顺序进行执行:

  • 1.触发变量或计划管道变量。
  • 2.项目级变量或受保护变量。
  • 3.组级变量或受保护变量。
  • 4.YAML 定义的作业级变量。
  • 5.YAML 定义的全局变量。
  • 6.部署变量。
  • 7.预定义的环境变量。

举个例子,如果你定义了私有变量 API_TOKEN=secure ,并且在 .gitlab-ci.yml 中定义了 API_TOKEN=yaml,那么私有变量 API_TOKEN 的值将是 secure ,因为secret variables的优先级较高。

  • Predefined variables(Environment variables): 有部分预定义的环境变量仅仅只能在最小版本的GitLab Runner中使用。
    • 注意:从GitLab 9.0 开始,部分变量已经不提倡使用。请查看9.0 Renaming部分来查找他们的替代变量。强烈建议使用新的变量,我们也会在将来的GitLab版本中将他们移除。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      Variable GitLab Runner Description
      CI all 0.4 标识该job是在CI环境中执行
      CI_COMMIT_REF_NAME 9.0 all 用于构建项目的分支或tag名称
      CI_COMMIT_REF_SLUG 9.0 all 先将 $CI_COMMIT_REF_NAME 的值转换成小写,最 大不能超过63个字节,然后把除了 0-9 和 a-z 的其他字符转换成 - 。在URLs和域名名称中使用。
      CI_COMMIT_SHA 9.0 all commit的版本号
      CI_COMMIT_TAG 9.0 0.5 commit的tag名称。只有创建了tags才会出现。
      CI_DEBUG_TRACE 9.0 1.7 debug tracing开启时才生效
      CI_ENVIRONMENT_NAME 8.15 all job的环境名称
      CI_ENVIRONMENT_SLUG 8.15 all 环境名称的简化版本,适用于DNS,URLs, Kubernetes labels等
      CI_JOB_ID 9.0 all GItLab CI内部调用job的一个唯一ID
      CI_JOB_MANUAL 8.12 all 表示job启用的标识
      CI_JOB_NAME 9.0 0.5 .gitlab-ci.yml 中定义的job的名称
      CI_JOB_STAGE 9.0 0.5 .gitlab-ci.yml 中定义的stage的名称
      CI_JOB_TOKEN 9.0 1.2 用于同GitLab容器仓库验证的token
      CI_REPOSITORY_URL 9.0 all git仓库地址,用于克隆
      CI_RUNNER_DESCRIPTION 8.10 0.5 GitLab中存储的Runner描述
      CI_RUNNER_ID 8.10 0.5 Runner所使用的唯一ID
      CI_RUNNER_TAGS 8.10 0.5 Runner定义的tags
      CI_PIPELINE_ID 8.10 0.5 GitLab CI 在内部使用的当前pipeline的唯一ID
      CI_PIPELINE_TRIGGERED all all 用于指示该job被触发的标识
      CI_PROJECT_DIR all all 仓库克隆的完整地址和job允许的完整地址
      CI_PROJECT_ID all all GitLab CI在内部使用的当前项目的唯一ID
      CI_PROJECT_NAME 8.10 0.5 当前正在构建的项目名称(事实上是项目文件夹
      名称)
      CI_PROJECT_NAMESPACE 8.10 0.5 当前正在构建的项目命名空间(用户名或者是组
      名称)
      CI_PROJECT_PATH 8.10 0.5 命名空间加项目名称
      CI_PROJECT_PATH_SLUG 9.3 all $CI_PROJECT_PATH 小写字母、除了 0-9 和 a-z的其他字母都替换成 - 。用于地址和域名名称。
      CI_PROJECT_URL 8.10 0.5 项目的访问地址(http形式)
      CI_REGISTRY 8.10 0.5 如果启用了Container Registry,则返回GitLab的Container Registry的地址
      CI_REGISTRY_IMAGE 8.10 0.5 如果为项目启用了Container Registry,它将返回与特定项目相关联的注册表的地址
      CI_REGISTRY_PASSWORD 9.0 all 用于push containers到GitLab的Container Registry 的密码
      CI_REGISTRY_USER 9.0 all用于push containers到GItLab的Container Registry 的用户名
      CI_SERVER all all 标记该job是在CI环境中执行
      CI_SERVER_NAME all all 用于协调job的CI服务器名称
      CI_SERVER_REVISION all all 用于调度job的GitLab修订版
      CI_SERVER_VERSION all all 用于调度job的GItLab版本
      ARTIFACT_DOWNLOAD_ATTEMPTS 8.15 1.9 尝试运行下载artifacts的job的次数
      GET_SOURCES_ATTEMPTS 8.15 1.9 尝试运行获取源的job次数
      GITLAB_CI all all 用于指示该job是在GItLab CI环境中运行
      GITLAB_USER_ID 8.12 all 开启该job的用户ID
      GITLAB_USER_EMAIL 8.12 all 开启该job的用户邮箱
      RESTORE_CACHE_ATTEMPTS 8.15 1.9 尝试运行存储缓存的job的次数
  • 作业脚本中环境变量的语法:所有变量都设置为生成环境中的环境变量,并且它们可通过用于访问此类变量的正常方法访问。在大多数情况下,或用于执行作业脚本。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    job_name:
    script:
    #bash 中访问环境变量,使用 () 前缀变量名称:$
    - echo $CI_JOB_ID
    #Windows 批处理中的环境变量,可以使用 () 环绕变量:%
    - echo %CI_JOB_ID%

    #命令列出所有环境变量
    jobs:
    script:
    - echo "#Gitlab Variable:"
    - export

    比如上面内置的预定义变量以及Runner主机环境变量默认值如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    $ echo "#Gitlab Variable:"
    #Gitlab Variable:
    $ export
    declare -x CATALINA_HOME="/app/tomcat-9.0.22"
    declare -x CI="true"
    declare -x CI_API_V4_URL="http://gitlab.weiyigeek.top/api/v4"
    declare -x CI_BUILDS_DIR="/home/gitlab-runner/builds"
    declare -x CI_BUILD_BEFORE_SHA="5bd0b719c43f196c26e3563948834cc863410950"
    declare -x CI_BUILD_ID="86"
    declare -x CI_BUILD_NAME="jobs"
    declare -x CI_BUILD_REF="b022716f52d7905d392bb090acafa358adde2bd6"
    declare -x CI_BUILD_REF_NAME="master"
    declare -x CI_BUILD_REF_SLUG="master"
    declare -x CI_BUILD_STAGE="test"
    declare -x CI_BUILD_TOKEN="[MASKED]"
    declare -x CI_COMMIT_BEFORE_SHA="5bd0b719c43f196c26e3563948834cc863410950"
    declare -x CI_COMMIT_BRANCH="master"
    declare -x CI_COMMIT_DESCRIPTION=""
    declare -x CI_COMMIT_MESSAGE="更新 .gitlab-ci.yml"
    declare -x CI_COMMIT_REF_NAME="master"
    declare -x CI_COMMIT_REF_PROTECTED="true"
    declare -x CI_COMMIT_REF_SLUG="master"
    declare -x CI_COMMIT_SHA="b022716f52d7905d392bb090acafa358adde2bd6"
    declare -x CI_COMMIT_SHORT_SHA="b022716f"
    declare -x CI_COMMIT_TITLE="更新 .gitlab-ci.yml"
    declare -x CI_CONCURRENT_ID="0"
    declare -x CI_CONCURRENT_PROJECT_ID="0"
    declare -x CI_CONFIG_PATH=".gitlab-ci.yml"
    declare -x CI_DEFAULT_BRANCH="master"
    declare -x CI_JOB_ID="86"
    declare -x CI_JOB_NAME="jobs"
    declare -x CI_JOB_STAGE="test"
    declare -x CI_JOB_TOKEN="[MASKED]"
    declare -x CI_JOB_URL="http://gitlab.weiyigeek.top/newproject/secopsdev/-/jobs/86"
    declare -x CI_NODE_TOTAL="1"
    declare -x CI_PAGES_DOMAIN="example.com"
    declare -x CI_PAGES_URL="http://newproject.example.com/secopsdev"
    declare -x CI_PIPELINE_ID="32"
    declare -x CI_PIPELINE_IID="11"
    declare -x CI_PIPELINE_SOURCE="push"
    declare -x CI_PIPELINE_URL="http://gitlab.weiyigeek.top/newproject/secopsdev/pipelines/32"
    declare -x CI_PROJECT_DIR="/home/gitlab-runner/builds/5UmJ5uEC/0/newproject/secopsdev"
    declare -x CI_PROJECT_ID="1"
    declare -x CI_PROJECT_NAME="secopsdev"
    declare -x CI_PROJECT_NAMESPACE="newproject"
    declare -x CI_PROJECT_PATH="newproject/secopsdev"
    declare -x CI_PROJECT_PATH_SLUG="newproject-secopsdev"
    declare -x CI_PROJECT_REPOSITORY_LANGUAGES=""
    declare -x CI_PROJECT_TITLE="SecOpsDev"
    declare -x CI_PROJECT_URL="http://gitlab.weiyigeek.top/newproject/secopsdev"
    declare -x CI_PROJECT_VISIBILITY="private"
    declare -x CI_REGISTRY_PASSWORD="[MASKED]"
    declare -x CI_REGISTRY_USER="gitlab-ci-token"
    declare -x CI_REPOSITORY_URL="http://gitlab-ci-token:[MASKED]@gitlab.weiyigeek.top/newproject/secopsdev.git"
    declare -x CI_RUNNER_DESCRIPTION="TestRunner"
    declare -x CI_RUNNER_EXECUTABLE_ARCH="linux/amd64"
    declare -x CI_RUNNER_ID="1"
    declare -x CI_RUNNER_REVISION="4c96e5ad"
    declare -x CI_RUNNER_SHORT_TOKEN="5UmJ5uEC"
    declare -x CI_RUNNER_TAGS="TestRunner"
    declare -x CI_RUNNER_VERSION="12.9.0"
    declare -x CI_SERVER="yes"
    declare -x CI_SERVER_HOST="gitlab.weiyigeek.top"
    declare -x CI_SERVER_NAME="GitLab"
    declare -x CI_SERVER_PORT="80"
    declare -x CI_SERVER_PROTOCOL="http"
    declare -x CI_SERVER_REVISION="ac5568eb5d8"
    declare -x CI_SERVER_URL="http://gitlab.weiyigeek.top"
    declare -x CI_SERVER_VERSION="12.9.2"
    declare -x CI_SERVER_VERSION_MAJOR="12"
    declare -x CI_SERVER_VERSION_MINOR="9"
    declare -x CI_SERVER_VERSION_PATCH="2"
    declare -x CI_SHARED_ENVIRONMENT="true"
    declare -x CLASSPATH=".:/usr/local/jdk1.8.0_211/lib/dt.jar:/usr/local/jdk1.8.0_211/lib/tools.jar:%CATALINA_HOME%/lib/servlet-api.jar"
    declare -x CONFIG_FILE="/etc/gitlab-runner/config.toml"
    declare -x CVS_RSH="ssh"
    declare -x FF_CMD_DISABLE_DELAYED_ERROR_LEVEL_EXPANSION="false"
    declare -x FF_NETWORK_PER_BUILD="false"
    declare -x FF_USE_LEGACY_BUILDS_DIR_FOR_DOCKER="false"
    declare -x FF_USE_LEGACY_KUBERNETES_EXECUTION_STRATEGY="true"
    declare -x FF_USE_LEGACY_VOLUMES_MOUNTING_ORDER="false"
    declare -x GITLAB_CI="true"
    declare -x GITLAB_FEATURES=""
    declare -x GITLAB_USER_EMAIL="admin@example.com"
    declare -x GITLAB_USER_ID="1"
    declare -x GITLAB_USER_LOGIN="root"
    declare -x GITLAB_USER_NAME="Administrator"
    declare -x HISTCONTROL="ignoredups"
    declare -x HISTSIZE="1000"
    declare -x HOME="/home/gitlab-runner"
    declare -x HOSTNAME="initiator"
    declare -x JAVA_HOME="/usr/local/jdk1.8.0_211"
    declare -x JRE_HOME="/usr/local/jdk1.8.0_211/jre"
    declare -x LANG="zh_CN.UTF-8"
    declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
    declare -x LOGNAME="gitlab-runner"
    declare -x MAIL="/var/spool/mail/gitlab-runner"
    declare -x MYSQL_HOME="/usr/local/mysql-5.7.24"
    declare -x OLDPWD="/home/gitlab-runner"
    declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/jdk1.8.0_211/bin:/usr/local/mysql-5.7.24/bin:/home/gitlab-runner/.local/bin:/home/gitlab-runner/bin"
    declare -x PWD="/home/gitlab-runner/builds/5UmJ5uEC/0/newproject/secopsdev"
    declare -x SHELL="/bin/bash"
    declare -x SHLVL="2"
    declare -x TOMCAT_HOME="/app/tomcat-9.0.22"
    declare -x USER="gitlab-runner"
    declare -x XDG_RUNTIME_DIR="/run/user/996"
    declare -x XDG_SESSION_ID="c383"
    declare -x url="blog.wieyigeek.top"
  • 9.0 Renaming:根据GitLab的命名规则,在9.0以后将从 build 术语转到 job CI变量中,并且已经被重命名。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    8.x name     9.0+  name
    CI_BUILD_ID -> CI_JOB_ID
    CI_BUILD_REF -> CI_COMMIT_SHA
    CI_BUILD_TAG -> CI_COMMIT_TAG
    CI_BUILD_REF_NAME -> CI_COMMIT_REF_NAME
    CI_BUILD_REF_SLUG -> CI_COMMIT_REF_SLUG
    CI_BUILD_NAME -> CI_JOB_NAME
    CI_BUILD_STAGE -> CI_JOB_STAGE
    CI_BUILD_REPO -> CI_REPOSITORY_URL
    CI_BUILD_TRIGGERED -> CI_PIPELINE_TRIGGERED
    CI_BUILD_MANUAL -> CI_JOB_MANUAL
    CI_BUILD_TOKEN -> CI_JOB_TOKEN
  • gitlab-ci.yaml defined variables:注意:此功能要求GitLab Runner 0.5或者更高版本,并且GitLab CI 7.14或者更高版本;

    • GitLab CI允许你向 .gitlab-ci.yml 中添加变量,这个变量在构建环境中设置。因此,变量将保存在存储中,他们用于存储非敏感的项目配置,例如: RAILS_ENV 或者 DATABASE_URL 。
    • YAML中定义的变量也将应用到所有创建的服务容器中,因此可以对它进行微调。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      #举个例子,如果将变量设置为全局以下(不是在一个作业中),则它将用于所有执行的命令脚本中:
      variables:
      DATABASE_URL: "postgres://postgres@postgres/my_database"

      #变量可以定义为全局,同时也可以定义为job级别。若要关闭作业中的全局定义变量,请定义一个空hash:
      job_name:
      variables: {}

      #您可以在变量定义中使用其他变量(或使用$$将其转义):
      variables:
      LS_CMD: 'ls $FLAGS $$TMP_DIR'
      FLAGS: '-al'
      script:
      - 'eval $LS_CMD' # will execute 'ls -al $TMP_DIR'
      执行结果:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      jobs:
      variables:
      LS_CMD: 'whoami'
      USERNAME: 'weiyigeek'
      script:
      - "echo -e\"# $LS_CMD \n$USERNAME\"" # will execute 'ls -al $TMP_DIR'
      - 'eval $LS_CMD'
      $ echo -e "> $LS_CMD # collapsed multi-line command
      # whoami
      weiyigeek
      $ eval $LS_CMD
      gitlab-runner
  • Secret variables:安全变量

    • GitLab CI允许你在构建环境过程中设置项目的私有变量。私有变量存储在仓库(.gitlab-ci.yml)中,并被安全的传递给GitLab Runner,使其在构建环境中可用。建议使用该方法存储诸如密码、秘钥和凭据之类的东西。
    • 可用通过Settings ➔ Pipelines来增加私有变量,通过Settings ➔ Pipelines找到的模块称之为私有变量。一次设置,所有的后续pipeline是都可以使用它们
  • Protected secret variables

    • 私有变量可以被保护。每当一个私有变量被保护时,它只会安全的传递到在受保护的分支或受保护的标签上运行的pipeline。其他的pipeline将不会得到受保护的变量
    • 可用通过Settings ➔ Pipelines来增加私有变量,通过Settings ➔ Pipelines找到的模块称之为私有变量,然后点击Protected。
  • Deploment variables

    • 负责部署配置的项目服务可以定义在构建环境中设置自己的变量。这些变量只定义用于部署job。请参考您正在使用的项目服务的文档,以了解他们定义的变量。
  • Debug tracing:启用调试跟踪

    • 默认情况下,GitLab Runner会隐藏了处理job时正在做的大部分细节。这种行为使job跟踪很短,并且防止秘密泄露到跟踪中,除非您的脚本将他们输出到屏幕中。
    • 如果job没有按照预期的运行,这也会让问题查找变得更加困难;在这种情况下,你可以在 .gitlab-ci.yml 中开启调试记录。它需要GitLab Runner v1.7版本以上,此功能可启用shell的执行记录,从而产生详细的job记录,列出所有执行的命令,设置变量等。
      1
      2
      3
      4
      #设置 CI_DEBUG_TRACE 变量的值为 true 来开启调试记录。
      job_name:
      variables:
      CI_DEBUG_TRACE: "true"
      WeiyiGeek.Debug

      WeiyiGeek.Debug

    • 警告:启用调试跟踪可能会严重的安全隐患。输出内容将包含所有的私有变量和其他的隐私!输出的内容将被上传到GitLab服务器并且将会在job记录中明显体现。