GitLab CI/CD 的配置文件 .gitlab-ci.yml 简介

〇、前言

.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 文件。

注意事项:

  1. **访问权限:**如果使用 project 类型引用其他项目的文件,需要确保当前项目有权限访问目标项目。如果使用 remote 类型,目标文件必须公开或有适当的访问权限。
  2. **不允许存在循环依赖:**例如 A 包含 B,B 又包含 A。
  3. **合理拆分文件:**单个大文件和过多的 include 都会增加 Pipeline 配置加载的时间。
  4. **提前验证配置内容:**使用 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 会根据以下优先级决定最终值**(从高到低)**:

  1. Job 任务级别的变量(局部变量)
  2. GitLab UI 配置的变量
  3. 全局变量(.gitlab-ci.yml 文件中定义的 variables)
  4. Runner 配置的变量
  5. 系统预定义变量

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 不会自动清理旧的缓存,但可以通过以下两种方式手动清理:

  1. 在项目的 Settings > CI/CD > Cache 页面中删除缓存。
  2. 修改 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 会抛出错误。确保依赖的任务正确生成了制品。

参考:https://juejin.cn/post/6971013569986953223

相关推荐
老陈头聊SEO3 天前
SEO长尾词优化实战布局
其他
ye150127774553 天前
220V转直流非隔离传感器供电电源芯片WT5105
stm32·单片机·嵌入式硬件·其他·硬件工程
时空无限4 天前
虚无隧穿产生宇宙(true nothing tunneling) 是谁提出的
其他
张高兴6 天前
为什么要对程序进行调试
其他
这是我587 天前
awk命令——功能强大的文本处理工具
linux·其他·shell·awk·强大··
cwtlw9 天前
PhotoShop学习10
笔记·学习·其他·photoshop
stockmasterx10 天前
什么是ETF跟踪误差?场内基金佣金最低是多少?
经验分享·笔记·其他
技术与健康10 天前
学点概率论,打破认识误区
经验分享·其他
安德胜SMT贴片10 天前
SMT贴片:现代电子制造的核心工艺
其他