.gitlab-ci.yml 简介

发布时间: 更新时间: 总字数:2732 阅读时间:6m 作者:IP:上海 网址

.gitlab-ci.yml 是 GitLab CI/CD 的核心配置文件,它告诉 GitLab Runner 具体要执行什么操作。

.gitlab-ci.yml 简介

.gitlab-ci.yml 是一个使用 YAML 语法编写的文件,通常存放在项目的根目录下。

  • 作用:定义自动化的流水线(Pipeline)。
  • 触发机制:当你推送代码(push)、创建合并请求(Merge Request)或打标签(Tag)时,GitLab 会自动检测该文件并触发流水线。
  • 结构:由一系列的 Jobs(作业)组成,这些 Job 被分配到不同的 Stages(阶段)中按顺序或并发执行。

核心关键字速查表

下表总结了最常用和关键的配置项:

关键字 说明 典型用途
stages 定义流水线的阶段顺序 [build, test, deploy],决定了 Job 的执行大顺序。
stage 定义当前 Job 属于哪个阶段 将 Job 归类,如 stage: build
script (必填) Job 真正执行的 Shell 命令 npm installdocker buildpytest 等。
image 指定执行环境的 Docker 镜像 node:16-alpinepython:3.9
default 设置全局默认值 如果大部分 Job 都用同一个 image 或 tag,可在此统一定义。
variables 定义环境变量 数据库连接串、版本号等(避免硬编码)。
rules 现代化的条件判断逻辑 (替代 only/except) 决定 Job 何时运行(如:只在 Tag 时、只在 MR 时)。
extends 继承模版(复用配置) 减少重复代码,继承隐藏作业 (.hidden-job) 的配置。
artifacts 定义产物(Job 跑完后保留的文件) 保存编译后的二进制文件、测试报告,供后续 Stage 下载。
dependencies 限制下载哪些 Job 的产物 默认后续 Stage 会下载前面所有产物,用此可指定只下载特定的。
needs 定义依赖关系(DAG 模式) 高级:允许跨 Stage 并行,不按严格顺序,只等待特定的 Job 完成。
allow_failure 是否允许失败 设为 true 时,即使该 Job 报错,流水线也会继续(常用于非阻塞的测试)。
before_script 脚本执行前的准备命令 安装依赖、打印环境信息等。
cache 定义缓存 缓存 node_modules 等,加速下一次构建。
environment 定义部署环境 用于 GitLab UI 记录部署历史(如 Production, Staging)。
tags 指定由哪个 Runner 执行 对应 GitLab Runner 配置的 tag(如 gpu, linux)。

环境变量解释

GIT_STRATEGY

  • 环境变量 GIT_STRATEGY 用于控制 GitLab Runner 如何获取(拉取)源代码,它决定了在作业(Job)开始执行脚本之前,Runner 是应该重用之前的代码、重新克隆整个仓库,还是根本不需要代码。
策略值 行为描述 速度 纯净度 推荐场景
fetch (默认) 复用本地目录,拉取更新 快 🚀 低 (可能有残留) 日常开发、测试、CI 流程
clone 删除目录,重新克隆 慢 🐢 高 (完全纯净) 正式发布、排查环境问题
none 不拉取代码 最快 ⚡️ - 仅依赖 Artifacts 的部署、通知任务

GIT_DEPTH

当使用 fetchclone 时,为了进一步加快速度,通常会配合 GIT_DEPTH 变量使用(浅克隆):

yaml
variables:
  GIT_STRATEGY: fetch
  GIT_DEPTH: "1" # 只下载最近的一次 commit,不下载历史记录,速度极快


## 深度解析:复杂流程完整实例

**场景假设**:
我们要构建一个 Node.js 应用。

1.  **全局配置**:默认使用 Node 镜像,设置重试机制。
2.  **Lint 阶段**:代码风格检查,允许失败(不阻塞流程)。
3.  **Build 阶段**:编译代码,生成 `dist/` 目录作为产物。
4.  **Test 阶段**:
    - 单元测试:需要 `dist/` 文件。
    - 安全扫描:使用特定 Docker 镜像,耗时较长。
5.  **Deploy 阶段**:
    - **Staging**:当合并到 `main` 分支时自动部署。
    - **Production**:只有打 `v*` 格式的 Tag 时才部署,且需要人工点击确认。

### 完整的 `.gitlab-ci.yml` 内容

```yaml
# 1. 定义整个流水线的阶段顺序
stages:
  - check # 代码检查
  - build # 构建
  - test # 测试
  - deploy # 部署

# 2. 全局默认配置 (Default)
# 所有 Job 如果没有单独指定,都会继承这里的配置
default:
  image: node:16-alpine # 默认使用 Node 16 镜像
  retry: 1 # 如果 Job 失败,自动重试 1 次
  tags: # 指定默认由带 'docker' 标签的 Runner 执行
    - docker

# 全局变量
variables:
  NPM_CONFIG_CACHE: '$CI_PROJECT_DIR/.npm'

# 3. 缓存配置:在 Job 之间共享 node_modules,加快速度
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
    - .npm/

# 4. 模版作业 (Hidden Job / Template)
# 以 '.' 开头,不会直接运行,专门用于被 extends 继承
.deploy_template:
  stage: deploy
  script:
    - echo "Deploying to $DEPLOY_ENV..."
    - echo "Simulate deployment script here"
    # 假设这里有真实部署命令,如 scp 或 kubectl
  dependencies:
    - build_app # 明确只下载 build_app 的产物

# =======================
# Stage: CHECK
# =======================
lint_code:
  stage: check
  script:
    - npm ci
    - npm run lint
  # 关键字: allow_failure
  # 即使代码风格检查失败,流水线也会显示橙色警告,但继续执行后续 Build
  allow_failure: true

# =======================
# Stage: BUILD
# =======================
build_app:
  stage: build
  script:
    - npm ci
    - npm run build
  # 关键字: artifacts
  # 定义产物,build 完成后,GitLab 会把 dist 目录压缩保存
  artifacts:
    name: 'dist-$CI_COMMIT_REF_NAME'
    expire_in: 1 week # 产物保留1周
    paths:
      - dist/ # 指定要保留的文件夹

# =======================
# Stage: TEST
# =======================
unit_test:
  stage: test
  script:
    - npm run test
  # 关键字: dependencies
  # 显式声明依赖 build_app,GitLab 会自动把 build_app 的 artifacts 下载并解压到当前目录
  dependencies:
    - build_app

security_scan:
  stage: test
  # 关键字: image (覆盖全局 default)
  # 这个 Job 需要特殊的安全工具镜像,不使用默认的 Node 镜像
  image: aquasec/trivy:latest
  script:
    - trivy filesystem .
  # 关键字: rules (逻辑控制)
  # 仅在 main 分支 或 Tag 时运行,Merge Request 中不运行以节省资源
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_COMMIT_TAG

# =======================
# Stage: DEPLOY
# =======================

# 部署到测试环境
deploy_staging:
  # 关键字: extends
  # 继承上面定义的 .deploy_template,复用 script 和 dependencies
  extends: .deploy_template
  variables:
    DEPLOY_ENV: 'Staging'
  environment:
    name: staging
    url: https://staging.example.com
  # 规则:只有当推送到 main 分支时执行
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# 部署到生产环境
deploy_production:
  extends: .deploy_template
  variables:
    DEPLOY_ENV: 'Production'
  environment:
    name: production
    url: https://example.com
  # 规则:只有打 Tag (例如 v1.0.0) 时才执行
  rules:
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
      when: manual # 关键:手动触发。流水线会暂停,等待人工点击`播放`按钮
  # 生产环境通常不允许失败
  allow_failure: false

详细代码解读

让我们把上面例子中体现的关键技术点拆解一下:

stages (流程编排)

GitLab CI 默认有 .pre, build, test, deploy, .post 这几个阶段

yaml
stages:
  - check
  - build
  - test
  - deploy

GitLab 会按照这个顺序执行。如果 check 阶段的所有 Job 没成功(除非 allow_failure: true),就不会进入 build。同一个 Stage 下的 Job(如 unit_testsecurity_scan)是并行运行的。

extends (继承/复用)

yaml
.deploy_template:
  script: ...

deploy_staging:
  extends: .deploy_template

这是保持 YAML 简洁的最佳实践。.deploy_template 就像父类,定义了通用的部署脚本。deploy_stagingdeploy_production 继承它,只需要修改变量 (variables) 和规则 (rules)。

artifactsdependencies (文件传递)

  • Build 阶段artifacts 告诉 GitLab:“我生成了 dist/ 目录,请打包上传到服务器”。
  • Test/Deploy 阶段:默认情况下,后续阶段会自动下载所有前序阶段的 artifacts。
  • Dependencies:在 deploy_staging 中,如果我们只想下载 build_app 的产物(不想下载 unit_test 可能产生的测试报告),使用 dependencies: ["build_app"] 可以显式指定,既安全又加快下载速度。

rules (强大的逻辑控制)

这是现代 GitLab CI 最核心的部分,取代了老旧的 only/except

yaml
rules:
  - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
    when: manual

这段逻辑表示:

  1. IF: 当前提交是一个 Tag,且 Tag 名字匹配版本号正则(如 v1.0.0)。
  2. THEN: 将 Job 状态设为 manual(手动)。在 UI 界面上,这个 Job 会显示一个播放按钮,只有点击后才会真正部署。这对生产环境至关重要。

allow_failure (容错)

lint_code 中设置了 true。这意味着,如果 ESLint 发现代码格式有问题报错了,Pipeline 会显示一个黄色的感叹号(Warning),但不会通过红色的 X(Error)来停止流水线,后续的 build 依然会继续。

defaultimage

  • 我们在顶部 default 里定义了 node:16-alpine。大部分 Job 不需要写 image,直接用这个。
  • 但是在 security_scan 中,我们需要运行安全扫描工具 trivy,所以用 image: aquasec/trivy:latest 覆盖了默认值。

这个例子涵盖了你在实际工作中 90% 会用到的场景,从基础构建到复杂的生产环境门禁控制。

参考

  1. https://docs.gitlab.com/ci/yaml/