前言
之前有专门写过一篇文章,对gitlab ci进行介绍,其中有涉及到gitlab-ci.yml进行介绍,那可能会有疑问,为什么要再开一篇来再说yml这玩意?
主要是因为之前在用gitlab-ci遇到不少问题,一路上摸索不容易,虽然有前车之鉴,但仍然遇到不可描述的问题,因为想重新了解下这块,当做是一个笔记;
上一篇关于gitlab ci介绍的链接:
https://juejin.cn/post/6844903609864290311
gitlab-ci运行介绍
由以下两个模块组成:
gitlab-ci server
gitlab-ci-runner
其中,gitlab-ci server负责调度、触发Runner,以及获取返回结果.
而gitlab-ci-runner则是主要负责来跑自动化CI(测试,编译,打包等)。
基本流程是:
用户提交代码
检查是否有.gitlab-ci.yml文件
如果无,则结束;
如果有,则调用runner执行脚本
获取返回的结果。
.gitlab-ci.yml
从7.12版本开始,GitLab CI使用YAML文件(.gitlab-ci.yml)来管理项目配置。
该文件存放于项目仓库的根目录,它定义该项目如何构建。
开始构建之前YAML文件定义了一系列带有约束说明的任务。
这些任务都是以任务名开始并且至少要包含script
部分:
job1:
script:
- echo "jb1"
job2:
script:
- echo "jb2"
上面例子是一个简单且带有两个独立任务的CI配置,每个任务分别执行echo输出对应的内容。
script
可以直接执行系统命令
(例如:./configure;make;make install)或者是直接执行脚本(test.sh)
任务是由Runners接管并且由服务器中runner执行。
每一个任务的执行过程都是独立运行的。
例子1:
# 定义 stages
stages:
- build
- test
# 定义 job
job1:
stage: test
script:
- echo "I am jb1"
- echo "I am in test stage"
# 定义 job
job2:
stage: build
script:
- echo "I am jb2"
- echo "I am in build stage"
根据在 stages 中的定义,build 阶段要在 test 阶段之前运行,
所以 stage:build 的 jobs 会先运行,
之后才会运行 stage:test 的 jobs。
再来个复杂的例子2:
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:
- docker5+4X5=25
下面列出保留字段,这些保留字段不能被定义为job
名称:
关键字 | 是否必须 | 描述 |
---|---|---|
image | 否 | 用于docker镜像,查看docker文档 |
services | 否 | 用于docker服务,查看docker文档 |
stages | 否 | 定义构建阶段 |
types | 否 | stages 的别名(已废除) |
before_script | 否 | 定义在每个job之前运行的命令 |
after_script | 否 | 定义在每个job之后运行的命令 |
variable | 否 | 定义构建变量 |
cache | 否 | 定义一组文件列表,可在后续运行中使用 |
image和services
这两个关键字允许使用一个自定义的Docker镜像和一系列的服务,并且可以用于整个job周期。
before_script
before_script
用来定义所有job之前运行的命令,包括deploy(部署) jobs,
但是在修复artifacts之后。它可以是一个数组或者是多行字符串。
after_script
GitLab 8.7 开始引入,并且要求Gitlab Runner v1.2
after_script
用来定义所有job之后运行的命令。它必须是一个数组或者是多行字符串;
stages
stages
用来定义可以被job调用的stages。
stages中的元素顺序决定了对应job的执行顺序:
1. 相同stage的job可以平行执行。
2. 下一个stage的job会在前一个stage的job成功后开始执行。
这里划重点:下一个stage的job会在前一个stage的job成功后开始执行,
正因为如此,所以可以在stage设定很多相互依赖的步骤,而且不需要判断是否成功状态,因为能执行下来的,必定是成功的!
看会上方的例子1:
stages:
- build
- test
-
- 首先,所有
build
的job都是并行执行的
- 首先,所有
-
- 所有
build
的jobs执行成功后,test
的jobs才会开始并行执行
- 所有
- 3.所有的
test
的jobs执行成功,commit才会标记为success
- 4.任何一个前置的jobs失败了,commit都会标记为
failed
并且下一个stages的jobs都不会执行。
这里提两个特殊例子:
1.如果.gitlab-ci.yml中没有定义stages,那么jobs的stages会默认定义成build,test和deploy
2.如果一个job没有指定stage,那么这个任务会分配到test stage
types
已废除,将会在10.0中移除。用stages替代,含义与stages一致
variable
GItLab CI 允许在.gitlab-ci.yml
文件中添加变量,并在job环境中起作用。
因为这些配置是存储在git仓库中,所以最好是存储项目的非敏感配置,例如:
variables:
jb: "jb is here"
这里注意,:号后面是带上空格的,不然会说语法错误 这些变量可以被后续的命令和脚本使用.
除了用户自定义的变量外,Runner也可以定义它自己的变量。
CI_COMMIT_REG_NAME
就是一个很好的例子,它的值表示用于构建项目的分支或tag名称。
除了在.gitlab-ci.yml中设置变量外,还有可以通过GitLab的界面上设置私有变量。
cache
用来指定需要在job之间缓存的文件或目录。只能使用该项目工作空间内的路径。
从GitLab 9.0开始,pipelines和job就默认开启了缓存
如果cache
定义在jobs的作用域之外,那么它就是全局缓存,所有jobs都可以使用该缓存。
缓存git中没有被跟踪的文件:
rspec:
script: test
cache:
untracked: true
缓存binaries
下没有被git跟踪的文件:
rspec:
script: test
cache:
untracked: true
paths:
- binaries/
缓存key
key
指令允许我们定义缓存的作用域(亲和性),可以是所有jobs的单个缓存,也可以是每个job,也可以是每个分支或者是任何你认为合适的地方。
cache:key
可以使用任何的预定义变量
缓存每个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-ci.yml
允许指定无限量jobs。
每个jobs必须有一个唯一的名字,而且不能是上面提到的关键字。
job由一列参数来定义jobs的行为。
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,用来指定选择哪个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
script
是Runner执行的yaml脚本。
job:
script: "bundle exec rspec"
该参数也可以用数组包含多个命令:
job:
script:
- uname -a
- bundle exec rspec
这里需要注意一点,如果script命令里面包含冒号:时,script需要被包在双引号内,这样YAML解析器才可以正确解析为一个字符串,而不是一个键值对(key:value);
使用下面这些特殊字符的时候,都要注意下:
:,{,},[,],,,&,*,#,?,|,-,<,>,=,!。
stage
stage
允许一组jobs进入不同的stages。
jobs在相同的stage时会parallel同时进行;
更多的用法请点击这里;
tags
tags
可以从允许运行此项目的所有Runners中选择特定的Runners来执行jobs。
在注册Runner的过程中,我们可以设置Runner的标签,比如ruby,postgres,development。
tags可通过tags来指定特殊的Runners来运行jobs:
job:
tags:
- ruby
- postgres
上面这个示例中,需要确保构建此job的Runner必须定义了ruby和postgres这两个tags。
allow_failure
allow_failure
可以用于当你想设置一个job失败的之后并不影响后续的CI组件的时候。
失败的jobs不会影响到commit状态。
下面的这个例子中,job1和job2将会并列进行,如果job1失败了,它也不会影响进行中的下一个stage,因为这里有设置了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
when
when
is used to implement jobs that are run in case of failure or despite the failure.
翻译过来就是:用于实现在失败或失败时运行的作业。
可以设置以下值:
on_success - 只有前面stages的所有工作成功时才执行。 这是默认值。
on_failure - 当前面stages中任意一个jobs失败后执行。
always - 无论前面stages中jobs状态如何都执行。
`manual ` - 手动执行。
举个例子:
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 。
- 不管前一个job执行失败还是成功都会执行`cleanup_job 。
- 可以从GitLab界面中手动执行deploy_jobs。
coverage
允许你配置代码覆盖率将会从该job中提取输出。
在这里正则表达式是唯一有效的值。
因此,字符串的前后必须使用/包含来表明一个正确的正则表达式规则。特殊字符串需要转义。
举个例子:
job1:
coverage: '/Code coverage: \d+\.\d+/'
Git Strategy
GitLab 8.9中以试验性功能引入。将来的版本中可能改变或完全移除。GIT_STRATEGY要求GitLab Runner v1.7+。
可以通过设置GIT_STRATEGY用于获取最新的代码,可以再全局variables或者是在单个job的variables模块中设置。
如果没有设置,将从项目中使用默认值。
可以设置的值有:clone,fetch,和none。
clone
是最慢的选项。它会从头开始克隆整个仓库,包含每一个job,以确保项目工作区是最原始的。
variables:
GIT_STRATEGY: clone
当它重新使用项目工作区是,fetch
是更快(如果不存在则返回克隆)。
git clean
用于撤销上一个job做的任何改变,git fetch
用于获取上一个job到现在的的commit。
variables:
GIT_STRATEGY: fetch
none
也是重新使用项目工作区,但是它会跳过所有的Git操作(包括GitLab Runner前的克隆脚本,如果存在的话)。
它主要用在操作job的artifacts(例如:deploy)。
variables:
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执行项目工作区更新到最新
variables:
GIT_STRATEGY: clone
GIT_CHECKOUT: false
script:
- git checkout master
- git merge $CI_BUILD_REF_NAME
Git Submodule Strategy
GIT_SUBMODULE_STRATEGY
变量用于在构建之前拉取代码时,Git子模块是否或者如何被引入。
它的可用值有:none,normal和recursive:
1)none意味着在拉取项目代码时,子模块将不会被引入。这个是默认值.
2)normal意味着在只有顶级子模块会被引入。它相当于
git submodule sync
git submodule update --init
3)recursive意味着所有的子模块(包括子模块的子模块)都会被引入,他相当于:
git submodule sync --recursive
git submodule update --init --recursive
注意:如果想要此功能正常工作,子模块必须配置(在.gitmodules)下面中任意一个:
可访问的公共仓库http(s)地址,
在同一个GitLab服务器上有一个可访问到另外的仓库的真实地址。
Job stages attempts
正在执行的job将会按照你设置尝试次数依次执行下面的stages:
变量 | 描述 |
---|---|
GET_SOURCES_ATTEMPTS | 获取job源的尝试次数 |
ARTIFACT_DOWNLOAD_ATTEMPTS | 下载artifacts的尝试次数 |
RESTORE_CACHE_ATTEMPTS | 重建缓存的尝试次数 |
默认是一次尝试。
例子:
variables:
GET_SOURCES_ATTEMPTS: 3
pages
pages是一个特殊的job,用于将静态的内容上传到GitLab,可用于为您的网站提供服务。
它有特殊的语法,因此必须满足以下两个要求:
任何静态内容必须放在public/目录下
artifacts必须定义在public/目录下
下面的这个例子是将所有文件从项目根目录移动到public/目录。
.public工作流是cp,并且它不会循环复制public/本身。
pages:
stage: deploy
script:
- mkdir .public
- cp -r * .public
- mv .public public
artifacts:
paths:
- public
only:
- master
Runner 定义的变量
上面在介绍variable的时候,有提及到Runner也有自己定义的变量,如下:
变量 | gitlab版本 | runner | 描述 |
---|---|---|---|
CI | all | 0.4 | 标记这个 job 是在 CI 环境执行的 |
CI_COMMIT_REF_NAME | 9.0 | all | 构建项目的 branch 或 tag 名称 |
CI_COMMIT_REF_SLUG | 9.0 | all | $CI_COMMIT_REF_NAME小写,除了0-9和a-z,替换为- |
CI_COMMIT_SHA | 9.0 | all | 构建项目的 commit SHA 值 |
CI_COMMIT_TAG | 9.0 | 0.5 | 构建项目的 commit 的 tag 名,只有在构建 tags 时才会使用。 |
CI_COMMIT_MESSAGE | 10.8 | all | 完整的提交消息。 |
CI_COMMIT_TITLE | 10.8 | all | 提交的标题——消息的完整第一行 |
CI_COMMIT_DESCRIPTION | 10.8 | all | 对提交的描述 |
CI_CONFIG_PATH | 9.4 | 0.5 | CI 配置文件路径,默认值是 .gitlab-ci.yml |
CI_DEBUG_TRACE | all | 1.7 | 是否启用 debug tracing 跟踪调试功能 |
CI_DEPLOY_USER | 10.8 | all | GitLab部署令牌的身份验证用户名 |
CI_DEPLOY_PASSWORD | 10.8 | all | GitLab部署令牌的身份验证密码 |
CI_DISPOSABLE_ENVIRONMENT | all | 10.1 | 标记job 是否运行在一次性环境中 |
CI_ENVIRONMENT_NAME | 8.15 | all | 执行 job 的环境名,如 produciton,dev,pre-production 等 |
CI_ENVIRONMENT_SLUG | 8.15 | all | 环境名称的简化版本,适用于DNS、url、Kubernetes标签等。 |
CI_ENVIRONMENT_URL | 9.3 | all | 执行 job 的环境 URL |
CI_JOB_ID | 9.0 | all | 当前 job 在 GitLab CI 内部的唯一 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容器注册表进行身份验证的令牌 |
CI_JOB_URL | 11.0 | 0.5 | 工作的URL |
CI_REPOSITORY_URL | 9.0 | all | 克隆 Git repository 的 URL |
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_RUNNER_VERSION | all | 10.6 | 正在执行当前 job 的 GitLab Runner 版本 |
CI_RUNNER_REVISION | all | 10.6 | 正在执行当前 job 的 GitLab Runner 修订版本 |
CI_RUNNER_EXECUTABLE_ARCH | all | 10.6 | GitLab GitLab Runner 可执行程序的 OS/架构 |
CI_PIPELINE_ID | 8.10 | 0.5 | 当前 pipeline 在 GitLab CI 内部的唯一 ID |
CI_PIPELINE_TRIGGERED | all | all | 标记这个 job 是 triggered 由触发器触发的 |
CI_PIPELINE_SOURCE | 10.0 | all | 标明如何触发 pipeline 。 可用的选项有: push, web, trigger, schedule, api, and pipeline |
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 当前正在构建的项目命名空间 (用户名或groupname) | |
CI_PROJECT_PATH | 8.10 | 0.5 | 完整的项目路径,即命名空间+项目名 |
CI_PROJECT_PATH_SLUG | 9.3 | all | $CI_PROJECT_PATH 小写,除了0-9和a-z,替换为- |
CI_PIPELINE_URL | 11.0 | 0.5 | Pipeline 详细URL |
CI_PROJECT_URL | 8.10 | 0.5 | 访问项目的HTTP地址 |
CI_PROJECT_VISIBILITY | 10.3 | all | 项目可见性(内部、私人、公共) |
CI_REGISTRY | 8.10 | 0.5 | 如果启用了注册中心,它将返回GitLab的注册表的地址 |
CI_REGISTRY_IMAGE | 8.10 | 0.5 | 如果为项目启用了注册表,那么它将返回与特定项目相关联的登记处地址 |
CI_REGISTRY_PASSWORD | 9.0 | all | 用来将容器推到GitLab容器注册表的密码 |
CI_REGISTRY_USER | 9.0 | all | 用来将容器推到GitLab容器注册表的用户名 |
CI_SERVER | all | all | 标记CI环境中执行 |
CI_SERVER_NAME | all | all | 用于协调作业的CI服务器的名称 |
CI_SERVER_REVISION | all | all | 用于安排工作的GitLab修订 |
CI_SERVER_VERSION | all | all | 用于安排工作的GitLab版本 |
CI_SHARED_ENVIRONMENT | all | 10.1 | 标记工作是在共享环境中执行的 |
GET_SOURCES_ATTEMPTS | 8.15 | 1.9 | 试图获取运行作业的资源的次数 |
GITLAB_CI | all | all | 在GitLab CI环境中执行该作业 |
GITLAB_USER_EMAIL | 8.12 | all | 开始工作的用户的电子邮件 |
GITLAB_USER_ID | 8.12 | all | 开始工作的用户的id |
GITLAB_USER_LOGIN | 10.0 | all | 启动该工作的用户的登录用户名 |
GITLAB_USER_NAME | 10.0 | all | 启动工作的用户的真实姓名 |
RESTORE_CACHE_ATTEMPTS | 8.15 | 1.9 | 试图休息的次数 |
因为没有汉化版,因此都是拿到网上翻译的,大致了解就行,详细信息,可以看官网的介绍:
https://docs.gitlab.com/ce/ci/variables/README.html
不过从上面runner自己定义的变量,是真的有很多很实用的变量,之前写脚本都是没有用变量,自己造轮子的~
小结
本文主要介绍了.gitlab-ci.yml一些常用的指令,比较常用的就是jobs,stages跟runner自己定义的变量,其他的可以先了解;
就介绍到这里吧,主要介绍常用的,剩下的,可以去官网了解下:
https://docs.gitlab.com/ce/ci/yaml/README.html
下篇文章会介绍,怎么在gitlab ci上获取每次提交的信息,并且发送到钉钉通知,这块也不难,感兴趣的同学可以想想怎么做;
谢谢大家~