Loading...

文章背景图

(三) 核心关键字详解:stages - jobs - variables - cache - artifacts

2026-08-10
0
-
- 分钟

一、stages:定义流水线的骨架

1.1 基本语法

stages:
  - build
  - test
  - deploy

三个要点:

  1. 顺序即执行顺序:列表的书写顺序就是阶段执行顺序——build → test → deploy

  2. 前一阶段全部成功,才会进入下一阶段:如果 build 中任何一个 Job 失败,test 根本不会执行

  3. 同一阶段内的 Job 并行执行:这是天然的并行能力,无需额外配置

1.2 特殊阶段:.pre 和 .post

stages:
  - .pre         # ← 在所有自定义阶段之前执行
  - build
  - test
  - deploy
  - .post        # ← 在所有自定义阶段之后执行(无论成败)
  • .pre:适合系统级初始化——比如拉取全局凭证、预热缓存等

  • .post:适合清理和通知——比如发送 Slack 通知、清理临时资源等。即使前面的阶段失败,.post 也会执行

1.3 阶段设计最佳实践

# ✅ 推荐:清晰的职责分离
stages:
  - lint           # 代码风格检查(最快,最先失败)
  - test           # 单元测试 + 集成测试
  - build          # 构建产物
  - deploy-staging # 先部署测试环境
  - deploy-prod    # 再部署生产环境

# ❌ 不推荐:阶段太少,串行等待过长
stages:
  - build
  - deploy

💡 技巧:把最快的检查放在最前面(如 lint、类型检查),让"快速失败"来得越早越好,节省等待时间。


二、Job 结构全解

一个完整的 Job 由以下要素构成:

job-name:                    # 1. 名称(必填,字母数字连字符)
  stage: build               # 2. 归属阶段(建议填写)
  image: node:20             # 3. 执行环境镜像
  tags:                      # 4. Runner 选择标签
    - docker
  script:                    # 5. 核心脚本(必填!)
    - npm install
    - npm run build
  before_script:             # 6. 前置脚本
    - echo "Job 开始"
  after_script:              # 7. 后置脚本
    - echo "Job 结束"
  only/except/rules:         # 8. 触发条件(第四篇详解)
  when: on_success           # 9. 执行时机

2.1 script:Job 的心脏

# 写法一:列表(推荐,清晰)
script:
  - npm ci
  - npm run lint
  - npm run build

# 写法二:多行字符串
script: |
  npm ci
  npm run lint
  npm run build

# 写法三:单行(不推荐超过一条命令)
script: npm run build

⚠️ 关键行为:script 中任意一条命令返回非零退出码,整个 Job 立即失败。

2.2 image:指定 Docker 镜像

# 使用官方镜像
image: node:20-alpine

# 使用精确版本(推荐生产环境)
image: node:20.11.1-alpine

# 使用私有仓库镜像
image: registry.example.com/my-team/build-image:v1.2.0

# 每个 Job 可以用不同的镜像
build-backend:
  image: golang:1.22
  script: go build ./...

build-frontend:
  image: node:20
  script: npm run build

⚠️ image 只在 Docker / Kubernetes Executor 中生效。Shell Executor 忽略此配置。

2.3 tags:选择 Runner

# 这个 Job 只会被同时拥有 docker 和 linux 标签的 Runner 执行
docker-build:
  tags:
    - docker
    - linux
  script: docker build -t myapp .

如果没有 Runner 匹配,Job 会一直卡在 pending 状态——这是新手最常见的踩坑之一。在 GitLab UI 中,你可以看到 Job 显示为 "stuck" 并提示 "no runner with tags matching xxx"。

2.4 before_script 和 after_script

default:
  before_script:
    - echo "=== 准备环境 ==="
    - npm config set registry https://registry.npmmirror.com

build-job:
  stage: build
  script:
    - npm run build
  after_script:
    - echo "构建完成,清理临时文件"
    - rm -rf /tmp/build-*

关键行为对比:

特性

before_script

script

after_script

命令失败影响 Job 结果

是(导致失败)

可与 default 合并

可以

不可

可以

适合放什么

环境准备

核心任务

清理和通知


三、variables:变量体系深度解析

3.1 变量的四个来源与优先级

GitLab CI/CD 变量有多个来源,当同名变量出现在不同来源时,有明确的优先级。以下从低到高排列:

① default 关键字中定义的         (最低)
② .gitlab-ci.yml 全局 variables
③ Project / Group / Instance 设置 中的变量
④ Job 级别 variables
⑤ 手动触发 Pipeline 时传入的变量    (最高)

换句话说:Job 级别的变量可以覆盖全局变量,手动传入的变量覆盖一切。

3.2 在 .gitlab-ci.yml 中定义变量

# 全局变量
variables:
  NODE_VERSION: "20"
  DEPLOY_ENV: "staging"

# Job 级变量
build:
  variables:
    NODE_ENV: "production"
    CACHE_DIR: "/tmp/build-cache"
  script:
    - echo "Node 版本: $NODE_VERSION"    # 全局变量
    - echo "环境: $NODE_ENV"              # Job 变量

3.3 变量类型

类型

说明

使用场景

Variable(普通)

键值对,日志中可见

配置项、版本号

File(文件型)

值写入临时文件,日志不可见

证书文件、SSH 私钥

Masked(屏蔽型)

值在日志中被 [MASKED] 替换

API Token、密码

Protected(保护型)

仅保护分支/标签可用

生产环境密钥

设置方法:在 GitLab UI 中 → Settings → CI/CD → Variables → Add variable

# 使用文件类型变量(值会自动写入临时文件)
deploy:
  script:
    - cat $KUBE_CONFIG        # 打印文件内容(K8s 配置文件)
    - kubectl --kubeconfig=$KUBE_CONFIG get pods

3.4 动态变量:巧用预定义变量

variables:
  # 根据分支动态决定环境名
  DEPLOY_TARGET: "${CI_COMMIT_BRANCH}"
  # 构建带时间戳的镜像标签
  IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}-${CI_PIPELINE_ID}"

deploy:
  script:
    - echo "部署到: $DEPLOY_TARGET"
    - docker tag myapp:$IMAGE_TAG registry.io/myapp:$IMAGE_TAG

四、cache:加速流水线的缓存策略

4.1 缓存的本质

cache 是为了在不同的 Pipeline 之间共享依赖文件,避免每次从头下载。典型使用场景:

  • node_modules(Node.js)

  • .m2/repository(Maven)

  • ~/.cache/pip(Python)

  • vendor/bundle(Ruby)

4.2 基本语法

cache:
  key: ${CI_COMMIT_REF_SLUG}   # 缓存键(决定了如何区分不同缓存)
  paths:
    - node_modules/
    - .npm/
  policy: pull-push             # 缓存策略

三个核心字段:

字段

说明

常用值

key

缓存的唯一标识

${CI_COMMIT_REF_SLUG}(按分支)、${CI_JOB_NAME}(按 Job 名)

paths

要缓存的目录/文件列表

node_modules/、target/

policy

缓存读写策略

pull-push(默认)、pull(只读)、push(只写)

4.3 cache:key 的策略

# 策略一:按分支缓存(最常用)
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/

# 策略二:按文件哈希缓存(更精确)
cache:
  key:
    files:
      - package-lock.json     # package-lock.json 变化时才重建缓存
  paths:
    - node_modules/

# 策略三:全局共享缓存
cache:
  key: global-cache
  paths:
    - .m2/repository/

4.4 cache:policy 的妙用

# install 阶段:写入缓存
install-deps:
  stage: build
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
    policy: pull-push         # ← 读写
  script:
    - npm ci

# test 阶段:只读缓存(不写回,更快)
unit-test:
  stage: test
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
    policy: pull              # ← 只读,节省写入时间
  script:
    - npm test

4.5 cache vs artifacts:一张表搞懂区别

特性

cache

artifacts

目的

加速后续 Pipeline

在 Job 之间传递构建产物

存储内容

依赖包、中间文件

构建结果、测试报告

生命周期

跨 Pipeline 持久

通常保留到 Pipeline 结束

是否上传

缓存到 Runner 侧

上传到 GitLab 服务器

下载位置

GitLab UI 不可下载

可在 UI 中下载

expire_in

不支持

支持过期时间

💡 一句话口诀依赖用 cache,产物用 artifacts。


五、artifacts:构建产物的生命周期管理

5.1 基本用法

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/              # 要保留的目录
      - build/
    exclude:               # 排除不必要文件(GitLab 14+)
      - dist/**/*.map
    expire_in: 7 days      # 7 天后自动删除

5.2 跨 Stage 传递产物

这是 artifacts 最核心的应用场景:

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/

deploy:
  stage: deploy
  script:
    - ls dist/              # ← 能访问到 build 阶段的产物!
    - scp -r dist/ server:/var/www/

默认情况下,所有后续阶段的所有 Job 都可以获取之前所有 Job 的 artifacts。如果需要精确控制,使用 dependencies:

# build-frontend 和 build-backend 同时运行
build-frontend:
  stage: build
  artifacts:
    paths: [dist/]

build-backend:
  stage: build
  artifacts:
    paths: [target/app.jar]

# deploy-frontend 只需要前端的产物
deploy-frontend:
  stage: deploy
  dependencies:
    - build-frontend        # ← 只获取前端产物
  script:
    - ls dist/              # ✅ 有
    - ls target/            # ❌ 没有

# deploy-backend 只需要后端的产物
deploy-backend:
  stage: deploy
  dependencies:
    - build-backend
  script:
    - ls target/app.jar     # ✅ 有

5.3 测试报告集成

unit-test:
  stage: test
  script:
    - npm test
  artifacts:
    reports:
      junit: junit.xml              # JUnit 测试报告 → GitLab 自动解析
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml  # 覆盖率报告

GitLab 会自动解析这些标准格式的报告,在 MR(Merge Request)页面中展示测试结果和覆盖率变化。这也是 artifacts 区别于 cache 的核心价值之一——结构化报告的自动解析和可视化

5.4 expire_in 的实用策略

# 按用途设置不同的过期时间
build:
  artifacts:
    paths: [dist/]
    expire_in: 1 day        # 构建产物保留 1 天即可(每次 MR 会重建)

release:
  artifacts:
    paths: [release/]
    expire_in: never        # 正式发布产物永久保留

六、综合示例:一个高效的 Node.js CI 配置

将本篇所有知识点串联起来:

stages:
  - install
  - lint
  - test
  - build
  - deploy

# 全局缓存策略
cache:
  key:
    files:
      - package-lock.json
  paths:
    - node_modules/
    - .npm/

# 全局默认值
default:
  image: node:20-alpine
  before_script:
    - echo "=== 开始执行 Job ==="
    - date

variables:
  NODE_ENV: "production"

# 阶段 1:安装依赖(写入缓存)
install:
  stage: install
  cache:
    policy: pull-push
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

# 阶段 2:代码检查(只读缓存)
lint:
  stage: lint
  cache:
    policy: pull
  script:
    - npm run lint

# 阶段 3:测试(生成 JUnit 报告)
test:
  stage: test
  cache:
    policy: pull
  script:
    - npm test
  artifacts:
    reports:
      junit: junit.xml
    expire_in: 30 days

# 阶段 4:构建
build:
  stage: build
  cache:
    policy: pull
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 day

# 阶段 5:部署
deploy:
  stage: deploy
  script:
    - echo "部署版本: ${CI_COMMIT_SHORT_SHA}"
    - echo "模拟部署到 ${DEPLOY_ENV:-staging}..."
  environment:
    name: staging
  only:
    - main

七、小结与下篇预告

核心知识点回顾

关键字

核心作用

一句话建议

stages

定义流程阶段和顺序

把最快失败的放最前面

script

Job 执行的命令

每个 Job 必须有

image

指定执行环境

用精确版本号,避免 latest

tags

选择 Runner

标签必须全部匹配

variables

管理配置变量

敏感信息用 Masked + Protected

cache

跨 Pipeline 缓存依赖

用 key:files 做精确缓存

artifacts

传递和保存构建产物

依赖用 cache,产物用 artifacts

下篇预告

掌握了"静态"配置后,接下来要学习如何让流水线"长脑子"——根据分支、文件变更、变量值等条件,智能地决定"是否运行"和"如何运行"。第四篇《流程控制:rules / workflow / when / needs / parallel》将带来 GitLab CI/CD 中表达式系统和 DAG 并行编排的完整讲解。


参考资料:

原创

(三) 核心关键字详解:stages - jobs - variables - cache - artifacts

本文链接: (三) 核心关键字详解:stages - jobs - variables - cache - artifacts

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

文章目录