一般情况无需修改.gitlab-ci.yml通用模板文件 如修改特定需求参考下方参数配置
GitLab CI介绍
- GitLab提交持续集成服务,当你在项目根目录中添加
.gitlab-ci.yml文件,并配置项目的运行器(GitLab Runner),那么后续的每次提交都会触发CI流水线(pipeline)的执行。 .gitlab-ci.yml文件告诉运行器需要做哪些事情,默认情况下,流水线有build、test、deploy三个阶段,即构建、测试、部署,未被使用的阶段将会被自动忽略。- 如果一切运行正常(没有非零返回值),您将获得与提交相关联的漂亮绿色复选标记(如下图所示)。这样可以在查看代码之前轻松查看提交是否导致任何测试失败。
-
大多数项目使用GitLab的CI服务来运行测试套件,以便开发人员在破坏某些内容时可以立即获得反馈。使用持续交付和持续部署将测试代码自动部署到模拟环境和生产环境的趋势越来越明显。
-
由于将
.gitlab-ci.yml文件存放在仓库中进行版本控制,使用单一的配置文件来控制流水线,具有读访问权限的每个人都可以查看内容,从而使其更有吸引力地改进和查看构建脚本。旧的版本也能构建成功,forks项目也容易使用CI,分支可以有不同的流水线和作业。 -
.gitlab-ci.yml定义每个项目的流水线的结构和顺序,由以下两个因素决定:- GiTlab Runner运行器使用的执行器(
executor),执行器常用的Shell、Docker、Kubernets, 我们当前仅使用Shell执行器,后续再使用其他执行器。 - 遇到进程成功或失败时等条件时做出的决定。
- GiTlab Runner运行器使用的执行器(
-
可以在 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、services、stages、types、before_script、after_script、variables、cache。
.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_script和script在一个上下文中是串行执行的,after_script是独立执行的,即after_script与before_script/script的上下文环境不同。 -
after_script会将当前工作目录设置为默认值。 -
由于
after_script是分离的上下文,在after_script中无法看到在before_script和script中所做的修改:- 在
before_script和script中的命名别名、导出变量,对after_script不可见; before_script和script在工作树之外安装的软件,对after_script不可见。
- 在
- 你可以在作业中定义
before_script,after_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的控制台输出:
可以发现build1作业的before_script和after_script将全局的before_script和after_script覆盖了。
stages
stages定义流水线全局可使用的阶段,阶段允许有灵活的多级管道,阶段元素的排序定义了作业执行的顺序。
- 相同
stage阶段的作业并行运行。 - 默认情况下,上一阶段的作业全部运行成功后才执行下一阶段的作业。
- 默认有三个阶段,
build、test、deploy三个阶段,即构建、测试、部署。 - 如果一个作业未定义
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代码进行规范检查。
由于Flake8检查到了Python代码中的缺陷,导致find Bugs作业失败!这样可以控制开发人员提交有坏味道的代码到仓库中。
另外,在上一个流水线中,Test阶段的作业test1和test2是并行执行的,如下图所示:
本次(pipeline #7)流水线由于在作业find Bugs检查不通过,导致整个流水线运行失败,后续的作业不会执行:
说明
默认情况下,GitLab Runner运行器每次只执行一个作业,只有当满足以下条件之一时,才会真正的并行执行:
- 作业运行在不同的运行器上;
- 你修改了运行器的
concurrent设置,默认情况下concurrent = 1。
only和except
only和except用于在创建作业时对作业的限制策略。
only定义了哪些分支或标签(branches and tags)的作业会运行except定义了哪些分支或标签(branches and tags)的作业不会运行
下面是策略规则:
only和except可同时使用,如果在一个作业中同时定义了only和except,则only和except同时进行过滤(注意,不是忽略except条件) 。only和except可以使用正则表达式。only和except允许指定用于过滤forks作业的存储库路径。only和except中可以使用特殊的关键字,如branches、tags、api、external、pipelines、pushes、schedules、triggers、web、merge_requests、chats等。
only和except中可以使用特殊的关键字:
| 关键字 | 描述释义 |
|---|---|
| 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运行器使用哪一个运行器来执行作业。
下面这个例子中,只有运行器注册时定义了ruby和postgres两个标签的运行器才能执行作业:
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 seconds、30 minutes、1 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:osx和build: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