GitLab-CI/CD使用手册

412 阅读15分钟

一般情况无需修改.gitlab-ci.yml通用模板文件 如修改特定需求参考下方参数配置

GitLab CI介绍

  • GitLab提交持续集成服务,当你在项目根目录中添加 .gitlab-ci.yml文件,并配置项目的运行器( GitLab Runner),那么后续的每次提交都会触发CI流水线(pipeline)的执行。
  • .gitlab-ci.yml文件告诉运行器需要做哪些事情,默认情况下,流水线有build 、test 、deploy三个阶段,即构建测试部署,未被使用的阶段将会被自动忽略。
  • 如果一切运行正常(没有非零返回值),您将获得与提交相关联的漂亮绿色复选标记(如下图所示)。这样可以在查看代码之前轻松查看提交是否导致任何测试失败。

gitlab_cicd_green_checkmark.png

  • 大多数项目使用GitLab的CI服务来运行测试套件,以便开发人员在破坏某些内容时可以立即获得反馈。使用持续交付和持续部署将测试代码自动部署到模拟环境和生产环境的趋势越来越明显。

  • 由于将 .gitlab-ci.yml文件存放在仓库中进行版本控制,使用单一的配置文件来控制流水线,具有读访问权限的每个人都可以查看内容,从而使其更有吸引力地改进和查看构建脚本。旧的版本也能构建成功,forks项目也容易使用CI,分支可以有不同的流水线和作业。

  • .gitlab-ci.yml定义每个项目的流水线的结构和顺序,由以下两个因素决定:

    • GiTlab Runner运行器使用的执行器( executor),执行器常用的 Shell 、 Docker 、Kubernets , 我们当前仅使用 Shell执行器,后续再使用其他执行器。
    • 遇到进程成功或失败时等条件时做出的决定。
  • 可以在 Getting started with GitLab CI/CD 查看到流水线的简单示例。

  • 可以在 GitLab CI/CD Examples 查看更多的流水线示例。

  • 在流水线脚本中可以使用预定义的全局变量,详细可查看 GitLab CI/CD Variables 。

  • 企业级的.gitlab-ci.yml示例可查看gitlab.com/gitlab-org/…

  • Job作业是.gitlab-ci.yml文件的基本元素,每个作业至少有 script脚本子句,在流水线中可以定义任意多个作业。

  • 每个作业必须具有唯一的名称,但有一些保留的关键字不能用作作业名称,保留关键字(reserved keywords)有image、 servicesstagestypesbefore_script、 after_scriptvariablescache

.gitlab-ci.yml配置参数

关键字描述
script必须参数,运行器需要执行的脚本
image使用Docker image镜像
services使用Docker services镜像
before_script作业执行前需要执行的命令
after_script作业执行后需要执行的命令
stages定义流水线所有的阶段
stage定义作业所处流水线的阶段(默认test阶段)
only限制作业在什么时候创建
except限制作业在什么时候不创建
tags作用使用的Runner运行器的标签列表
allow_failure允许作业失败,失败的作业不影响提交的状态
when什么时候运行作业
environment作用部署的环境名称
cache指定需要在job之间缓存的文件或目录
artifacts归档文件列表,指定成功后应附加到job的文件和目录的列表
dependencies当前作业依赖的其他作业,你可以使用依赖作业的归档文件
coverage作业的代码覆盖率
retry作业失败时,可以自动执行多少次
parallel指定并行运行的作业实例
trigger定义下游流水线的触发器
include作业加载其他YAML文件
extends控制实体从哪里继承
pages上传GitLab Pages的结果
retry作业失败时,可以自动执行多少次
variables定义环境变量

参数详解

script

script是作业中唯一必须的关键字参数,是运行器需要执行的脚本,如:

yml

build1:
  script:
    - echo "Do your build here"
    - uname -a

表示build1作业需要执行的命令是输出"Do your build here"。

警告

Sometimes, script commands will need to be wrapped in single or double quotes. For example, commands that contain a colon (😃 need to be wrapped in quotes so that the YAML parser knows to interpret the whole thing as a string rather than a “key: value” pair. Be careful when using special characters: :, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, `. 即使用冒号时应使用引号包裹起来,使用特殊字符时需要特别注意!!!注意如果要输出冒号字符,冒号后面不能紧接空格!!!

image

image指定使用Docker镜像。如iamge:name,暂时忽略。

services

services 指定使用Docker镜像服务。如 services:name,暂时忽略。

before_script

before_script用于定义在所有作业之前需要执行的命令,比如更新代码、安装依赖、打印调试信息之类的事情。

示例:

yaml

before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script

after_script用于定义在所有作业(即使失败)之后需要执行的命令,比如清空工作空间。

示例:

yaml

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

重要说明

  • before_scriptscript在一个上下文中是串行执行的,after_script是独立执行的,即after_scriptbefore_script/script的上下文环境不同。

  • after_script会将当前工作目录设置为默认值。

  • 由于after_script是分离的上下文,在after_script中无法看到在before_scriptscript中所做的修改:

    • before_scriptscript中的命名别名、导出变量,对after_script不可见;
    • before_scriptscript在工作树之外安装的软件,对after_script不可见。
  • 你可以在作业中定义before_scriptafter_script,也可以将其定义为顶级元素,定义为顶级元素将为每一个任务都执行相应阶段的脚本或命令。作业级会覆盖全局级的定义。

示例:

yaml

before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

build1:
  stage: build
  before_script:
    - echo "Before script in build stage that overwrited the globally defined before_script"
    - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
    - yum install cloc -y
  after_script:
    - echo "After script in build stage that overwrited the globally defined after_script"
    - cloc --version
    - cloc .
  script:
    - echo "Do your build here"
    - cloc --version
    - cloc .
  tags:
    - bluelog

将修改上传提交,查看作业build1的控制台输出:

job_before_script_overwrited_global_before_script.pngjob_after_script_overwrited_global_after_script.png

可以发现build1作业的before_scriptafter_script将全局的before_scriptafter_script覆盖了。

stages

stages定义流水线全局可使用的阶段,阶段允许有灵活的多级管道,阶段元素的排序定义了作业执行的顺序。

  • 相同 stage阶段的作业并行运行。
  • 默认情况下,上一阶段的作业全部运行成功后才执行下一阶段的作业。
  • 默认有三个阶段, build 、testdeploy三个阶段,即 构建测试部署 。
  • 如果一个作业未定义 stage阶段,则作业使用 test测试阶段。
  • 默认情况下,任何一个前置的作业失败了,commit提交会标记为failed并且下一个stages的作业都不会执行。

stage

stage定义流水线中每个作业所处的阶段,处于相同阶段的作业并行执行。

示例:

yaml

# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options


before_script:
  - echo "Before script section"
  - echo "For example you might run an update here or install a build dependency"
  - echo "Or perhaps you might print out some debugging details"

after_script:
  - echo "After script section"
  - echo "For example you might do some cleanup here"

stages:
  - build
  - code_check
  - test
  - deploy

build1:
  stage: build
  before_script:
    - echo "Before script in build stage that overwrited the globally defined before_script"
    - echo "Install cloc:A tool to count lines of code in various languages from a given directory."
    - yum install cloc -y
  after_script:
    - echo "After script in build stage that overwrited the globally defined after_script"
    - cloc --version
    - cloc .
  script:
    - echo "Do your build here"
    - cloc --version
    - cloc .
  tags:
    - bluelog

find Bugs:
  stage: code_check
  script:
    - echo "Use Flake8 to check python code"
    - pip install flake8
    - flake8 --version
    - flake8 .
  tags:
    - bluelog
    
test1:
  stage: test
  script:
    - echo "Do a test here"
    - echo "For example run a test suite"
  tags:
    - bluelog

test2:
  stage: test
  script:
    - echo "Do another parallel test here"
    - echo "For example run a lint test"
  tags:
    - bluelog

我们增加一个 code_check阶段,该阶段有一个作业find Bugs,该作业主要是先安装Flake8,然后使用Flake8对Python代码进行规范检查。

job_code_check_failed.png

由于Flake8检查到了Python代码中的缺陷,导致find Bugs作业失败!这样可以控制开发人员提交有坏味道的代码到仓库中。

另外,在上一个流水线中,Test阶段的作业test1和test2是并行执行的,如下图所示:

test_jobs_are_executed_in_parallel.png

本次(pipeline #7)流水线由于在作业find Bugs检查不通过,导致整个流水线运行失败,后续的作业不会执行:

code_check_failed_no_jobs_of_further_stage_are_executed.png

说明

默认情况下,GitLab Runner运行器每次只执行一个作业,只有当满足以下条件之一时,才会真正的并行执行:

  • 作业运行在不同的运行器上;
  • 你修改了运行器的concurrent设置,默认情况下concurrent = 1

onlyexcept

onlyexcept用于在创建作业时对作业的限制策略。

  • only定义了哪些分支或标签(branches and tags)的作业会运行
  • except定义了哪些分支或标签(branches and tags)的作业不会运行

下面是策略规则:

  • onlyexcept可同时使用,如果在一个作业中同时定义了onlyexcept,则onlyexcept同时进行过滤(注意,不是忽略 except条件) 。
  • onlyexcept可以使用正则表达式。
  • onlyexcept允许指定用于过滤forks作业的存储库路径。
  • onlyexcept中可以使用特殊的关键字,如branchestagsapiexternalpipelinespushesschedulestriggerswebmerge_requestschats等。

onlyexcept中可以使用特殊的关键字:

关键字描述释义
branches当一个分支被push上来
tags当一个打了tag标记的Release被提交时
api当一个pipline被第二个piplines api所触发调起(不是触发器API)
external当使用了GitLab以外的外部CI服务,如Jenkins
pipelines针对多项目触发器而言,当使用CI_JOB_TOKEN,
并使用gitlab所提供的api创建多个pipelines的时候
pushes当pipeline被用户的git push操作所触发的时候
schedules针对预定好的pipline计划而言(每日构建一类)
triggers用触发器token创建piplines的时候
web在GitLab WEB页面上Pipelines标签页下,按下run pipline的时候
merge_requests当合并请求创建或更新的时候
chats当使用GitLab ChatOps 创建作业的时候

在下面这个例子中,job将只会运行以issue-开始的refs(分支),然而except中指定分支不能执行,所以这个job将不会执行:

job:
  # use regexp
  only:
    - /^issue-.*$/
  # use special keyword
  except:
    - branches

匹配模式默认是大小写敏感的(case-sensitive),使用i标志,如/pattern/i可以使匹配模式大小写不敏感:

job:
  # use regexp
  only:
    - /^issue-.*$/i
  # use special keyword
  except:
    - branches

下面这个示例,仅当指定标记的tags的refs引用,或者通过API触发器的构建、或者流水线计划调度的构建才会运行:

job:
  # use special keywords
  only:
    - tags
    - triggers
    - schedules

仓库的路径(repository path)只能用于父级仓库执行作业,不能用于forks:

job:
  only:
    - branches@gitlab-org/gitlab-ce
  except:
    - master@gitlab-org/gitlab-ce
    - /^release/.*$/@gitlab-org/gitlab-ce

上面这个例子,将会在所有分支执行,但不会在master主干以及以release/开头的分支上执行。

  • 当一个作业没有定义only规则时,其默认为only: ['branches', 'tags']
  • 如果一个作业没有定义except规则时,则默认except规则为空。

下面这个两个例子是等价的:

job:
  script: echo 'test'

转换后:

job:
  script: echo 'test'
  only: ['branches', 'tags']

说明

关于正则表达式使用的说明:

  • 因为@用于表示ref的存储库路径的开头,所以在正则表达式中匹配包含@字符的ref名称需要使用十六进制字符代码\x40
  • 仅标签和分支名称才能使用正则表达式匹配,仓库路径按字面意义匹配。
  • 如果使用正则表达式匹配标签或分支名称,则匹配模式的整个引用部分都是正则表达式。
  • 正则表达式必须以/开头和结尾,即/regular expressions/,因此,issue-/.*/不会匹配以issue-开头的标签或分支。
  • 可以在正则表达式中使用锚点^$,用来匹配开头或结尾,如/^issue-.*$//^issue-/等价,但 /issue/却可以匹配名称为severe-issues的分支,所以正则表达式的使用要谨慎!

tags

tags关键字用于指定GitLab Runner运行器使用哪一个运行器来执行作业。

下面这个例子中,只有运行器注册时定义了rubypostgres两个标签的运行器才能执行作业:

yaml

job:
  tags:
    - ruby
    - postgres

allow_failure

  • allow_failure可以用于当你想设置一个作业失败的之后并不影响后续的CI组件的时候。失败的作业不会影响到commit提交状态。
  • 如果允许失败的作业失败了,则相应的作业会显示一个黄色的警告,但对流水线成功与否不产生影响。

下面的这个例子中,job1和job2将会并列进行,如果job1失败了,它也不会影响进行中的下一个阶段,因为这里有设置了allow_failure: true:

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

但是如果上面的job2执行失败,那么job3则会受到影响而不会执行。

when

when关键字用于实现在作业失败时或发生故障时运行的作业 (when is used to implement jobs that are run in case of failure or despite the failure.)。

when可以设置以下值:

  • on_success:只有前面的阶段的所有作业都成功时才执行,这是默认值。
  • on_failure:当前面阶段的作业至少有一个失败时才执行。
  • always: 无论前面的作业是否成功,一直执行本作业。
  • manual:手动执行作业,作业不会自动执行,需要人工手动点击启动作业。
  • delayed: 延迟执行作业,配合start_in关键字一起作用,start_in设置的值必须小于或等于1小时,``start_in设置的值示例:10 seconds30 minutes1 hour`,前面的作业结束时计时器马上开始计时。

示例:

yaml

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

说明:

  • 只有在build_job构建作业失败时,才会执行cleanup_build_job作业。
  • 需要在GitLab Web界面手动点击,才能执行deploy_job部署作业。
  • 无论之前的作业是否成功还是失败,``cleanup_job`清理作业一直会执行。

延时处理的示例:

timed rollout 10%:
  stage: deploy
  script: echo 'Rolling out 10% ...'
  when: delayed
  start_in: 30 minutes

上面的例子创建了一个"timed rollout 10%"作业,会在上一个作业完成后30分钟后才开始执行。

如果你点击"Unschedule"按钮可以取消一个激活的计时器,你也可以点击"Play"按钮,立即执行延时作业。

dependencies

  • dependencies依赖关键字应该与artifacts工件关键字联合使用,允许你在不同作业间传递工件。
  • 默认情况下,会传递所有本作业之前阶段的所有工件。
  • 需要在作业上下文中定义dependencies依赖关键字,并指出所有需要使用的前序工件的作业名称列表。 作业列表中不能使用该作业后的作业名称 。
  • 定义空的依赖项,将下不会下载任何工件。
  • 使用依赖项不会考虑前面作业的运行状态。

示例:

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

上面示例中,build:osxbuild:linux两个作业定义了工件,test:osx作业执行时,将会下载并解压 build:osx的工件内容。相应的,test:linux也会获取build:linux的工件。deploy作业会下载全部工件。

说明

如果作为依赖的作业的工件过期或者被删除,那么依赖这个作业的作业将会失败。

coverage

  • coverage可以从作业的输出log中提取代码覆盖率。
  • 仅支持正则表达式方式获取覆盖率。
  • 字符串的前后必须使用/包含来表明一个正确的正则表达式规则。特殊字符串需要转义。

下面是一个简单的例子:

job1:
  coverage: '/Code coverage:\d+.\d+%/'

如在作业日志中输出了"Code coverage:80.2%",我们使用上面的正则表达式就可以获取到代码的覆盖率。然后在作业的右上角处就会显示Coverage:80.2%

retry

  • retry重试关键字用于配置当作业失败时可以重新执行的次数。
  • 当作业失败时,如果配置了retry,那么该作业就会重试,直到允许的最大次数。
  • 如果retry设置值为2,如果第一次重试运行成功了,那么就不会进行第二次重试。
  • retry设置值只能是0、1、2三个整数。

下面是一个简单的例子:

test:
  script: rspec
  retry: 2
  • 为了更好的控制重试次数,retry可以设置以下两个关键字:
  • max: 最大重试次数
  • when: 何时重试

下面这个例子只有当运行器系统出现故障时才能最多重试两次:

test:
  script: rspec
  retry:
    max: 2
    when: runner_system_failure

如果上面例子中出现的是其他故障,那么作业不会重试。

为了针对多种重试情形,我们可以使用矩阵形式罗列出错误情形,如下示例:

test:
  script: rspec
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure

when可以是以下值:

  • always: 一直重试,默认值。
  • unknown_failure:当错误未知时重试。
  • script_failure: 脚本错误时重试。
  • api_failure: API调用错误时重试。
  • stuck_or_timeout_failure: 作业卡信或超时错误时重试。
  • runner_system_failure: 运行器系统错误(如设置工作失败)时重试。
  • missing_dependency_failure: 依赖工件丢失错误时重试。
  • runner_unsupported: 运行器不支持错误时重试。

trigger

  • trigger关键字用于多项目流水线时,定义下游的流水线工程,由于社区版本不支持此功能,不详细介绍。具体可参考 trigger

include

  • include包含关键字可以将其他yaml文件载入到当前的.gitlab-ci.yml配置文件中,详情请查看官网指导 include

extends

  • extends扩展用于定义当前作业从哪里继承。
  • 它是使用YAML锚点的替代方案,更加灵活、可读性强。详情请查看官网指导 extends

pages

  • pages是一项特殊工作,用于将静态内容上传到GitLab,可用于为您的网站提供服务。详情请查看官网指导 GitLab Pages