找回密码
 立即注册
首页 业界区 业界 GitLab CI/CD 的配置文件 .gitlab-ci.yml 简介

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

南宫玉英 4 天前
〇、前言

.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.png

1.3 Job:一个基本执行单元

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

每个 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。
二、示例配置

一个简单的示例配置,可以大概浏览下有哪些配置节点,结合后文继续理解。
  1. include:
  2.   - remote: "http://www.baidu.com/data/prod.yml"
  3. variables:
  4.   - buildImage: "http://hub.com/nginx"
  5. workflow:
  6.   rules:
  7.     - if: '$CI-PIPELINE_SOURCE' == "push"'
  8.       when: never
  9.     - when: always
  10. stages:
  11.     - build
  12.     - nextStep
  13.     - testStep1
  14. build-job:
  15.   stage: build
  16.   script:
  17.     - echo "Hello, $GITLAB_USER_LOGIN!"
  18. test-job1:
  19.   stage: nextStep
  20.   script:
  21.     - echo "This job tests something"
  22. test-job2:
  23.   stage: nextStep
  24.   script:
  25.     - echo "This job tests something, but takes more time than test-job1."
  26.     - echo "After the echo commands complete, it runs the sleep command for 20 seconds"
  27. deploy-prod:
  28.   stage: testStep1
  29.   script:
  30.     - echo "This job deploys something from the $CI_COMMIT_BRANCH branch."
复制代码
这份文件包含了四个可执行的 Jobs,通过 stages 定义执行的顺序,test-job1、test-job2 的 stage 名字相同都是 nextStep,此时这两个任务将并列执行。
3.png

三、全局关键字

.gitlab-ci.yml 可以分为几个层级,首先最外层的变量包括四个,如下:
关键字释义值例举说明
stages阶段,类型数组分别为自定义的 jobs规定各个任务的执行顺序,任务名称相同,则同时执行
include引用的 yml 或 yaml 配置文件key: 包括,local、remote、file、templatelocal 一般是本地文件,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 默认是并行执行的。例如:
  1. stages:
  2.   - test
  3. unit_tests:
  4.   stage: test
  5.   script:
  6.     - echo "Running unit tests..."
  7. integration_tests:
  8.   stage: test
  9.   script:
  10.     - echo "Running integration tests..."
复制代码
在这个例子中,unit_tests 和 integration_tests 会同时运行。
在一个阶段中,也可以通过 needs 配置来实现串行执行,从而强制某些 Jobs 按顺序执行,即使它们属于同一个 stage。例如:
  1. stages:
  2.   - build
  3. job1:
  4.   stage: build
  5.   script:
  6.     - echo "Running job1..."
  7.     - sleep 5
  8.   tags:
  9.     - shared
  10. job2:
  11.   stage: build
  12.   script:
  13.     - echo "Running job2 after job1..."
  14.   needs:
  15.     - job1
复制代码
在 job2 中添加了 needs: -job1 配置,意思就是在执行 job2 之前,需要等 job1 先执行完成。
常见的阶段列举:
阶段名称描述
prepare准备工作,如安装依赖、设置环境变量等
build构建代码或生成构建产物,如编译代码、打包应用程序等
test运行单元测试、集成测试、端到端测试等
deploy将应用程序部署到目标环境,如测试、生产环境等
release发布版本,例如生成发布包、推送镜像到容器仓库等
cleanup清理临时文件、释放资源等
配置的注意事项:
为每个阶段分配明确的任务,避免混杂。例如:build 阶段只负责构建;test 阶段只负责测试;deploy 阶段只负责部署。
根据项目需求定义清晰的阶段名称,例如 prepare、package、publish 等。
过多的阶段可能导致 Pipeline 变得复杂且难以维护,要根据实际需求合理划分阶段。
如果某些阶段的失败不影响整体流程,可以通过 allow_failure: true 来允许失败。
  1. optional_stage:
  2.   stage: optional
  3.   script:
  4.     - echo "This stage can fail without affecting the pipeline."
  5.   allow_failure: true
复制代码
3.2 include 引入外部配置文件

3.2.1 简介

include 配置,用于将外部的配置文件引入到当前的 CI/CD 配置中。可以实现配置的模块化和复用,从而简化复杂的管道配置文件。
即:拆分复杂的配置文件;在多个项目中共享通用的 CI/CD 配置;维护更加清晰和模块化的管道定义。
include 等基本类型:
  1. include:
  2.   # 1)引入本地文件
  3.   # 路径是相对于项目根目录
  4.   - local: path/to/file.yml
  5.   # 2)引入外部 URL 提供的配置文件
  6.   # 文件必须可通过 HTTP 或 HTTPS 访问,并且支持 CORS(Cross-Origin Resource Sharing:跨源资源共享)
  7.   - remote: https://example.com/config.yml
  8.   # 3)使用 GitLab 提供的内置模板(如 Auto DevOps)
  9.   # 内置模板可以直接使用,无需额外配置
  10.   - template: Auto-DevOps.gitlab-ci.yml
  11.   # 4)引入其他项目的文件
  12.   # 需要指定项目路径(project)和文件路径(file)
  13.   - project: 'group/project'
  14.     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。
例如:
  1. # 主文件
  2. include:
  3.   - local: included.yml
  4. stages:
  5.   - build
  6.   - test
  7. # 外部文件:included.yml
  8. stages:
  9.   - deploy
  10. # 最终合并结果
  11. stages:
  12.   - build
  13.   - test
  14. # 即:主文件中的 stages 完全覆盖了外部文件中的 stages
复制代码

  • jobs 的合并规则
不冲突时合并:如果主文件和外部文件中的 jobs 名称不同,则它们会被合并到最终的配置中。
冲突时主文件优先:如果主文件和外部文件中有同名的 job,则主文件中的定义会完全覆盖外部文件中的定义。
  1. # 主文件:.gitlab-ci.yml
  2. include:
  3.   - local: included.yml
  4. build_job:
  5.   script:
  6.     - echo "Building from main file"
  7. # 外部文件:included.yml
  8. build_job:
  9.   script:
  10.     - echo "Building from included file"
  11. test_job:
  12.   script:
  13.     - echo "Testing from included file"
  14. # 合并结果:
  15. build_job:
  16.   script:
  17.     - echo "Building from main file"
  18. test_job:
  19.   script:
  20.     - echo "Testing from included file"
  21. # build_job 被主文件覆盖
  22. # test_job 被保留,因为它没有冲突
复制代码

  • 全局变量的合并规则
主文件优先:如果主文件和外部文件中都定义了相同的全局变量,则主文件中的值会覆盖外部文件中的值。
非冲突变量合并:如果主文件和外部文件中的变量名称不同,则它们会被合并。
3.2.3 include 实现配置文件的动态包含

通过结合 rules 或 only/except,可以根据条件动态地引入不同的配置文件。
当一个管道触发时,GitLab 会根据当前的环境变量(如 $CI_COMMIT_BRANCH)评估 rules 条件。只有满足条件的 include 块会被执行,对应的外部文件内容会被加载并合并到主配置中。
例如:
  1. include:
  2.   - local: .gitlab/ci/build-dev.yml
  3.     rules:
  4.       - if: '$CI_COMMIT_BRANCH == "dev"' # 如果当前提交的分支是 dev,则加载 .gitlab/ci/build-dev.yml 文件
  5.   - local: .gitlab/ci/build-prod.yml
  6.     rules:
  7.       - if: '$CI_COMMIT_BRANCH == "main"' # 如果当前提交的分支是 main,则加载 .gitlab/ci/build-prod.yml 文件
复制代码
3.2.4 include 允许嵌套包含

外部文件本身也可以包含其他文件,从而实现嵌套的模块化配置。
例如:
  1. # 主文件
  2. include:
  3.   - local: .gitlab/ci/main-config.yml
  4. # 外部文件:.gitlab/ci/main-config.yml
  5. include:
  6.   - local: .gitlab/ci/build.yml
  7.   - local: .gitlab/ci/test.yml
复制代码
3.2.5 include 可以结合锚点(&)和别名(*)

结合 YAML 的锚点和别名,可以在多个地方复用相同的配置。
例如:
  1. # 主文件
  2. include:
  3.   - local: .gitlab/ci/common.yml
  4. # 外部文件:.gitlab/ci/common.yml
  5. .common-template: &common-template # 定义了一个 YAML 锚点 .common-template,它包含了通用的配置(如 image 和 before_script)
  6.   image: alpine
  7.   before_script:
  8.     - echo "Preparing environment..."
  9. build_job:
  10.   <<: *common-template # 使用 <<: *common-template 将锚点的内容合并到 build_job 中,并添加特定的任务脚本(如 script)
  11.   script:
  12.     - echo "Building the application..."
  13. # 最终合并结果
  14. # 合并后的完整配置
  15. image: alpine
  16. before_script:
  17.   - echo "Preparing environment..."
  18. build_job:
  19.   image: alpine
  20.   before_script:
  21.     - echo "Preparing environment..."
  22.   script:
  23.     - echo "Building the application..."
复制代码
GitLab 对制品大小有限制,具体取决于实例配置(通常为 1GB 或更高)。如果制品过大,可以考虑压缩后再上传。
制品会在 expire_in 时间后自动删除。如果需要永久保存某些制品,可以手动调整过期时间或将其存储到外部系统(如 S3)。
如果项目使用了多个 Runner,确保 Runner 有权限上传和下载制品。
4.10 allow_failure:允许任务失败而不影响整体流水线

用于控制任务失败时是否会影响管道的整体状态。
默认情况下,如果某个任务失败,整个管道会被标记为失败。而通过设置 allow_failure: true,即使该任务失败,流水线仍然可以继续运行。
  1. # 当前触发流水线的【分支或标签名称】,示例:在 main 分支触发的流水线中,该值为 main
  2. CI_COMMIT_REF_NAME
  3. # 【当前提交(commit)的完整 SHA 值】,常用于构建 Docker 镜像或其他需要唯一标识符的场景
  4. CI_COMMIT_SHA
  5. # 当前触发流水线的【分支名称】,用于基于分支的条件逻辑判断。注意:对于由标签触发的流水线,此变量为空
  6. CI_COMMIT_BRANCH
  7. # 【当前流水线的唯一 ID】,可用于追踪特定流水线实例
  8. CI_PIPELINE_ID
  9. # 【当前任务(job)的唯一 ID】,可用于日志记录或调试
  10. CI_JOB_ID
  11. # 【项目根目录路径】,用于指定文件路径或工作目录
  12. CI_PROJECT_DIR
  13. # 【项目名称】,可用于生成报告、文档等
  14. CI_PROJECT_NAME
  15. # 项目【主页的 URL 地址】,可用于发送通知或链接到项目主页
  16. CI_PROJECT_URL
  17. # 默认情况下,这是【GitLab 容器注册表的基础地址】,结合项目路径和名称构成完整的镜像名,通常与 CI_COMMIT_SHA 结合使用来标记 Docker 镜像
  18. CI_REGISTRY_IMAGE
  19. # 如果流水线是由一个标签(tag)触发,则此变量包含该【标签的名字】否则为空,用于版本发布流程中
  20. CI_COMMIT_TAG
  21. # 【执行当前任务的 Runner 的 ID】,有助于了解哪个 Runner 执行了任务
  22. CI_RUNNER_ID
  23. # 提供服务的 GitLab 实例名称,可用于区分不同的 GitLab 实例,
  24. CI_SERVER_NAME
  25. # 【临时的 API 令牌】,允许任务访问 GitLab API 资源,可用于自动化脚本调用 GitLab API
  26. CI_JOB_TOKEN
  27. # 当前【部署环境的名称】,在多环境部署策略中很有用
  28. CI_ENVIRONMENT_NAME
  29. # 【部署密码】,当启用保护变量时可用,用于安全地存储和传递敏感信息如密码
  30. CI_DEPLOY_PASSWORD
复制代码
如果 allow_failure: true 的任务失败,管道的状态不会被标记为失败,但仍会显示为“部分成功”或“有警告”。如果所有任务都成功,则管道状态为“成功”。
有哪些使用场景:

  • 非关键任务,例如实验性功能的测试、非核心部署等。
  • 手动触发任务,允许用户手动触发的任务失败不影响整体流程。
  • 延迟任务,某些延迟任务即使失败也不影响主要流程。
4.11 when:控制任务的执行时机

when 需结合 rules 或 trigger 使用。
常用的值:
on_success:描述:任务仅在所有前置任务成功完成时运行(默认行为)。
on_failure:任务仅在至少一个前置任务失败时运行。通常用于清理环境或发送通知。
always:无论前置任务是否成功或失败,任务都会运行。通常用于生成报告或记录日志。
manual:任务需要手动触发,不会自动运行。适用于需要人工干预的任务,例如部署到生产环境。
delayed:任务会在指定的时间延迟后运行。适用于定时任务或延迟触发的场景(需配合 start_in)。
  1. variables: # 全局变量
  2.   ENV: "production"
  3.   DB_HOST: "db.example.com"
  4. build_job1:
  5.   script:
  6.     - echo "Deploying to $ENV"
  7.     - echo "Connecting to $DB_HOST"
  8.    
  9. build_job2:
  10.   variables: # 局部变量
  11.     BUILD_TYPE: "debug"
  12.   script:
  13.     - echo "Building with type $BUILD_TYPE"
复制代码
注意:手动任务不会影响流水线的整体状态,即使未触发也不会导致流水线失败。
when: delayed 的限制 start_in 的最小延迟时间为 1 分钟。如果流水线被取消或超时,延迟任务不会运行。
4.12 extends:继承其他任务或模板的配置

extends 用于实现任务配置的复用和继承。
通过 extends,可以将通用的配置提取到一个模板中,避免重复定义,提高配置文件的可维护性和可读性。
  1. [[runners]]
  2.   environment = ["CUSTOM_VAR=value"]
复制代码
模板名称通常以 . 开头(如 .common-template),表示它是一个隐藏的任务,不会被实际执行
如果模板和任务中有同名的配置项,任务中的配置优先级更高
extends 只能在同一个文件中使用。如果需要跨文件复用配置,可以结合 include 使用。
应避免在 extends 中形成循环依赖,否则会导致配置解析失败。
4.13 services:附加容器服务(如数据库、代理)

services 用于定义与任务关联的服务容器。这些服务容器通常用来运行数据库、缓存系统或其他依赖服务(如 Redis、PostgreSQL、MySQL 等),以便在 CI/CD 流水线中模拟真实的应用环境。
  1. deploy_job:
  2.   script:
  3.     - if [ "$DEPLOY_ENV" == "production" ]; then
  4.         echo "Deploying to production";
  5.       else
  6.         echo "Deploying to staging";
  7.       fi
复制代码
注意:
服务容器会在任务开始时启动,并在任务结束时停止。如果任务失败,服务容器也会被销毁。
服务容器和任务容器共享同一个 Docker 网络,任务可以通过服务的主机名(或别名)访问服务。
某些服务需要特定的环境变量才能正常运行(如 MySQL 的 MYSQL_ROOT_PASSWORD),因此需要确保正确配置这些变量。
服务容器可能会占用额外的资源(CPU、内存等)。如果资源不足,流水线可能会失败。
services 主要适用于基于 Docker 的 Runner。如果使用其他类型的 Runner(如 Shell Runner),可能无法使用 services。
4.14 dependencies:控制任务之间依赖关系

dependencies 主要用于指定当前任务需要从哪些前置任务中下载 artifacts(制品)
默认情况下,GitLab 会自动下载所有前置任务的制品,但通过 dependencies,可以显式地定义需要下载哪些任务的制品,或者完全禁用制品下载。
  1. deploy_job:
  2.   script:
  3.     - echo "Using API key: $API_KEY"
复制代码
注意:
制品只能从前置任务中下载,不能跨流水线或从后续任务中下载。
使用 dependencies 可以减少不必要的制品下载,从而提高流水线的执行效率。
dependencies 通常与 artifacts 和 stages 结合使用,实现更精细的依赖管理。
如果指定的任务没有生成制品,GitLab 会抛出错误。确保依赖的任务正确生成了制品。
参考:https://juejin.cn/post/6971013569986953223

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册