〇、前言
.gitlab-ci.yml 文件主要用于项目的自动化部署配置,自动化可以大大提升团队效率,但同时这个文件的内容也比较复杂,弄清楚也并非易事,本文将对此文件的内容进行简单介绍,供参考。
另外,.gitlab-ci.yml 文件一般存放在项目的根目录中,可以参考以往项目的配置文件来理解。
关于 CI/CD 的概念可参考博主过往文章:https://www.cnblogs.com/hnzhengfy/p/18806480/CI_CD1。
一、.gitlab-ci.yml 可以做什么
1.1 简介
.gitlab-ci.yml 是 GitLab 中用于定义持续集成(CI)和持续交付/部署(CD)流程的配置文件。
它告诉 GitLab Runner 如何执行自动化任务,例如构建代码、运行测试、打包应用程序以及将应用程序部署到生产环境。
通过统一的自动化的流程,减少手动操作,从而避免诸多的人为错误;还可以快速发现和修复问题(例如通过自动化测试);也可以实现持续交付和持续部署,缩短从代码提交到上线的时间。
.gitlab-ci.yml 还可以与代码一起存入版本控制系统(如 Git),便于跟踪配置变更。
1.2 关于 Pipelines(管道)
Popelines 代表了一系列用于构建、测试和部署代码的任务或步骤的集合 。这些任务按照预定的顺序执行,以确保软件的质量和稳定性,并且能够高效地将新功能或修复推送到生产环境中。
配置文件完成后,就可以触发 CI,启动 Pipelines,成功的状态为 passed,失败为 failed,如下图。
每个 Pipeline 通常由多个 Job 组成,这些 Job 根据 stages 配置,同一阶段默认并行执行,不同阶段串行执行。

1.3 Job:一个基本执行单元
Job 是 CI/CD 流程中的基本执行单元,代表了一个独立的任务或操作。
每个 Job 通常负责完成某一特定的工作,例如编译代码、运行测试、打包应用程序或部署到生产环境。
在 .gitlab-ci.yml 文件中,Job 是通过 YAML 格式定义的。每个 Job 都有一个唯一的名称,并包含一组配置选项来描述它的行为。
点击 Pipelines 可以查看 Job 详情,如下图。

每个 Job 包含多个配置选项,如 stage、script、artifacts、cache 等,后文将详细介绍。
1.4 Runners
Runners 是执行 CI/CD 任务的核心组件。它们是实际运行 .gitlab-ci.yml 中定义的 Jobs 的代理或服务。
Runners 是需要单独安装注册的 ,教程可以参考:https://juejin.cn/post/6963927908444274718。
Runners 是执行 CI/CD 任务的一个独立的核心组件。它负责从 GitLab 接收指令并执行 Pipeline 中定义的任务(Jobs)。每个 Runner 可以被分配到一个或多个项目,并根据需要执行不同的 Jobs。
Runners 的主要类型有:
Shared Runners: 由 GitLab.com 提供,所有用户都可以使用,适合小型项目或不需要定制化环境的项目,特点是资源共享,但可能会导致排队等待。
**Group Runners:**可以被分配给某个 GitLab Group 下的所有项目。它提供了一种在组内共享资源的方式,同时保持一定程度的隔离。
Specific Runners: 专为特定项目配置的 Runner。它提供了最大的灵活性和控制力,允许针对项目的特殊需求进行定制。适用于需要特定环境或高安全性的场景。
当一个项目的代码发生变化(如提交、合并请求等),GitLab 会根据 .gitlab-ci.yml 文件创建一个新的 Pipeline。Pipeline 包含多个阶段(stages),每个阶段包含一个或多个 Jobs。GitLab 将这些 Jobs 分配给可用的 Runner 来执行。
执行的流程大概为:
**注册 Runner:**首先需要将 Runner 注册到 GitLab 实例上,这样它才能接收到来自 GitLab 的任务。
**获取任务:**一旦有新的 Pipeline 触发,GitLab 会将相应的 Jobs 分配给符合条件的 Runner。
**执行脚本:**Runner 执行 .gitlab-ci.yml 中定义的 script 命令。
**报告结果:**完成 Job 后,Runner 会将结果(成功或失败)以及任何生成的产物(artifacts)返回给 GitLab。
二、示例配置
一个简单的示例配置,可以大概浏览下有哪些配置节点,结合后文继续理解。
include:
- remote: "http://www.baidu.com/data/prod.yml"
variables:
- buildImage: "http://hub.com/nginx"
workflow:
rules:
- if: '$CI-PIPELINE_SOURCE' == "push"'
when: never
- when: always
stages:
- build
- nextStep
- testStep1
build-job:
stage: build
script:
- echo "Hello, $GITLAB_USER_LOGIN!"
test-job1:
stage: nextStep
script:
- echo "This job tests something"
test-job2:
stage: nextStep
script:
- echo "This job tests something, but takes more time than test-job1."
- echo "After the echo commands complete, it runs the sleep command for 20 seconds"
deploy-prod:
stage: testStep1
script:
- echo "This job deploys something from the $CI_COMMIT_BRANCH branch."
这份文件包含了四个可执行的 Jobs,通过 stages 定义执行的顺序,test-job1、test-job2 的 stage 名字相同都是 nextStep,此时这两个任务将并列执行。

三、全局关键字
.gitlab-ci.yml 可以分为几个层级,首先最外层的变量包括四个,如下:
|-----------|---------------------|------------------------------------|---------------------------------------------------------------------------|
| 关键字 | 释义 | 值例举 | 说明 |
| stages | 阶段,类型数组 | 分别为自定义的 jobs | 规定各个任务的执行顺序,任务名称相同,则同时执行 |
| include | 引用的 yml 或 yaml 配置文件 | key: 包括,local、remote、file、template | local 一般是本地文件,remote 可以是远程其他可访问的地址,filter 一般是其他项目下的文件路径,template 是官方提供的模版 |
| variables | 变量 | 预定义或自定义 | 根据变量位置不同,优先级不样,相同的变量会根据优先级进行覆盖 |
| workflow | 工作流 | rules | 用来定义 CI/CD 何时触发,和 jobs 中的 rules、only 相似 |
3.1 stages 阶段(每个阶段可包含多个 Job)
stages 用于定义 CI/CD Pipeline 的执行阶段顺序。
每个阶段(stage)包含一组任务(Jobs,并行或串行),并且这些任务会按照 stages 中定义的顺序依次执行。
各个阶段是控制依赖关系(串行),即前一个阶段的所有 Jobs 必须成功完成后,才会进入下一个阶段。如果某个阶段中的某个 Job 失败,后续阶段通常不会执行(除非配置了允许失败)。如果某个阶段没有定义任何 Jobs,则该阶段会被跳过。
如果没有显式定义 stages,GitLab 会使用默认的三个阶段:build-构建代码或准备环境;test-运行测试;deploy-部署到目标环境。
在一个阶段中,所有 Jobs 默认是并行执行的。例如:
stages:
- test
unit_tests:
stage: test
script:
- echo "Running unit tests..."
integration_tests:
stage: test
script:
- echo "Running integration tests..."
在这个例子中,unit_tests 和 integration_tests 会同时运行。
在一个阶段中,也可以通过 needs 配置来实现串行执行,从而强制某些 Jobs 按顺序执行,即使它们属于同一个 stage。例如:
stages:
- build
job1:
stage: build
script:
- echo "Running job1..."
- sleep 5
tags:
- shared
job2:
stage: build
script:
- echo "Running job2 after job1..."
needs:
- job1
在 job2 中添加了 needs: -job1 配置,意思就是在执行 job2 之前,需要等 job1 先执行完成。
常见的阶段列举:
|----------|---------------------------|
| 阶段名称 | 描述 |
| prepare | 准备工作,如安装依赖、设置环境变量等 |
| build | 构建代码或生成构建产物,如编译代码、打包应用程序等 |
| test | 运行单元测试、集成测试、端到端测试等 |
| deploy | 将应用程序部署到目标环境,如测试、生产环境等 |
| release | 发布版本,例如生成发布包、推送镜像到容器仓库等 |
| cleanup | 清理临时文件、释放资源等 |
配置的注意事项:
为每个阶段分配明确的任务,避免混杂。例如:build 阶段只负责构建;test 阶段只负责测试;deploy 阶段只负责部署。
根据项目需求定义清晰的阶段名称,例如 prepare、package、publish 等。
过多的阶段可能导致 Pipeline 变得复杂且难以维护,要根据实际需求合理划分阶段。
如果某些阶段的失败不影响整体流程,可以通过 allow_failure: true 来允许失败。
optional_stage:
stage: optional
script:
- echo "This stage can fail without affecting the pipeline."
allow_failure: true
3.2 include 引入外部配置文件
3.2.1 简介
include 配置,用于将外部的配置文件引入 到当前的 CI/CD 配置中。可以实现配置的模块化和复用,从而简化复杂的管道配置文件。
即:拆分复杂的配置文件;在多个项目中共享通用的 CI/CD 配置;维护更加清晰和模块化的管道定义。
include 等基本类型:
include:
# 1)引入本地文件
# 路径是相对于项目根目录
- local: path/to/file.yml
# 2)引入外部 URL 提供的配置文件
# 文件必须可通过 HTTP 或 HTTPS 访问,并且支持 CORS(Cross-Origin Resource Sharing:跨源资源共享)
- remote: https://example.com/config.yml
# 3)使用 GitLab 提供的内置模板(如 Auto DevOps)
# 内置模板可以直接使用,无需额外配置
- template: Auto-DevOps.gitlab-ci.yml
# 4)引入其他项目的文件
# 需要指定项目路径(project)和文件路径(file)
- project: 'group/project'
file: '/path/to/file.yml'
当使用 include 引入外部文件时,GitLab 会将所有文件的内容合并为一个完整的 .gitlab-ci.yml 文件。
注意事项:
- **访问权限:**如果使用 project 类型引用其他项目的文件,需要确保当前项目有权限访问目标项目。如果使用 remote 类型,目标文件必须公开或有适当的访问权限。
- **不允许存在循环依赖:**例如 A 包含 B,B 又包含 A。
- **合理拆分文件:**单个大文件和过多的 include 都会增加 Pipeline 配置加载的时间。
- **提前验证配置内容:**使用 GitLab 的 CI Lint 工具可以验证最终合并的配置是否正确。
通过灵活运用 include,可以构建出高效且可扩展的 CI/CD 流程。
3.2.2 合并规则
如果有重复的键值对,后定义的内容会覆盖先定义的内容(后来居上)。
所有的 stages、jobs 和全局变量都会被合并。如果某个 Job 定义了相同的名称,则后定义的 Job 会覆盖前一个(后来居上)。
- stages 的合并规则
**主文件优先:**如果主 .gitlab-ci.yml 文件中定义了 stages,那么它会完全覆盖外部文件中的 stages 定义。
**外部文件补充:**如果主文件中没有定义 stages,则会使用外部文件中的 stages。
例如:
# 主文件
include:
- local: included.yml
stages:
- build
- test
# 外部文件:included.yml
stages:
- deploy
# 最终合并结果
stages:
- build
- test
# 即:主文件中的 stages 完全覆盖了外部文件中的 stages
- jobs 的合并规则
**不冲突时合并:**如果主文件和外部文件中的 jobs 名称不同,则它们会被合并到最终的配置中。
**冲突时主文件优先:**如果主文件和外部文件中有同名的 job,则主文件中的定义会完全覆盖外部文件中的定义。
# 主文件:.gitlab-ci.yml
include:
- local: included.yml
build_job:
script:
- echo "Building from main file"
# 外部文件:included.yml
build_job:
script:
- echo "Building from included file"
test_job:
script:
- echo "Testing from included file"
# 合并结果:
build_job:
script:
- echo "Building from main file"
test_job:
script:
- echo "Testing from included file"
# build_job 被主文件覆盖
# test_job 被保留,因为它没有冲突
- 全局变量的合并规则
**主文件优先:**如果主文件和外部文件中都定义了相同的全局变量,则主文件中的值会覆盖外部文件中的值。
**非冲突变量合并:**如果主文件和外部文件中的变量名称不同,则它们会被合并。
3.2.3 include 实现配置文件的动态包含
通过结合 rules 或 only/except,可以根据条件动态地引入不同的配置文件。
当一个管道触发时,GitLab 会根据当前的环境变量(如 $CI_COMMIT_BRANCH)评估 rules 条件。只有满足条件的 include 块会被执行,对应的外部文件内容会被加载并合并到主配置中。
例如:
include:
- local: .gitlab/ci/build-dev.yml
rules:
- if: '$CI_COMMIT_BRANCH == "dev"' # 如果当前提交的分支是 dev,则加载 .gitlab/ci/build-dev.yml 文件
- local: .gitlab/ci/build-prod.yml
rules:
- if: '$CI_COMMIT_BRANCH == "main"' # 如果当前提交的分支是 main,则加载 .gitlab/ci/build-prod.yml 文件
3.2.4 include 允许嵌套包含
外部文件本身也可以包含其他文件,从而实现嵌套的模块化配置。
例如:
# 主文件
include:
- local: .gitlab/ci/main-config.yml
# 外部文件:.gitlab/ci/main-config.yml
include:
- local: .gitlab/ci/build.yml
- local: .gitlab/ci/test.yml
3.2.5 include 可以结合锚点(&)和别名(*)
结合 YAML 的锚点和别名,可以在多个地方复用相同的配置。
例如:
# 主文件
include:
- local: .gitlab/ci/common.yml
# 外部文件:.gitlab/ci/common.yml
.common-template: &common-template # 定义了一个 YAML 锚点 .common-template,它包含了通用的配置(如 image 和 before_script)
image: alpine
before_script:
- echo "Preparing environment..."
build_job:
<<: *common-template # 使用 <<: *common-template 将锚点的内容合并到 build_job 中,并添加特定的任务脚本(如 script)
script:
- echo "Building the application..."
# 最终合并结果
# 合并后的完整配置
image: alpine
before_script:
- echo "Preparing environment..."
build_job:
image: alpine
before_script:
- echo "Preparing environment..."
script:
- echo "Building the application..."
3.3 Variables(变量)
3.3.1 简介
Variables 用于存储配置信息、敏感数据或任何需要动态改变的值,并且可以在 .gitlab-ci.yml 文件、Pipeline Jobs 的脚本中使用。合理地使用变量可以提高 Pipeline 的灵活性和安全性。
主要作用为:
**配置管理:**通过变量来配置不同的环境(如开发、测试、生产),使得同一套 CI/CD 配置能够适应多种环境。
**动态流程控制:**通过变量控制任务的行为(如分支名称、环境类型)。
**安全性:**保护敏感信息(例如 API 密钥、数据库密码等),避免直接硬编码到脚本或配置文件中。
**灵活性:**允许根据不同的条件动态调整 Pipeline 行为,例如分支名称、标签等。
3.3.2 Variables 有哪些类型
- 预定义变量
.gitlab-ci.yml 自动提供了一些预定义的环境变量,这些变量包含了关于当前项目、提交、分支、标签等信息。如下是常用的预定义变量列举:
# 当前触发流水线的【分支或标签名称】,示例:在 main 分支触发的流水线中,该值为 main
CI_COMMIT_REF_NAME
# 【当前提交(commit)的完整 SHA 值】,常用于构建 Docker 镜像或其他需要唯一标识符的场景
CI_COMMIT_SHA
# 当前触发流水线的【分支名称】,用于基于分支的条件逻辑判断。注意:对于由标签触发的流水线,此变量为空
CI_COMMIT_BRANCH
# 【当前流水线的唯一 ID】,可用于追踪特定流水线实例
CI_PIPELINE_ID
# 【当前任务(job)的唯一 ID】,可用于日志记录或调试
CI_JOB_ID
# 【项目根目录路径】,用于指定文件路径或工作目录
CI_PROJECT_DIR
# 【项目名称】,可用于生成报告、文档等
CI_PROJECT_NAME
# 项目【主页的 URL 地址】,可用于发送通知或链接到项目主页
CI_PROJECT_URL
# 默认情况下,这是【GitLab 容器注册表的基础地址】,结合项目路径和名称构成完整的镜像名,通常与 CI_COMMIT_SHA 结合使用来标记 Docker 镜像
CI_REGISTRY_IMAGE
# 如果流水线是由一个标签(tag)触发,则此变量包含该【标签的名字】否则为空,用于版本发布流程中
CI_COMMIT_TAG
# 【执行当前任务的 Runner 的 ID】,有助于了解哪个 Runner 执行了任务
CI_RUNNER_ID
# 提供服务的 GitLab 实例名称,可用于区分不同的 GitLab 实例,
CI_SERVER_NAME
# 【临时的 API 令牌】,允许任务访问 GitLab API 资源,可用于自动化脚本调用 GitLab API
CI_JOB_TOKEN
# 当前【部署环境的名称】,在多环境部署策略中很有用
CI_ENVIRONMENT_NAME
# 【部署密码】,当启用保护变量时可用,用于安全地存储和传递敏感信息如密码
CI_DEPLOY_PASSWORD
- 自定义变量
用户自己可以在 .gitlab-ci.yml 文件中或者通过 GitLab UI 添加自定义变量。自定义变量可以分为两类:全局变量(适用于整个 Pipeline 中的所有 Jobs)、Job 特定变量(仅适用于某个具体的 Job)。
variables: # 全局变量
ENV: "production"
DB_HOST: "db.example.com"
build_job1:
script:
- echo "Deploying to $ENV"
- echo "Connecting to $DB_HOST"
build_job2:
variables: # 局部变量
BUILD_TYPE: "debug"
script:
- echo "Building with type $BUILD_TYPE"

Runner 配置变量:在 GitLab Runner 的配置文件中定义(如 config.toml),作用于特定 Runner。
[[runners]]
environment = ["CUSTOM_VAR=value"]
- 保护变量
对于包含敏感信息的变量(如密码、API密钥),可以将其设置为"保护"状态。这意味着该变量只能被用于受保护的分支或标签上的 Pipelines。
3.3.3 变量的优先级
当多个来源的变量发生冲突时,GitLab 会根据以下优先级决定最终值**(从高到低)**:
- Job 任务级别的变量(局部变量)
- GitLab UI 配置的变量
- 全局变量(.gitlab-ci.yml 文件中定义的 variables)
- Runner 配置的变量
- 系统预定义变量
3.3.4 应用场景
-
通过变量控制任务的执行逻辑
deploy_job:
script:
- if [ "$DEPLOY_ENV" == "production" ]; then
echo "Deploying to production";
else
echo "Deploying to staging";
fi -
将敏感信息存储为变量,避免直接暴露在代码中
deploy_job:
script:
- echo "Using API key: $API_KEY"
可以在 GitLab UI 中定义 API_KEY,并将其标记为"屏蔽",防止日志泄露。
- 跨任务共享数据
通过 artifacts:reports 或 artifacts 将变量传递给后续任务。
build_job:
script:
- echo "BUILD_VERSION=1.0.0" > build.env
artifacts:
reports:
dotenv: build.env
deploy_job:
script:
- echo "Deploying version $BUILD_VERSION"
- 控制触发条件
结合 rules 或 only/except 使用变量控制任务的触发
deploy_job:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
script:
- echo "Deploying to main branch"
-
设置默认值
script:
- echo "${ENV:-staging}" # 如果 ENV 未定义,则使用 "staging" -
变量之间支持多层嵌套
variables:
BASE_URL: "https://example.com"
API_URL: "${BASE_URL}/api" -
多行变量
对于较长的变量值,可以使用 YAML 的多行语法。
variables:
LONG_TEXT: |
This is a multi-line variable.
It can span multiple lines.
3.4 workflow
3.4.1 简介
workflow 用于定义管道的触发规则,决定了管道是否应该被创建。
然后根据分支、标签、事件类型等条件动态调整管道的行为,配合 rules 或 only/except 使用,提供更细粒度的控制。
workflow 定义在 .gitlab-ci.yml 文件的顶层,与 stages 和 jobs 并列。
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
3.4.2 配置项:rules
rules 是 GitLab CI/CD 推荐的条件控制机制,用于决定管道是否应该被创建。
以下是 rules 的关键字:
**if:**基于条件表达式判断是否创建管道。
**when:**指定管道的行为:
always:总是创建管道。
on_success:仅当之前的任务成功时创建。
on_failure:仅当之前的任务失败时创建。
manual:手动触发管道。
never:不创建管道。
**changes:**根据文件变更路径判断是否创建管道。
**exists:**根据文件是否存在判断是否创建管道。
3.4.3 配置项:only/except 这两个都是旧语法
only 和 except 是早期版本的 GitLab 提供的条件控制机制,虽然仍然支持,但推荐使用 rules 替代。
only: 指定管道仅在某些条件下创建。
except: 指定管道在某些条件下不创建。
workflow:
only: # 管道仅在 main 分支或合并请求事件 merge_requests 时创建
- main
- merge_requests
except: # 不在计划管道(schedules)中创建
- schedules
3.4.4 workflow 的典型用法
- 按分支触发管道
只在特定分支上创建流水线。
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "main"' # 如果分支是 main,则始终创建管道
when: always
- if: '$CI_COMMIT_BRANCH =~ /^feature\//' # 如果分支以 feature/ 开头,则需要手动触发管道
when: manual
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # 如果是合并请求事件,则 manual 需要手动触发管道
when: manual
- when: never # 其他分支不创建管道
- 按事件类型触发管道
根据管道来源(如推送、合并请求、计划流水线)控制。
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "push"' # 如果是代码推送事件,则始终创建管道
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # 如果是合并请求事件,则需要手动触发管道
when: manual
- if: '$CI_PIPELINE_SOURCE == "schedule"' # 如果是计划管道,则不创建管道
when: never
- 按文件变更触发管道
根据文件变更路径决定是否创建流水线。
workflow:
rules: # 如果在 main 分支上修改了 src 目录下的文件,则创建管道
- if: '$CI_COMMIT_REF_NAME == "main" && $CI_COMMIT_CHANGED_FILES =~ /src/'
when: always
- when: never # 其他情况不创建管道
按时间触发管道
结合计划流水线(Schedules)使用。
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"' # 如果是计划管道,则始终创建管道
when: always
- when: never # 其他情况不创建管道
3.4.5 workflow 优先级
workflow 的规则会覆盖任务级别的 rules 或 only/except。如果 workflow 规则阻止了管道的创建,则所有任务都不会运行。
workflow:
rules: # 如果分支不是 main,则不会创建管道,即使 build_job 存在也不会运行
- if: '$CI_COMMIT_BRANCH != "main"'
when: never
build_job:
script:
- echo "Building..."
四、Jobs 相关的关键字
4.1 script:定义任务执行的具体命令
每个任务必须包含 script,且可以执行多个命令行。
# 语法:
job_name:
script:
- command1
- command2
# 示例:
build_job:
script:
- echo "Building the project..."
- npm install
- npm run build
4.2 before_script / after_script:在 Job开始之前/之后执行的脚本
可以是全局配置,也可以局部配置。
# 语法:
before_script:
- apt-get update
job_name:
before_script:
- echo "Overriding global before_script"
# 示例:
before_script: # 全局 before_script 配置,会应用到全部的任务中,除非在任务中重新配置过
- echo "Global setup"
build_job:
before_script: # 局部的 before_script,会覆盖全局配置 before_script
- echo "Local setup"
script: echo "Building..."
# 如果希望全局配置 before_script 保留,则需要用到 extends 关键字:
.before_template:
before_script:
- echo "Global setup"
build_job:
extends: .before_template # extends 引入全局的 before_template 配置
before_script:
- echo "Local setup"
script:
- echo "Building..."
4.3 stage:指定任务所属的阶段
stage 的内容需要与全局的 stages 中内容对应。
# 语法
job_name:
stage: stage_name
# 示例
stages: # 全局 stages 配置
- build
- test
- deploy
build_job:
stage: build
script: echo "Building"
4.4 image:指定任务运行的 Docker 镜像
# 语法
job_name:
image: image_name[:tag]
# 示例
build_job:
image: node:18
script: npm install && npm run build
4.5 tags:指定任务运行的 Runner 标签,确保任务由特定 Runner 执行
# 语法
job_name:
tags:
- tag1
- tag2
# 示例
deploy_job:
tags:
- production
- docker
script: echo "Deploying to prod"
4.6 rules:定义任务是否运行的条件规则(推荐使用,来替代 only/except)
# 语法:
job_name:
rules:
- if: <条件表达式>
when: <执行时机> # 执行时机枚举:always(总是), on_success(成功时), on_failure(失败时), manual(手动触发), never(从不)
[changes: <文件路径>]
# 示例
test_job:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
- when: never
# only:指定管道仅在某些条件下创建
# except:指定管道在某些条件下不创建
# 语法
job_name:
only:
- branches # 分支
- tags # 标签
- pipelines # 流水线类型
# 示例
build_job:
only:
- main
- /^feature-.*/ # 正则匹配分支
4.7 variables:定义任务的环境变量
# 语法
job_name:
variables:
VAR_NAME: "value"
# 示例
test_job:
variables:
DB_HOST: "localhost"
DB_PORT: "5432"
script: echo "Connecting to $DB_HOST:$DB_PORT"
4.8 cache:定义任务的缓存路径,加速后续任务
cache 是 GitLab CI/CD 中优化流水线性能的重要工具,尤其适用于频繁安装依赖的任务。
通过合理使用 paths 和 key,可以有效减少重复操作,提高构建和测试的速度。
同时,需要注意缓存的作用范围和清理策略,确保流水线的稳定性和可靠性。
# 语法
job_name:
cache:
paths:
- path/to/cache/
key: $CI_COMMIT_REF_SLUG # 缓存键
# 示例
stages:
- build
build_job:
stage: build
cache: # 缓存 Node.js 依赖,到 node_modules 目录,避免每次运行时都重新安装依赖
key: "$CI_COMMIT_REF_SLUG"
paths:
- node_modules/
script:
- npm install
- npm run build
# 示例:多个缓存条目
job_name:
cache:
- key: "npm-cache"
paths:
- node_modules/
- key: "gradle-cache"
paths:
- .gradle/
# 示例:动态缓存键
# 通过环境变量动态生成缓存键,避免不同分支或任务之间的缓存冲突
stages:
- deploy
deploy_job:
stage: deploy
cache: # 根据分支名称生成不同的缓存键,避免不同分支之间的缓存冲突
key: "cache-$CI_COMMIT_REF_SLUG"
paths:
- dist/
script:
- echo "Deploying..."
# $CI_COMMIT_REF_SLUG 是 GitLab 提供的预定义变量,表示分支或标签名称的规范化版本
GitLab CI/CD 不会自动清理旧的缓存,但可以通过以下两种方式手动清理:
- 在项目的 Settings > CI/CD > Cache 页面中删除缓存。
- 修改 key 的值以强制生成新的缓存。
缓存的作用域:
** 跨任务共享:** 如果多个任务使用相同的 key,它们将共享同一个缓存。
** 跨管道共享** :缓存不仅限于当前管道,还可以在后续管道中复用。
** Runner 级别隔离:**缓存存储在 Runner 上,因此只有使用相同 Runner 的任务才能访问缓存。
注意,Cache 和 Artifacts 的区别:
Cache:用于在任务之间共享文件 ,适合存储依赖项或其他临时文件。
Artifacts:用于保存任务的输出结果,可供后续任务或用户下载。
cache 缓存可能会丢失(例如,当 Runner 清理磁盘空间时),因此,不要将关键数据仅依赖于缓存,确保任务能够重新生成所需文件。
GitLab 默认保留最近 7 天的缓存。如果缓存占用过多空间,可以手动清理或调整 key 强制生成新缓存。
如果项目使用了多个 Runner ,建议使用共享存储(如 S3)来存储缓存,以确保一致性。
4.9 artifacts:定义任务的输出结果
用于定义任务的输出结果(如文件、目录等),并使其可供后续任务使用或供用户下载。
与 cache 不同,artifacts 主要用于保存任务的构建产物,而不是依赖项。
# 语法
job_name:
artifacts:
paths: # 指定需要保存的文件或目录路径
- path/to/artifact
expire_in: 1 week # 定义过期时间,缺省默认为 30 天
untracked: true # 是否包含未被 Git 跟踪的文件(即未提交到仓库的文件),缺省默认为 false
# 示例:保存构建产物
stages:
- build
build_job:
stage: build
script:
- mkdir dist
- echo "Build output" > dist/output.txt
artifacts:
paths:
- dist/
expire_in: 1 week
# 示例:传递测试报告
# 将 JUnit 测试报告上传到 GitLab,管道页面会显示测试结果
stages:
- test
test_job:
stage: test
script:
- mvn test
artifacts:
reports:
junit: target/surefire-reports/TEST-*.xml
# 示例:根据根据分支名称生成不同的保存路径
stages:
- deploy
deploy_job:
stage: deploy
script:
- mkdir -p "build/$CI_COMMIT_REF_SLUG"
- echo "Deployed to $CI_COMMIT_REF_SLUG" > "build/$CI_COMMIT_REF_SLUG/output.txt"
artifacts:
paths:
- "build/$CI_COMMIT_REF_SLUG/"
GitLab 对制品大小有限制,具体取决于实例配置(通常为 1GB 或更高)。如果制品过大,可以考虑压缩后再上传。
制品会在 expire_in 时间后自动删除。如果需要永久保存某些制品,可以手动调整过期时间或将其存储到外部系统(如 S3)。
如果项目使用了多个 Runner,确保 Runner 有权限上传和下载制品。
4.10 allow_failure:允许任务失败而不影响整体流水线
用于控制任务失败时是否会影响管道的整体状态。
默认情况下,如果某个任务失败,整个管道会被标记为失败。而通过设置 allow_failure: true
,即使该任务失败,流水线仍然可以继续运行。
# 语法
job_name:
allow_failure: true
# 示例
unstable_test:
allow_failure: true
script: ./run-unstable-tests.sh
如果 allow_failure: true 的任务失败,管道的状态不会被标记为失败,但仍会显示为"部分成功"或"有警告"。如果所有任务都成功,则管道状态为"成功"。
有哪些使用场景:
- 非关键任务,例如实验性功能的测试、非核心部署等。
- 手动触发任务,允许用户手动触发的任务失败不影响整体流程。
- 延迟任务,某些延迟任务即使失败也不影响主要流程。
4.11 when:控制任务的执行时机
when 需结合 rules 或 trigger 使用。
常用的值:
on_success:描述:任务仅在所有前置任务成功完成时运行(默认行为)。
on_failure:任务仅在至少一个前置任务失败时运行。通常用于清理环境或发送通知。
always:无论前置任务是否成功或失败,任务都会运行。通常用于生成报告或记录日志。
manual:任务需要手动触发,不会自动运行。适用于需要人工干预的任务,例如部署到生产环境。
delayed:任务会在指定的时间延迟后运行。适用于定时任务或延迟触发的场景(需配合 start_in)。
# 基本用法
job_name:
script:
- echo "Running job"
when: on_success # 默认值,任务仅在所有前置任务成功完成时运行
# 示例:结合 rules 使用,实现更复杂的逻辑
deploy_job:
script:
- echo "Deploying..."
rules: # 如果分支是 main,则任务需要手动触发;否则不运行
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
- when: never
# 示例:通过环境变量动态调整 when 的值
deploy_job:
script:
- echo "Deploying..."
when: $DEPLOY_WHEN # 根据 $DEPLOY_WHEN 的值决定任务的执行时机
# 示例:清理任务
stages:
- build
- cleanup
build_job:
stage: build
script:
- echo "Building..."
when: on_success
cleanup_job:
stage: cleanup
script:
- echo "Cleaning up..."
when: on_failure # 如果构建失败,则运行清理任务
# 示例:部署任务需要手动触发
stages:
- deploy
deploy_job:
stage: deploy
script:
- echo "Deploying to production..."
when: manual
# 示例:延迟任务
stages:
- notify
notify_job:
stage: notify
script:
- echo "Sending notification..."
when: delayed # 通知任务会在 10 分钟后运行
start_in: "10 minutes"
注意:手动任务不会影响流水线的整体状态,即使未触发也不会导致流水线失败。
when: delayed 的限制 start_in 的最小延迟时间为 1 分钟。如果流水线被取消或超时,延迟任务不会运行。
4.12 extends:继承其他任务或模板的配置
extends 用于实现任务配置的复用和继承。
通过 extends,可以将通用的配置提取到一个模板中,避免重复定义,提高配置文件的可维护性和可读性。
# 语法
.base_template:
script:
- echo "Base script"
job1:
extends: .base_template
script:
- echo "Extended script"
# 示例:允许多层嵌套
.base-template:
image: alpine
.common-template:
extends: .base-template
before_script:
- echo "Preparing environment..."
build_job:
extends: .common-template
script:
- echo "Building the application..."
# 示例:合并配置
# 当任务继承模板时,GitLab 会合并模板和任务的配置。如果存在冲突,任务中的配置优先于模板中的配置
.common-template: &common-template
image: alpine
variables:
ENV: "production"
build_job:
extends: .common-template
variables:
ENV: "development" # 覆盖模板中的变量
script:
- echo "Building with $ENV"
# 示例:继承多个模板
.base-image:
image: alpine
.base-script:
before_script:
- echo "Preparing environment..."
build_job:
extends:
- .base-image
- .base-script
script:
- echo "Building the application..."
模板名称通常以 . 开头(如 .common-template),表示它是一个隐藏的任务,不会被实际执行。
如果模板和任务中有同名的配置项,任务中的配置优先级更高。
extends 只能在同一个文件中使用。如果需要跨文件复用配置,可以结合 include 使用。
应避免在 extends 中形成循环依赖,否则会导致配置解析失败。
4.13 services:附加容器服务(如数据库、代理)
services 用于定义与任务关联的服务容器。这些服务容器通常用来运行数据库、缓存系统或其他依赖服务(如 Redis、PostgreSQL、MySQL 等),以便在 CI/CD 流水线中模拟真实的应用环境。
# 基本用法
job_name:
services:
- name: redis:6
alias: cache # 通过 alias 为服务指定一个自定义的主机名,方便任务访问
script:
- echo "Connecting to Redis at cache:6379"
# 示例:通过 variables 向服务容器传递环境变量,用于配置服务的行为
job_name:
services:
- name: mysql:8
alias: db
variables: # 设置 MySQL 的初始密码和数据库名称
MYSQL_ROOT_PASSWORD: "rootpassword"
MYSQL_DATABASE: "testdb"
script:
- echo "Connecting to MySQL at db:3306"
# 示例:启动 Redis 服务并测试连接
stages:
- build
build_job:
stage: build
services:
- name: redis:6
alias: cache
script:
- apt-get update && apt-get install -y redis-tools
- redis-cli -h cache ping
# 示例:启动 MySQL 服务并列出数据库
stages:
- deploy
deploy_job:
stage: deploy
services:
- name: mysql:8
alias: db
variables:
MYSQL_ROOT_PASSWORD: "rootpassword"
MYSQL_DATABASE: "testdb"
script:
- apt-get update && apt-get install -y mysql-client
- mysql -h db -uroot -prootpassword -e "SHOW DATABASES;"
注意:
**服务容器会在任务开始时启动,并在任务结束时停止。**如果任务失败,服务容器也会被销毁。
服务容器和任务容器共享同一个 Docker 网络,任务可以通过服务的主机名(或别名)访问服务。
某些服务需要特定的环境变量才能正常运行(如 MySQL 的 MYSQL_ROOT_PASSWORD),因此需要确保正确配置这些变量。
服务容器可能会占用额外的资源(CPU、内存等)。如果资源不足,流水线可能会失败。
services 主要适用于基于 Docker 的 Runner。如果使用其他类型的 Runner(如 Shell Runner),可能无法使用 services。
4.14 dependencies:控制任务之间依赖关系
dependencies 主要用于指定当前任务需要从哪些前置任务中下载 artifacts(制品)。
默认情况下,GitLab 会自动下载所有前置任务的制品,但通过 dependencies,可以显式地定义需要下载哪些任务的制品,或者完全禁用制品下载。
# 语法
job_name:
dependencies:
- job1
- job2
# 示例:默认情况
build_job:
script:
- echo "Building..."
artifacts: # 由于未指定 dependencies,test_job 会自动下载 build_job 的制品(dist/)
paths:
- dist/
test_job:
script:
- echo "Testing..."
# 示例:使用 dependencies 显式指定需要下载制品的任务
build_job:
script:
- echo "Building..."
artifacts:
paths:
- dist/
another_job:
script:
- echo "Another job..."
test_job:
dependencies: # test_job 只会下载 build_job 的制品,而不会下载 another_job 的制品
- build_job
script:
- echo "Testing with artifacts from build_job..."
# 示例:将 dependencies 设置为空数组表示,不下载任何制品
build_job:
script:
- echo "Building..."
artifacts:
paths:
- dist/
test_job: # test_job 不会下载任何制品
dependencies: []
script:
- echo "Testing without artifacts..."
# 示例:允许跨阶段引用其他任务的制品
stages:
- build
- test
build_job:
stage: build
script:
- echo "Building..."
- mkdir dist && echo "Artifact" > dist/file.txt
artifacts:
paths:
- dist/
test_job:
stage: test
dependencies: # test_job 从 build_job 下载制品并读取内容
- build_job
script:
- cat dist/file.txt
注意:
制品只能从前置任务中下载,不能跨流水线或从后续任务中下载。
使用 dependencies 可以减少不必要的制品下载,从而提高流水线的执行效率。
dependencies 通常与 artifacts 和 stages 结合使用,实现更精细的依赖管理。
如果指定的任务没有生成制品,GitLab 会抛出错误。确保依赖的任务正确生成了制品。