.gitlab-ci.yml 的详细介绍
文档用途
详见官方文档 CI/CD YAML syntax reference.
Pipeline
手动执行
Pipeline 会在每次 push 后触发, 但也可以手动触发.
在 GitLab 某个工程的网页左侧, CI/CD > Pipelines 页面, 点击下图中的按钮.

避免执行
若希望在 push 的时候跳过 CI/CD 流程, 可以选用以下任意一种方案:
- 在 commit message 中添加
[skip ci]或者[ci skip]. - 通过 Git push option, 也就是使用
git push -o ci.skip命令.
默认与继承
可以通过 default 来设置那些会默认被所有 Job 继承的字段.
default:
before_script:
- echo "nice"
retry: 2在 Job 中默认进程 default 中的所有字段.
如果不想继承, 或只打算继承一部分, 可以这么做:
default:
before_script:
- echo "nice"
retry: 2
job1:
script: echo "job1"
inherit:
# 放弃继承 default 中的所有字段 #
default: false
job2:
script: echo "job2"
inherit:
# 只继承 default 中的 retry 字段 #
default:
- retryWorkflow
Workflow 可以决定 "在什么情况下执行 Pipeline".
如果使用了 Merge Request 工作流,
并且限制了远程主分支不能 push (只能通过 MR 合并),
则推荐使用以下 Workflow 设置:
## 工作流控制
workflow:
rules:
## 如果通过 GitLab 网页手动发起, 则总会执行
- if: $CI_PIPELINE_SOURCE == "web"
when: always
## git push 时不执行
- if: $CI_PIPELINE_SOURCE == "push"
when: never
## 其他未指明的情况会执行
- when: always多文件
当 Job 数量比较多时, 建议将他们写在多个文件中, 并通过 include 字段来引用.
## 引用本地路径中的文件
include:
- local: .gitlab/*.yml对应的工程目录举例:
.gitlab
| android.gitlab-ci.yml
| ios.gitlab-ci.yml
| template.gitlab-ci.yml
| variables.gitlab-ci.yml
|
\---issue_templates
bug-report.md下游管线
INFO
我们可以通过某个管线中 Job 触发另一个管线.
主动触发的管线被称之 上游管线 (Upstream Pipeline),
被触发的管线被称之为 下游管线 (Downstream Pipeline).
INFO
下游管线实际上有两类情况: parent-child 和 multi-project.parent-child 是指同一个代码仓库, 由父管线触发子管线.multi-project 涉及到两个不同的代码仓库, 由其中一个管线触发另一个管线.
我们在这里只讨论 multi-project 这种情况, 因为更常用.
# 此 job 应该写在 upstream pipeline
trigger-job:
# 这里的环境变量将会传递至 downstream pipline
variables:
MY_ENVIRONMENT: yahaha
trigger:
# downstream pipeline 对应的代码仓库路径
project: project-group/my-downstream-project
# 若添加这一行, 那么下游管线的执行结果会反映到上游管线.
# 例如下游管线执行失败, 那么上有管线也会被标记为失败.
strategy: depend# 此 job 应该写在 downstream pipeline
my-job:
rules:
# 判断触发方式, "pipeline" 说明触发自其他代码仓库的管线
- if: $CI_PIPELINE_SOURCE == "pipeline"
script: echo "This job is triggered by multi-project pipeline"Variables
作用域
预定义的, 以及在 GitLab 网页中自定义的环境变量, 作用域都是 全局 (贯穿整个 Pipeline).
在 .gitlab-ci.yml 中的 variables 根字段 中所定义的环境变量, 作用域也是 全局.
在 .gitlab-ci.yml 中的 Job 内的 variables 字段中所定义的环境变量, 作用域 仅限当前 Job.
全局变量
可以设置全局变量的备选值:
variables:
ENABLE_FEATURE_A:
description: "Enable Feature A"
# 默认值
value: "false"
# 备选值
options:
- "true"
- "false"当我们在网页中尝试手动触发一次 Pipeline 时, 将会看到所有存在备选值的全局变量:

WARNING
不要将密码等敏感信息写入 .gitlab-ci.yml 文件中.
有的环境变量会影响 gitlab-runner 的行为, 详见官方文档 Configuring runners.
例如可以通过以下环境变量, 让 gitlab-runner 采取更快的压缩算法.
variables:
# The GitLab Runner feature flag FF_USE_FASTZIP must also be enabled.
# Use fast compression for artifacts and cache, resulting in larger archives.
ARTIFACT_COMPRESSION_LEVEL: fast
CACHE_COMPRESSION_LEVEL: fast局部变量
既可以定义全局变量, 也可以在 job 中定义仅能在其内部使用的变量:
variables:
TEST_VAR: "All jobs can use this variable's value"
job1:
variables:
TEST_VAR_JOB: "Only job1 can use this variable's value"
script:
- echo "$TEST_VAR" and "$TEST_VAR_JOB"借助 inherit 字段, 可以选择性地继承全局变量.
variables:
VARIABLE1: "This is variable 1"
VARIABLE2: "This is variable 2"
VARIABLE3: "This is variable 3"
job1:
script: echo "This job does not inherit any global variables."
# 放弃继承任意全局变量
inherit:
variables: false
job2:
script: echo "This job inherits only the two listed global variables."
# 选择一部分全局变量来继承
inherit:
variables:
- VARIABLE1
- VARIABLE2Jobs
基础说明
Job 是 .gitlab-ci.yml 中最基础的元素, 定义了什么条件下任务会被执行.
每个 Job 都应该有独特的名字, 并且至少包含一个 script 语句.
命名限制
Job 命名有限制, 不能使用以下名称:
image, services, stages, types, before_script, after_script, variables,
cache, include, true, false, nil
将 Job 分组
当有一些列非常类似的 Job 时, 可以考虑使用 "分组" 机制将它们合并显示.
将 Job 分组的可选方案如下:
| 语法 | 举例 |
|---|---|
| 用斜杠分隔 | test 1/3, test 2/3, test 3/3 |
| 用冒号分隔 | test 1:3, test 2:3, test 3:3 |
| 用空格分隔 | test 0 3, test 1 3, test 2 3 |
分组之后 Job 在 GitLab 网页中的显示效果如下图:

隐藏与模板
有时候我们不希望执行某个 Job, 此时可以直接将相关代码注释掉,
也可以在 Job 名称前面加上一个英文句号:
.hidden_job:
script:
- run test"在 Job 名称前加上英文句号" 这种方式, 特别适合那些作为 模板 的 Job.
## 作为模板的 Job
.build-app:
stage: build
script:
- echo "build $BUILD_TARGET"
# 使用模板
build-ios-app:
# 通过 extends 字段引用模板
extends: .build-app
variables:
BUILD_TARGET: iOS
# 使用模板
build-android-app:
# 通过 extends 字段引用模板
extends: .build-app
variables:
BUILD_TARGET: Android当与模板中的字段发生冲突时, 以 "最后添加的字段" 为准.
INFO
在使用 模板 时, 虽然可以使用 YAML Anchor 特性, 但更建议使用 extends 字段.
因为 YAML Anchor 不能 跨文件引用, 也就是说无法引用那些被 include 的模板.
执行的条件
使用 rules 字段给 Job 的执行设立条件, 必须满足条件才会执行 Job.
upload-ios-app:
script:
- echo "uploading archive to AppStore Connect"
rules:
# 满足此条件时, 执行该 Job
- if: $UPLOAD_IOS_APP == "true"
# 其他情况下, 通过网页中的按钮手动执行
- when: manual执行的顺序
默认情况下, 如果不使用 needs 字段, Job 将会按照 stage 来执行.
例如按照下方的配置, 将会以 .pre, test, build, deploy, .post 的顺序执行.
其中 .pre 和 .post 是 GitLab 默认的 stage, 分别代表着最早和最晚的 stage.
stages:
- test
- build
- deploy当我们使用 needs 字段时, Job 将会 无视 stage, 而是按照依赖关系来执行.
如下图所示, 我们可以直接在 Pipeline 页面中看到 Job 之间的依赖关系.

needs 字段的用法示例:
test-job:
stage: test
script:
- echo "test passed"
build-job:
stage: build
script:
- echo "build"
# 通过 needs 字段建立依赖
needs:
- job: test-job如果希望某个 Job 在 Pipeline 启动时就立即执行, 可以这么做:
my-job:
script:
- echo "my-job"
needs: [] TIP
不难发现, stage 与 needs 字段的功能有部分重叠, 所以我们在此探讨 job 执行顺序的最佳实践.needs 可以精细控制 job 之间的依赖关系, 使得 job 的 "并行执行" 变得更容易, 显然应该优先使用.
但 stage 也有其价值, 它让 pipeline 的各阶段在视觉上一目了然地划分成组.
因此笔者建议同时使用这两者, 完全使用 needs 来控制执行顺序, 同时借助 stage 提升可读性.
Artifacts
在 GitLab 中 artifacts 是指: 在 Job 中被指定的文件.
这些文件在 Job 的执行过程中产生, 会被自动上传时 GitLab 服务器.
我们可以将那些需要被保存的文件作为 artifacts 上传至 GitLab.
例如重要 Job 的日志, 自动化测试结果, 构建好的安装包或可执行文件.
.build-app:
stage: build
script:
- echo "build $BUILD_TARGET"
artifacts:
# 即使 Job 执行失败, 也上传 artifacts (方便查看错误日志)
when: always
# 所有 artifacts 文件的路径 (可以是文件夹)
paths:
- $LOG_PATH/log.txt
- $BUILD_PATH
# 3 天后这些 artifacts 将会被 GitLab 删除
expire_in: 3 days如果不希望继承, 可以这么写:
build-job:
extends: .build-app
# 用 null 覆盖掉继承的值
artifacts: {} 当使用 needs 字段建立 Job 之间的依赖关系时, 会自动下载所依赖的 Job 之前上传的 Artifacts.
如果不使用 needs 字段, 那么 Job 就会下载前面所有 Stage 中所有 Job 上传的 Artifacts.
有些时候这不是预期行为: 例如我们只打算确立先后顺序, 根本不需要用到前面上传的 Artifacts.
为此, 可以使用 dependencies 字段来声明 "使用哪些 Artifacts":
test-job:
script:
- echo "test passed"
artifacts:
paths:
- $LOG_PATH/log.txt
build-job:
script:
- echo "build"
# 当使用 needs 字段时, 默认下载列在这里的 job 的 artifacts.
# 若不需要使用这些 artifacts, 就需要注明 "artifacts: false".
needs:
- job: test-job
artifacts: falsetest-job:
stage: test
script:
- echo "test passed"
artifacts:
paths:
- $LOG_PATH/log.txt
build-job:
stage: build
script:
- echo "build"
# 当不使用 needs 时, 会默认下载前面的 stage 所有 job 的 artifacts.
# 若不需要使用这些 artifacts, 就需要借助 "dependencies" 字段.
dependencies: []WARNING
默认情况下, artifacts 是公开的, 可以被当前代码仓库的所有成员访问 (甚至 Guest 角色也可以访问).
如果 artifacts 中包含敏感数据 (例如密码), 则会带来安全风险. 解决方案是:
# 让单个 job 的 artifacts 不公开.
my-job:
script:
- xxx
artifacts:
public: false
# 也可以让整个 pipeline 的 artifacts 默认不公开.
default:
artifacts:
public: false然而以上方式实测有点问题 (gitlab-ee-v16.8.1):
artifacts:public 在编写时会报错 (应该是因为官方 schema 没有更新).
default:artifacts:public 不起作用, 只有 job 中的相关字段能起效.
Cache
当后续的 Job 依赖于之前的 Job 所生成的文件时, 我们有两个选择:
可以使用 Artifacts 并通过 needs 字段来建立依赖关系, 也可以使用 Cache.
什么情况下应该使用 Cache (而不是 Artifacts):
不希望将生成的文件上传 GitLab, 只需要保存在运行 gitlab-runner 的设备中.
upload-ios-app:
script:
- echo "uploading iOS App"
cache:
- key: xcode-cache
paths:
- $XCODE_PROJECT_PATH
- $IOS_ARCHIVE_PATH
policy: pullWARNING
cache 可能会影响下一次 Pipeline, 因此需要好好指定 policy.
建议将执行顺序 靠前 的 Job 的 cache policy 设置为 push, 以避免被更早的 Pipeline 的 cache 干扰.
policy 的值包括: pull, push, pull-push (默认值).
如果在容器中执行 pipeline 时 (也就是 GitLab Runner 的 Executor 类型 为 Docker 时),
缓存文件位于自动创建的 Docker Volume 中, 可以通过 Docker Desktop 查看.

容器相关
筛选 Runner
INFO
GitLab Runner 的标签设置详见 持续集成与发布 CI/CD - 网页配置.
我们可以通过 tags 字段来筛选用于执行此 Job 的 gitlab-runner.tags 字段可以写在 default 中, 也可以位于 Job 内部.
# 在 default 中指定 tag,
# 默认情况下将会被所有 job 继承.
default:
tags:
- windows
- dockermy-job:
script: echo "my-job"
# 为 job 单独设置 tag.
tags:
- macos
# 放弃继承 default.
inherit:
default: false如果经过 Job 标签筛选后发现没有可以用的 runner, 则会出现下图中的警告.

常用字段
build-job:
# 失败则重试, 最多重试两次
retry: 2
# 如果超过 1.5 小时, 则被认为失败
timeout: 1 h 30 m
# 执行失败后不会终止 Pieline
allow_failure: trueEnvironment
Environment 用于自动化部署.
在 Job 中描述
deploy_review:
stage: deploy
script:
- echo "Add script here that deploys the code to your infrastructure"
environment:
# 名字以 "review/" 开头的 environment 有特殊作用.
name: review/$CI_COMMIT_REF_NAME
# 在 Operate / Environments 网页中点击 Open 按钮即可打开链接.
# CI_ENVIRONMENT_SLUG 变量只能在 review 类型的 environment 中使用.
url: https://$CI_ENVIRONMENT_SLUG.example.com
# 多久之后将此 environment 标记为 stop.
# 取值举例 168 hours, 7 days, one week, never.
auto_stop_in: 1 day
# 当被标记为 stop 状态时, 将会执行的操作.
on_stop: stop_review # 值为其他 Job 的名称
stop_review:
stage: deploy
script:
- echo "Add script here to stop and cleanup"
# 避免此 Job 自动执行.
when: manual
needs:
- job: deploy_review
environment:
# 应当与 "被停止的 Job" 同名
name: review/$CI_COMMIT_REF_NAME
# action 的值必须为 stop, 这样才能被 on_stop 引用.
action: stop在网页中查看
在代码仓库的侧边栏点击 Operate / Environments 菜单, 可以进入 Environments 主页.
点击任意 environment 右上角的 Open 按钮, 即可打开在 Job 中声明的 url.
如果点击右上角的 Stop 按钮, 则会标记为 Stop, 并调用 on_stop 字段中所引用的 Job.

另外, 如果想要触发用于停止的 Job, 也可以在 Pipeline 页面中操作.
注意到下图中用于手动触发 Job 的按钮的样式为 "停止", 这与其他需要手动触发的 Job 不同.

如果有处于激活状态 (Active) 的 environment, 那么在代码仓库的主页就能直接看到.

Merge Request
在 merge request 中也可以看到相关的 environment, 并且能打开链接或停止.

如果希望在 merge request 被合并时, 自动停止相关的 environment, 可以这么做:
deploy_review:
stage: deploy
script:
- echo "Deploy a review app"
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://$CI_ENVIRONMENT_SLUG.example.com
on_stop: stop_review
rules:
# 在 merge request 中执行 #
- if: $CI_MERGE_REQUEST_ID
# 在通过网页发起的 pipeline 中执行 #
- if: $CI_PIPELINE_SOURCE == "web"
stop_review:
stage: deploy
script:
- echo "Remove review app"
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
rules:
- if: $CI_MERGE_REQUEST_ID
when: manual
- if: $CI_PIPELINE_SOURCE == "web"
when: manual