1. GitLab CI/CD是啥?
CI,CONTINUOUS INTEGRATION,持续集成。简单来说就是自动化构建和测试。
一个应用程序的代码存储在Git仓库中。开发人员推送的每个更改,甚至是开发分支,都可以通过一组脚本来自动地构建和测试。这些测试可确保更改通过您为应用程序建立的所有测试、指南和代码合规性标准。
CD,CONTINUOUS DELIVERY,持续交付。简单来说就是自动化构建和测试+支持手动触发部署。
每次将代码更改推送到代码库时,不仅会自动构建和测试应用程序,还支持一键部署应用程序,这里的部署需要手动触发。
CD,CONTINUOUS DEPLOYMENT,持续部署。简单来说就是自动化构建和测试+自动部署。
持续部署类似于持续交付,不同之处在于,不是手动触发部署应用程序,而是将其设置为自动部署。
而GitLab CI/CD,就是一种支持在GitLab中配置使用持续集成、持续交付和持续部署的工具。GitLab CI/CD通过使用YAML文件定义作业流程和流水线(pipelines),可实现复杂的应用程序的自动化构建和部署。
参考文档:
2. GitLab CI/CD基本概念
- pipeline:在每个仓库中,使用名为
.gitlab-ci.yml
的yaml文件配置gitlab ci/cd流水线(pipeline) - stage:一条流水线可以包含多个阶段(stage),一个阶段可以包含多个作业
- job:作业(job)是具体要执行的任务,是命令脚本语句的集合
- runner:runner是每个作业的执行节点;每个作业可以根据标签选择不同的执行节点
3. Gitlab CI/CD工作机制
1、在gitlab仓库中的根目录下添加.gitlab-ci.yml
文件,定义流水线
2、当仓库中发生commit、push、merge等事件时,根据.gitlab-ci.yml
的定义触发流水线
3、流水线会调用gitlab runner,在gitlab runner中按照.gitlab-ci.yml
的定义跑作业
4. 配置第一个流水线
4.1. 配置.gitlab-ci.yml
为了配置GitLab CI/CD流水线,首先需要在项目根目录创建一个.gitlab-ci.yml
文件,并定义需要执行的作业和阶段。
1 | stages: |
这个简单的例子定义了三个作业,每个作业分别执行构建、测试和部署脚本。
4.2. 注册Runner
为了让流水线工作,我们需要至少一个注册的Runner。可以使用GitLab提供的共享Runner,或者自己安装和注册一个专用的Runner。
注册Runner步骤如下:
1、在GitLab页面上,进入我们的项目设置。
2、寻找CI/CD设置,找到Runners部分。
3、我们会看到用于注册Runner的URL和Token。
4、在具有网络访问权限的机器上安装Runner并运行注册命令,使用提供的URL和Token。
更多Runner相关内容,参考文档《好好学GitLab:GitLab Runner入门篇》
5. 流水线典型示例
1 | stages: #对stages的编排 |
6. 流水线语法
6.1. 流水线语法概述
GitLab CI/CD流水线是由 .gitlab-ci.yml 文件中定义的一系列规则和指令组成。这个文件使用YAML语法来描述CI/CD的过程。
GitLab CI/CD 流水线配置包括:
- 配置流水线行为的全局关键字
- 配置作业行为作业关键字
参考文档:
6.2. 全局关键字
- default 作业关键字的自定义默认值。
- stages 流水线阶段的名称和顺序。
- workflow 控制运行的流水线类型。
- include 从其他 YAML 文件导入配置。
6.3. 作业关键字
6.3.1. 执行命令
- before_script:作业在运行前执行的Shell命令行
- script:作业在运行中执行的Shell命令行,每个作业至少要包含一个script
- after_script:作业在运行后执行的Shell命令行
有了before_script、script、和after_script,可以方便我们把通用的脚本抽象出来。
- before_script:有命令执行结果非0,job判定失败,不再执行before_script的后续命令,跳过script,继续执行after_script
- script:有命令执行结果为0,job判定失败,不再执行script的后续命令,继续执行after_script
- after_script:有命令执行结果非0,job判定不受影响,不再执行after_script后续命令
6.3.2. 环境变量
- variables:在作业级别定义作业变量。
- environment:作业部署到的环境的名称。
- secrets:作业所需的 CI/CD secret 信息。secret属于enviroment。
6.3.3. 作业条件
- stage:定义作业阶段,指定当前作业所属的阶段名称,从而确定作业顺序
- only:满足条件时执行作业
- except:满足条件时不执行作业
- rules:12.3之后引入的特性,不能与only/except混用,具体用法参考【jobs:rules作业控制】一节
- when:何时运行作业。
- needs:在 stage 顺序之前执行的作业。
- tags:根据标签选择运行作业的Runner节点,如果有多个标签,则匹配具有所有标签的Runner节点
- image:指定执行作业的脚本时应该启动哪个 Docker 镜像作为执行环境,成为主容器。这个 Docker 镜像应包含所有必要的依赖和工具,以便能够运行定义在 script 部分的命令。需要Runner支持Docker。
- services:指定与主容器相连的额外容器服务。这些服务可以是数据库、缓存等。
- allow_failure:允许作业失败。失败的作业不会导致流水线失败。
- parallel:应该并行运行多少个作业实例。
- resource_group:限制作业并发。
- trigger:定义下游流水线触发器。
6.3.4. 超时与重试
- retry:在失败的情况下可以自动重试作业的时间和次数。
- timeout:定义优先于项目范围设置的自定义作业级别超时。
6.3.5. 继承
- extends:此作业继承自的配置条目。
- inherit:选择所有作业继承的全局默认值。
6.3.6. 其他
- artifacts:成功时附加到作业的文件和目录列表。
- cache:应在后续运行之间缓存的文件列表。
- coverage:给定作业的代码覆盖率设置。
- dast_configuration:在作业级别使用来自 DAST 配置文件的配置。
- dependencies:通过提供要从中获取产物的作业列表,来限制将哪些产物传递给特定作业。
- interruptible:定义当新运行使作业变得多余时,是否可以取消作业。
- pages:上传作业的结果,与 GitLab Pages 一起使用。
- release:指示运行器生成 release 对象。
7. 流水线部分关键字详解
7.1. variables环境变量
环境变量可以分为两类:全局变量和局部变量,局部变量优先级高于全局变量
- 全局变量是整个流水线生效的,局部变量是仅在作业中生效的
- 全局变量可以使用CI自带的预定义变量,也可以自定义变量
- 全局变量定义在全局 variables 中,也可以定义在 workflow:rules:variables 中
- 局部变量定义在 job:variables 中,也可以定义在 job:rules:variables 中
.gitlab-ci.yml解析顺序为:全局变量 -> workflow规则 -> job规则
因此优先级顺序为:job中变量优先级 > workflow中变量优先级 > 全局变量优先级
常用全局预定义变量:
变量名称 | GitLab | GitLab Runner | 描述 |
---|---|---|---|
CI | all | 0.4 | 对CI/CD中的所有作业可见,值为true |
CI_BUILDS_DIR | all | 11.10 | 构建时的最顶层目录 |
CI_COMMIT_AUTHOR | 13.11 | all | 提交的作者,格式为:名称<邮箱> |
CI_COMMIT_BEFORE_SHA | 11.2 | all | 当前分支的上一个提交哈希值 |
CI_COMMIT_BRANCH | 12.6 | 0.5 | 提交的分支名,在合并流水线和tag流水线时不可见 |
CI_COMMIT_DESCRIPTION | 10.8 | all | 提交的描述 |
CI_COMMIT_MESSAGE | 10.8 | all | 完整的提交信息 |
CI_COMMIT_REF_NAME | 9.0 | all | 项目的分支名或tag名 |
CI_COMMIT_REF_PROTECTED | 11.11 | all | 如果作业正在构建的是被保护的分支或tag,值为true |
CI_COMMIT_REF_SLUG | 9.0 | all | CI_COMMIT_REF_NAME的小写形式。 |
CI_COMMIT_SHA | 9.0 | all | 提交的完整哈希值 |
CI_COMMIT_SHORT_SHA | 11.7 | all | 8个字符的提交哈希值 |
CI_COMMIT_TAG | 9.0 | 0.5 | 提交的tag,仅在tag流水线可见 |
CI_COMMIT_TIMESTAMP | 13.4 | all | 提交时的时间戳 |
CI_COMMIT_TITLE | 10.8 | all | 提交的标题 |
CI_DEFAULT_BRANCH | 12.4 | all | 项目的默认分支 |
CI_DEPLOY_FREEZE | 13.2 | all | 当流水运行是处于部署冻结阶段时可见,值为true。 |
CI_ENVIRONMENT_NAME | 8.15 | all | 当前作业的部署环境名,当设置了environment:name 时可见 |
CI_ENVIRONMENT_URL | 9.3 | all | 当前作业的部署环境地址,只有设置了environment:url可见 |
CI_JOB_ID | 9.0 | all | 当前作业的ID,系统内唯一 |
CI_JOB_IMAGE | 12.9 | 12.9 | 当前作业使用的Docker镜像名 |
CI_JOB_NAME | 9.0 | 0.5 | 当前作业名称 |
CI_JOB_STAGE | 9.0 | 0.5 | 当前作业所属的阶段名 |
CI_PIPELINE_ID | 8.10 | all | 当前流水线ID(实例级),系统内唯一 |
CI_PIPELINE_SOURCE | 10.0 | all | 流水线触发方式,枚举值为push,web, schedule, api, external, chat, webide,merge_request_event, external_pull_request_event, parent_pipeline, trigger, 或者 pipeline |
CI_PIPELINE_TRIGGERED | all | all | 当作业是使用trigger触发的时为true |
CI_PIPELINE_URL | 11.1 | 0.5 | 流水线详情的地址 |
CI_PIPELINE_CREATED_AT | 13.10 | all | 流水线创建时间 |
CI_PROJECT_DIR | all | all | 存放克隆项目的完整路径,作业运行的目录。 |
CI_PROJECT_NAME | 8.10 | 0.5 | 当前项目名称,不包含组名 |
CI_PROJECT_NAMESPACE | 8.10 | 0.5 | 项目的命名空间(组名或用户名) |
CI_PROJECT_PATH | 8.10 | 0.5 | 包含项目名称的命名空间 |
CI_PROJECT_TITLE | 12.4 | all | 项目名称(网页上显示的) |
CI_PROJECT_URL | 8.10 | 0.5 | 项目HTTP(S)地址 |
CI_RUNNER_TAGS | 8.10 | 0.5 | 逗号分割的runner标签列表 |
GITLAB_USER_EMAIL | 8.12 | all | 开始当前作业的用户邮箱 |
GITLAB_USER_LOGIN | 10.0 | all | 开始当前作业的登录用户名 |
GITLAB_USER_NAME | 10.0 | all | 开始当前作业的用户名 |
CI_MERGE_REQUEST_APPROVED (仅合并流水线) | 14.1 | all | 当合并流水线的MR被通过时值为true |
CI_MERGE_REQUEST_ASSIGNEES (仅合并流水线) | 11.9 | all | 逗号分割的合并请求指派人列表 |
CI_MERGE_REQUEST_SOURCE_BRANCH_NAME(仅合并流水线) | 11.6 | all | 合并请求中的源分支名称 |
CI_MERGE_REQUEST_TARGET_BRANCH_NAME(仅合并流水线) | 11.6 | all | 合并请求中的目标分支名称 |
CI_MERGE_REQUEST_TITLE(仅合并流水线) | 11.9 | all | 合并请求的标题 |
预定义变量详情参考文档:
7.2. 全局关键字
7.2.1. workflow:rules流水线控制
使用 workflow:rules 关键字来控制何时创建流水线。
workflow:rules 关键字在作业之前进行评估。例如,将作业配置为针对标签运行,但工作流阻止标签流水线,则该作业永远不会运行。
rules包含以下关键字:
- if:条件判断,为true时再看对应的when规则。
- when:取值
never
表示流水线不运行,取值always
或者缺省表示流水线运行。- 最后一个规则的if缺省,
when: always
表示其他所有流水线类型都运行。 - 最后一个规则不是
when: always
,表示其他所有流水线类型都不运行。
- 最后一个规则的if缺省,
- variables:定义特定流水线条件的变量(引入于13.11版本)。例如不同分支,同一个变量可以定义不同的值。
参考文档:
- GitLab CI/CD workflow 关键字
- .gitlab-ci.yml 关键字参考 - workflow
- Interaction between workflow:rules and rules
7.2.2. stages阶段控制
- stages里可以定义各个stage执行的前后顺序,但是
.pre
和.post
阶段不受其控制 .pre
阶段的作业总是在流水线开始时执行.post
阶段的作业总是在流水线结束时执行- 如果两个或者多个作业,指向同一个阶段名称,则该阶段下的所有作业都并行运行;如果不能并行运行,需要检查runner的配置文件中的
concurrent
7.2.3. include
使用 include 在 CI/CD 配置中包含外部 YAML 文件。 您可以将一个长的 .gitlab-ci.yml 文件拆分为多个文件以提高可读性,或减少同一配置在多个位置的重复。
您还可以将模板文件存储在中央仓库中并将它们包含在项目中。
include 文件说明:
- 与 .gitlab-ci.yml 文件中的那些合并。
- 无论 include 关键字的位置如何,始终先求值,然后与 .gitlab-ci.yml 文件的内容合并。
include 子键:
- include:local
- include:project,include:file,include:ref
- include:remote
- include:template
注意:如果include了多个文件中都包含stages,那么最后一个文件中的stages会生效。
参考文档:gitlab-ci - include
7.3. 作业关键字
7.3.1. job:rules作业控制
使用 job:rules 关键字来控制何时创建作业。
rules包含以下子关键字:
- if:条件判断,为true时再看对应的其他规则。
- if的语法和bash中的if语法很像
- 不同1:模式匹配时添加了两个斜杠
- 不同2:变量不能加花括号(版本14.0.5)
- when:前面的作业成功或者失败时运行。on_success(默认值)前面作业成功时执行;on_failure 前面作业失败时执行;always 总是执行;manual 手动执行;delayed&start_in 延迟执行;never 永不执行。
- allow_failure:是否允许作业失败,默认值为false。启用后,作业失败不会阻塞接下来的任务。
- retry:作业遇到错误重新运行的次数。
- timeout:作业运行超时时间。
- needs:作业依赖控制。当前作业可能只依赖前一个stage的其中一个作业,就不用等前一个stage的作业全部完成。
- parallel:生成多个作业,并行运行。值在
2-50
之间。 - variables:定义特定作业条件下的变量。
参考文档:
7.3.2. extends
使用 extends 来重用配置 section。它是 YAML 锚点 的替代方案,并且更加灵活和可读。
关键字类型:作业关键字。您只能将其用作作业的一部分。
可能的输入:
- 流水线中另一个作业的名称。
- 流水线中其他作业的名称列表(数组)。
注意:extends父作业时,如果不想执行父作业,那么父作业的名称应该以点.
开头。
参考文档:gitlab-ci - extends
7.3.3. job:services
使用services可以指定job运行所依赖的服务镜像。
GitLab CI/CD会为每个任务创建一个Docker网络,并且把任务容器(主容器)和服务容器都连接到这个网络上。
服务容器的别名就是它在这个网络上的主机名,所以任务容器可以通过别名来访问服务容器提供的端口。
使用Docker执行器的话,任务和服务都跑在容器中。
使用Shell执行器的话,任务跑在执行器所在的机器上,服务跑在容器中。同时,执行器所在机器需要安装Docker。
参考文档:
7.3.4. job:artifacts
job:artifacts的作用是将Job执行后生成的文件或目录存储在GitLab服务器上,供后续的Job或用户下载和使用。我们可以通过UI或API来下载Job artifacts。需要注意的是,Job artifacts的大小不能超过配置的最大值。
artifacts常用关键字:
- paths:所有指定的路径中的文件,都会被放入artifacts目录。用于指定任意类型的Job artifact,例如编译后的二进制文件、日志文件、图片文件等,这些类型的Job artifact可以被后续的Job或用户下载和使用。只有在Job执行成功时才会上传,除非指定了when:always参数。
- name:指定制品名称,默认制品名称是
artifacts
,下载时对应artifacts.zip
。 - exclude:排除不要放入artifacts目录的文件。
- expire_in:制品的过期时间,默认30天。每小时会自动删除一次过期制品。
- expose_as:要在制品下载链接的UI中显示的名称。
- public:制品是否可以公开下载。
- reports:用于指定一些特定类型的Job artifact,例如JUnit测试报告、代码覆盖率报告、性能测试报告等,这些报告是可以在GitLab的流水线视图、性能仪表盘和安全仪表盘中查看的。总是上传制品,无论Job执行成功还是失败。
- untracked:是否把
.gitignore
中忽略的文件也作为制品,默认false,不包含被忽略的文件。 - when:什么时候上传制品。取值on_success、on_failure和always,只对paths生效,reports一定会上传。
下载制品的方法:进入CI/CD Pipelines页面,找到Job对应的Pipeline,最右边三个点,点击下载artifacts。
参考文档:
7.3.5. job:coverage
将覆盖率与自定义正则表达式一起使用,可以配置如何从作业输出中提取代码覆盖率。如果作业输出中至少有一行与正则表达式匹配,则覆盖率将显示在UI中。
参考文档:
8. 常用配置
8.1. 当流水线成功时合并分支
1、项目配置
Project -> Settings -> General -> Merge requests -> Expand -> Merge checks -> 勾选 Pipelines must succeed
2、gitlab-ci配置
gitlab-ci配置时,要保证workflow和job中都允许merge requests触发pipeline。
3、触发合并请求
gitlab页面上发起一次合并请求,或者使用glab发起合并请求
4、流水线成功时自动合并
打开合并代码的页面,当pipeline运行时,点击 Merge when pipeline succeeds
参考文档: