MENU

.gitlab-ci.yml关键词完整解析

• 2022 年 01 月 05 日 • DevOps

.gitlab-ci.yml关键词完整解析

使用GitLab自带的流水线,必须要定义流水线的内容,而定义内容的文件默认叫做.gitlab-ci.yml,使用yml的语法进行编写。
目前任务关键词有28个,全局的关键词有10个,两者重叠的有很多。今天我给大家先讲解一下常用的关键词,掌握了这些关键词的用法,你可以编写逻辑严谨,易于扩展的流水线。

任务的28个关键词分别是,
script, after_script, allow_failure, artifacts, before_script, cache, coverage, dependencies, environment, except, extends, image, include, interruptible, only, pages, parallel, release, resource_group, retry, rules, services, stage, tags, timeout, trigger, variables, when

全局的关键词
image,services,before_script,after_script,tags,cache,artifacts,retry,timeout,interruptible

script

任务要执行的shell脚本内容,内容会被runner执行,在这里,你不需要使用git clone ....克隆当前的项目,来进行操作,因为在流水线中,每一个的job的执行都会将项目下载,恢复缓存这些流程,不需要你再使用脚本恢复。你只需要在这里写你的项目安装,编译执行,如
npm install 另外值得一提的是,脚本的工作目录就是当前项目的根目录,所有可以就像在本地开发一样。此外script可以是单行或者多行

单行脚本

job:
  script: npm install

多行脚本

job:
  script:
    - npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
    - npm install --registry=http://registry.npm.taobao.org

script是一个job的必填内容,不可或缺。一个job最少有二个属性,一个是job name, 任务名称, 一个就是script。

image

指定一个基础Docker镜像作为基础运行环境,经常用到的镜像有node nginx docker

job:
  image: node:latest
  script: npm install

在上面这个任务中,如果不指定image: node:latest 执行下面的npm install时会报错,找不到npm的命令。
image的作用就是给当前任务或者当前流水线设置一个基础环境,有可能是nodejs,也有可能是java, go, php,
可以设置当前流水线的,也可以设置当前任务的。

artifacts

翻译出来这个单词就是制品,一个成品,作用是将流水线过程中的一些文件,文件夹,打包压缩,提供一个外链供人下载,另外还能在后续的job中缓存。
比如我们构建一个前端项目后将dist目录做成一个压缩包,

build:
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

在这个任务后面运行的任务会自动恢复这个制品,意味着你不用再执行npm run build来获取编译后的dist文件了,
在安卓,ios打包的时候,非常有用,因为流水线最终输出的就是一个可下载,可安装的应用。
paths 是用来指定将那些文件,目录放入制品中,
也可以使用exclude关键词,将那些目录,文件排除,支持正则表达式。
此外还有以下几个属性

  • paths 文件路径
  • exclude 排除的文件
  • name 制品名称
  • expose_as 在UI页面导出的名称
  • untracked 布尔类型,是否将git忽略的文件加到制品中
  • when on_success;on_failure;always 何时上传制品
  • expire_in 过期时间默认30天
  • reports 收集测试报告
build:
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    exclude:
      - binaries/**/*.o
    expose_as: 'artifact 1'
    name: "$CI_COMMIT_REF_NAME"
    untracked: false
    expire_in: 2 hrs 20 min
    when: on_failure
tags

tags 关键词是用于指定Runner,tags的取值范围是在该项目可见的runner tags中,可以在Setting =>CI/CD => Runner 中查看的到。
要知道,改属性可以设置全局,不设置则默认使用公有Runner去执行流水线。每个任务可以指定一个Runner,可以指定多个标签,但runner却只能一个。以一个为准。tags是在我们注册Runner是配置的,后续也可以更改。

install:
  tags:
    - hello-vue
    - docker
  script:
    - npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
    - npm install --registry=http://registry.npm.taobao.org
cache

缓存是将当前工作环境目录中的一些文件,一些文件夹存储起来,用于在各个任务初始化的时候恢复。避免多个下载同样的包,能够大大优化流水线效率。在前端项目中,我们经常把node_modules缓存起来,这样一条流水线都可以使用这些下载好的包。在java项目中经常把maven下载的包缓存起来。以备后用
cache下的参数有

  • paths 当前工作环境下的目录
  • key 存储的key,key不变不会重新生成缓存,
  • prefix 使用一些文件制作成文件hash值,当做key的一部分,
  • untracked 是否缓存git忽略的文件
  • when 定义何时存储缓存 on_success;on_failure;always
  • policy 缓存是否要在job完成后重新上传

缓存可以设置流水线全局,也可以在job中设置

cache:
  key: hello-vue-cache
  paths:

   - node_modules
cache:
  key:
    files:
      - Gemfile.lock
      - package.json
  paths:
    - vendor/ruby
    - node_modules
stage

stage 是阶段的意思,用于归档一部分的job,按照定义的stage顺序来执行。
默认的stage有build,test,deploy, 此外还有两个特殊的.pre 和 .post
job执行的顺序不是按照编写的顺序,大体上是按照stage定义的顺序来执行的,注意是大体,也有例外的情况。

stages:

  - build
  - test
  - deploy

job 0:
  stage: test
  script: echo 'tets'

job 1:
  stage: build
  script: echo 'build'

由于build在test之前所有会指向job1这个任务,后指向job0任务

when

when关键字是实现在发生故障或尽管发生故障时仍能运行的作业。比如你要在任务失败后需要触发一个job,
或者你需要手动执行任务,或者当你一个任务执行成功后,执行另一个任务.

  • on_success 所有任务执行成功后
  • on_failure 当至少一个任务失败后
  • always 执行作业,而不考虑作业在早期阶段的状态。
  • manual 手动执行任务
  • delayed 延迟执行任务
  • never

在rules中不排除执行的任务

在workflow:rules不允许的流水线

only/except

only/except 是规定当前job的可见状态,一个项目有很多分支,tag,我们的流水线,为了对特定的分支,特定的tag执行不同的job,这里就要使用only和except
在任务上加上这一段代码,就表明当前任务只有在master分支可以运行

only:
  - master

也可以根据当前的代码变动是合并,还是推送,还是使用API来触发的。
如果一个任务没有only属性,那默认就是
only: ['branches', 'tags'] 操作分支或者tags都会触发流水线。

before_script

before_script 关键词是用于在每个任务之前执行的脚本,但是会在artifacts恢复之后执行。你可以这样定义一个全局的before_script,

default:
  before_script:
   - echo "Execute this script in all jobs that don't already have a before_script section."

也可以在一个任务中中单独定义

job:
  before_script:
    - echo "Execute this script instead of the global before_script."
  script:
    - echo "This script executes after the job's `before_script`"

任务中的before_script会覆盖全局的before_script

after_script

after_script与before_script类似,用于定义多行脚本,会在任务执行完成后执行,即使任务失败也会被执行。如果任务被取消或者超时,after_script就不会被执行了,目前官方正在计划这个特性。
可以定义全局的,也可以定义局部的

default:
  after_script:
    - echo "Execute this script in all jobs that don't already have an after_script section."

job1:
  script:
    - echo "This script executes first. When it completes, the global after_script executes."

job:
  script:
    - echo "This script executes first. When it completes, the job's `after_script` executes."
  after_script:
    - echo "Execute this script instead of the global after_script."
dependencies

dependencies关键词是定义特定的job运行规则。默认artifacts是从当前阶段产生,在后续的阶段都会被下载,但我们可以使用dependencies关键词来控制artifacts从哪里下载,
这里有一个例子,

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

test:linux:
  stage: test
  script: make test:linux
  dependencies:
    - build:linux

deploy:
  stage: deploy
  script: make deploy

根据这个例子我们不难看出,
任务test:osx 依赖build:osx
任务test:linux 依赖 build:linux
这样配置以后 任务test:linux 就不用等任务build:osx 执行完成在执行了,只需要等待任务build:linux完成
很好地利用了依赖关系来优化流水线的速率,前四个任务都执行完成后,才会执行最后一个部署的任务。

environment

environment是用于定义环境变量,可以是用k-v的方式定义

deploy to production:
  stage: deploy
  script: git push production HEAD:master
  environment:
    name: production

需要注意的是这里定义的环境变量是不能在script值使用的。
这个关键词可以和review和merge搭配。

extends

这个关键词可以使一个任务继承另一个任务。
如下案例

.tests:
  script: rake test
  stage: test
  only:
    refs:
      - branches

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

任务rspec 继承了.tests任务,在流水线中.tests是一个隐藏的任务,在流水线中,以英文远点开头的任务名,都是隐藏的任务。不会被执行。 被rspec继承后,相同的key会以rspec为准,rspec没有的,而.tests有的,则合并到rspec中,
合并后的结果是

rspec:
  script: rake rspec
  stage: test
  only:
    refs:
           - branches
    riables:
      - $RSPEC

使用这一个手段,可以写一个模板,只要稍微改改就能后使用。非常适合大批量编写流水线。

include

使用include可以导入一个或多个额外的yaml文件到你的CICD配置里,这一你就可以将一个很长的流水线,分隔出来。使用include来引入。
也可以将几个流水线中相同的配置,提取出来,公用。引入的文件扩展名 必须是.yaml或者.yml两种,其他的不行。
include 关键词下,有四个可选性,
local, 引入一个当前项目的文件
file, 引入一个不同项目的文件
remote, 引入一个公网文件,
template, 引入一个由GitLab提供的模板

下面是几个例子

include:
  - local: '/templates/.gitlab-ci-template.yml'
include:
  - project: 'my-group/my-project'
    file: '/templates/.gitlab-ci-template.yml'
include:
  - local: '/templates/.gitlab-ci-template.yml'
include:
  - project: 'my-group/my-project'
    ref: master
    file: '/templates/.gitlab-ci-template.yml'
    
  - project: 'my-group/my-project'
    ref: v1.0.0
    file: '/templates/.gitlab-ci-template.yml'
    
  - project: 'my-group/my-project'
    ref: 787123b47f14b552955ca2786bc9542ae66fee5b  # Git SHA
    file: '/templates/.gitlab-ci-template.yml'
include:
  - remote: 'https://gitlab.com/awesome-project/raw/master/.gitlab-ci-template.yml'
trigger

trigger 是应对那些更加复杂的CICD流程,如多流水线,父子流水线
使用它可以定义一个下游的流水线,配置了trigger的任务是不能跑脚本的,就是说不能定义script, before_script, 和 after_script.
项目这个是一个多项目流水线

rspec:
  stage: test
  script: bundle exec rspec

staging:
  stage: deploy
  trigger: my/deployment

流水线执行完test任务后就会去执行my/deployment项目的流水线

配置下游流水线式也可以执行分支

rspec:
  stage: test
  script: bundle exec rspec

staging:
  stage: deploy
  trigger:
    project: my/deployment
    branch: stablez
rules

rules是用于规定任务的执行规则,使用一个表达式,来规范那些任务执行,那些任务不执行.还可以在任务成功,或者失败后,触发另一个任务。
如下面这个例子

docker build:
  script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
  rules:

   - if: '$CI_COMMIT_BRANCH == "master"'
     when: delayed
     start_in: '3 hours'
     allow_failure: true

如果当前的分支是master分支则任务执行就延迟3个小时,并且允许失败。
rules的下面有是哪个可选属性

  • if 使用if表达式 添加或移除一个任务, 类似 only:variables.
  • changes 根据某些个文件是否改变来追加或移除一些任务。类似 only:changes.
  • exists 根据是否存在特定文件来追加或移除一些任务

if中可以使用CICD的所有预设变量,分支,来源,合并请求,commit,push web,schedule等。可以针对不用的情景配置不用的规则。
在看下这个例子

job:
  script: echo "Hello, Rules!"
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
      when: manual
      allow_failure: true

解释起来并不复杂,一个判断语句,二句赋值语句。即如果当前分支是master,在任务的执行方式改为手动,并且运行失败。

allow_failure

allow_failure是一个布尔类型, true或false, 默认为false,表示当前任务是否允许失败。有这样一个应用场景,在使用eslint检查代码的时候,如果团队管理松散,可以将在eslint的任务下设置allow_failure: true,(其实这样还不如去掉这个任务那,手动狗头) 这样即使这个任务报错了,流水线也会继续往下走。如果一个任务设置了allow_failure: true,并且这个任务报错了,那么它将会显示黄色警告。但有种情况任务失败了也会停止的, 那就是任务设置了when: manual,即手动操作的任务。手动启动的任务,报错了就会停止,不会继续执行后续任务,除非在rule设置报错的处理逻辑。

coverage

coverage 是用于获取项目的代码覆盖率,这个配置项的值只能是一个正则表达式,官方有提供一些,在CICD的General pipelines里
覆盖率可以添加到项目的readme上,像这样的。

pages

pages是一项特殊的工作,用于将静态内容上传到GitLab,可用于为您的网站提供服务,其实就是可以托管你的网站。它具有特殊的语法,因此必须满足以下两个要求:

  • 任何静态内容都必须放在public/目录下。
  • 制品artifacts必须是目录public/,就是编译后的文件必须存放在public中

下面的示例将所有文件从项目的根目录移至public/目录。这里必须先创建一个.public 目录,防止根目录下已经存在public了,导致循环复制。

pages:
  stage: deploy
  script:

   - mkdir .public
     - cp -r * .public
       - mv .public public
         artifacts:
         paths:
     - public
       only:
         - master
release

release关键词是用于创建一个release,即创建一个发布,
创建一个发布,可以配置这些内容

  • tag_name tag 名称
  • description 描述
  • name 名称
  • ref 提交的hash值
  • milestones 要关联的里程碑
  • released_at 创建时间
ios-release:
  script:
    - echo 'iOS release job'
  release:
    tag_name: v1.0.0-ios
    description: 'iOS release v1.0.0'
resource_group

有时在环境中同时运行多个作业或流水线时可能会导致在部署过程中出错。

为了避免这些错误,resource_group可以使用该属性来确保运行程序不会同时运行某些任务。资源组的行为类似于其他编程语言中的信号灯。

当一个任务设置了resource_group , 同一项目的不同管道之间任务的运行是互斥的。如果属于同一资源组的多个任务同时进入队列,则运行程序仅选择其中一个作业。其他作业将等到 resource_group释放。

deploy-to-production:
  script: deploy
  resource_group: production

在这种情况下,两个deploy-to-production单独流水线中的两个作业永远无法同时运行。最后的结果及时你可以确保永远不会在生产环境中发生并发部署。

您可以为每个环境定义多个资源组。例如,当部署到物理设备时,您可能有多个物理设备。可以将每个设备部署到,但是在任何给定时间每个设备只能部署一个。

resource_group值只能包含字母,数字,-, _, /, $, {, }, .,和空格。它不能以开头或结尾/。

retry

retry可以设置一个任务的重试次数,值的类型是数字 最大是2,如果设置2,就表明该任务最多可以执行3次,其中包括2次重试。对于网络不稳定的部署,非常有用。

test:
  script: rspec
  retry: 2
timeout

timeout是用于设置一个任务的超时时间,
你也可以设置一个项目级别的超时时间。在CICD的设置中

build:
  script: build.sh
  timeout: 3 hours 30 minutes

test:
  script: rspec
  timeout: 3h 30m
variables

variables可以让你在yaml文件中定义变量,变量可以设置全局的,也可以是单个任务内定义。然后在script或者执行的命中使用,定义和使用的示例,

variables:
  DEPLOY_SITE: "https://example.com/"

deploy_job:
  stage: deploy
  script:
    - deploy-script --url $DEPLOY_SITE --path "/"

deploy_review_job:
  stage: deploy
  variables:
    REVIEW_PATH: "/review"
  script:
    - deploy-review-script --url $DEPLOY_SITE --path $REVIEW_PATH

变量名一般大写,使用时使用$加变量名