Loading...

文章背景图

(四) 流程控制:rules - workflow - when - needs - parallel

2026-08-10
0
-
- 分钟

一、rules:新一代条件控制

rules 是 GitLab CI/CD 中用于控制 Job 是否运行的核心机制,也是官方推荐替代 only/except 的现代化方案。

1.1 基本结构

job-name:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: always              # 条件匹配时执行
    - if: $CI_COMMIT_BRANCH == "develop"
      when: manual              # 条件匹配时手动触发
    - when: never               # 其余情况不执行

1.2 rules:if:基于变量条件判断

这是最常用的 rules 子句,基于 CI/CD 变量表达式来决定 Job 是否运行。

deploy-prod:
  stage: deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/   # 匹配语义化版本标签
  script:
    - ./deploy.sh production

⚠️ 求值规则:rules 按从上到下的顺序求值,遇到第一个匹配的规则就停止(first-match 模式)。因此,把最严格的条件放在最上面。

1.3 rules:changes:文件变更触发

frontend-tests:
  rules:
    - changes:
        - frontend/**/*           # 只有 frontend 目录下的文件变更才触发
        - package.json
        - package-lock.json
  script:
    - cd frontend && npm test

你可以组合多个条件:

docker-build:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      changes:
        - Dockerfile
        - docker-compose.yml
        - src/**/*
  script:
    - docker build -t myapp .

1.4 rules:exists:文件存在性判断

java-build:
  rules:
    - exists:
        - build.gradle           # 存在 Gradle 配置文件
  script:
    - gradle build

maven-build:
  rules:
    - exists:
        - pom.xml                # 存在 Maven 配置文件
  script:
    - mvn package

1.5 rules 中 when 的可选值

含义

always(默认)

条件匹配时自动执行

never

条件匹配时不执行

manual

条件匹配时手动触发

delayed

条件匹配时延迟执行(需配合 start_in)

on_success

前面阶段都成功时执行

1.6 实战:从 only/except 迁移到 rules

# ❌ 旧式写法(GitLab 已不推荐)
deploy:
  only:
    - main
  except:
    - tags

# ✅ 新式写法
deploy:
  rules:
    - if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG == null

二、workflow:全局流水线开关

2.1 为什么需要 workflow?

rules 控制的是单个 Job,"这个 Job 要不要运行";而 workflow 控制的是整条 Pipeline,"这条 Pipeline 要不要被创建"。

workflow:
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /\[skip ci\]/        # 提交信息包含 [skip ci]
      when: never                                      # → 不创建 Pipeline
    - if: $CI_PIPELINE_SOURCE == "merge_request_event" # MR 触发
    - if: $CI_COMMIT_BRANCH == "main"                  # main 分支推送
    - if: $CI_COMMIT_TAG                               # 标签推送
    - when: never                                       # 其他情况不触发

2.2 workflow:name:自定义 Pipeline 名称

workflow:
  name: 'Pipeline for $CI_COMMIT_BRANCH ($CI_COMMIT_SHORT_SHA)'
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

在 GitLab UI 中,你看到的 Pipeline 名称就从默认的 #123456789 变成了可读的描述。

2.3 workflow vs rules 的职责划分

workflow:rules

Job 的 rules

控制粒度

整条 Pipeline

单个 Job

典型用途

过滤不需要 CI 的提交、限定触发来源

决定哪些 Job 在当前分支运行

求值时机

Pipeline 创建前

Pipeline 创建后

💡 最佳实践:workflow 做"粗筛",Job rules 做"细选"。


三、when:精确控制执行时机

3.1 六个可选值

job-a:
  when: on_success    # 默认值:前面阶段都成功时运行

job-b:
  when: on_failure    # 前面有失败时运行(告警/回滚常见)

job-c:
  when: always        # 无论前面成败,始终运行(通知/清理)

job-d:
  when: manual        # 手动触发(审批门禁)

job-e:
  when: delayed       # 延迟执行
  start_in: 30 minutes

job-f:
  when: never         # 永不自动执行(但可以通过 API 或 UI 触发)

3.2 manual:手动审批门禁

deploy-production:
  stage: deploy
  when: manual
  script:
    - kubectl apply -f production.yaml
  environment:
    name: production

效果:Pipeline 运行到 deploy-production 时会停下来,显示一个"播放按钮"。只有被授权的人点击后,才会继续执行。这就是 DevOps 中常见的"部署审批"机制。

3.3 delayed:延迟执行与自动回滚

deploy-canary:
  stage: deploy
  script:
    - kubectl apply -f canary.yaml
  environment:
    name: production
    on_stop: rollback-canary   # ← 自动停止时会触发回滚 Job

rollback-canary:
  stage: deploy
  when: manual
  script:
    - kubectl rollout undo deployment/canary
  environment:
    name: production
    action: stop

3.4 allow_failure:允许失败不阻塞

security-scan:
  stage: test
  script:
    - run-security-scan.sh
  allow_failure: true          # ← 即使失败,也不阻塞后续阶段

allow_failure

Job 失败时

false(默认)

Pipeline 状态变为 failed,后续阶段不执行

true

Job 显示为黄色警告 ⚠️,Pipeline 继续执行

典型场景:代码风格检查、安全扫描——这些"建议性"的检查不应该阻塞构建。


四、needs:打破阶段顺序(DAG Pipeline)

4.1 默认行为 vs needs

默认情况下,同一 Stage 的 Job 并行执行,但 Stage 之间严格串行:

Stage: build        Stage: test          Stage: deploy
┌──────────┐       ┌──────────┐       ┌──────────┐
│ build-app│──→    │ test-app │──→    │ deploy   │
└──────────┘       └──────────┘       └──────────┘

使用 needs 可以创建有向无环图(DAG),让 Job 突破 Stage 的顺序限制:

build-frontend:
  stage: build
  script: npm run build --prefix frontend
  artifacts:
    paths: [frontend/dist/]

build-backend:
  stage: build
  script: mvn package -f backend
  artifacts:
    paths: [backend/target/app.jar]

# 不等待整个 build 阶段完成!只要 build-frontend 完成就立刻开始
test-frontend:
  stage: test
  needs: [build-frontend]     # ← 只依赖 build-frontend
  script: npm test --prefix frontend

test-backend:
  stage: test
  needs: [build-backend]
  script: mvn test -f backend

deploy:
  stage: deploy
  needs: [test-frontend, test-backend]
  script: ./deploy.sh

这样,test-frontend 不需要等待 build-backend 完成就能开始,大幅缩短整体 Pipeline 时间。

4.2 needs + artifacts:精确的产物传递

build:
  stage: build
  script: make build
  artifacts:
    paths: [output/]

deploy:
  stage: deploy
  needs:
    - job: build
      artifacts: true          # ← 明确声明需要 build 的 artifacts
  script:
    - ls output/               # ✅ 能访问到

4.3 needs 的可视化

在 GitLab 的 Pipeline 详情页中,使用 needs 的 Pipeline 会展示为真正的 DAG 图,你可以直观地看到 Job 之间的依赖关系和数据流向。


五、parallel:并行化与矩阵构建

5.1 基本并行

heavy-test:
  script: rspec
  parallel: 5            # ← 同时启动 5 个 Job 实例

GitLab 会自动创建 heavy-test 1/5、heavy-test 2/5 …… heavy-test 5/5。每个实例可以通过环境变量知道自己是第几个:

  • CI_NODE_INDEX:从 1 开始的索引

  • CI_NODE_TOTAL:总数

heavy-test:
  parallel: 5
  script:
    - echo "这是第 ${CI_NODE_INDEX}/${CI_NODE_TOTAL} 个实例"
    - rspec --only-chunk=${CI_NODE_INDEX} --total-chunks=${CI_NODE_TOTAL}

5.2 parallel:matrix:矩阵变量组合

这是 GitLab 13.3+ 引入的强大特性,让你用一个 Job 定义覆盖多种环境组合:

test-matrix:
  stage: test
  image: $IMAGE
  parallel:
    matrix:
      - IMAGE: [node:18, node:20, node:22]
        DB: [postgres:15, postgres:16]
  script:
    - echo "测试环境: Node.js $IMAGE + PostgreSQL $DB"
    - npm test

上面的配置会自动生成 3 × 2 = 6 个 Job 实例

test-matrix: [node:18, postgres:15]
test-matrix: [node:18, postgres:16]
test-matrix: [node:20, postgres:15]
test-matrix: [node:20, postgres:16]
test-matrix: [node:22, postgres:15]
test-matrix: [node:22, postgres:16]

这样可以非常方便地测试跨版本兼容性。


六、其他流程控制关键字

6.1 interruptible:自动取消冗余 Pipeline

# 任何 Job 都可以声明自己是可中断的
build:
  interruptible: true
  script:
    - npm run build

效果:当你快速连续推送代码时,如果前一个 Pipeline 还没跑完,GitLab 会自动取消旧 Pipeline 中标记了 interruptible: true 的 Job,节省 Runner 资源。需要配合项目设置中的 "Auto-cancel redundant pipelines" 开关使用。

6.2 retry:失败自动重试

flakey-test:
  script: npm run test
  retry:
    max: 2                  # 最多重试 2 次
    when:
      - runner_system_failure
      - stuck_or_timeout_failure
      - unknown_failure

可用的 when 值:

触发场景

always

任何失败都重试

unknown_failure

未知错误(非脚本错误)

script_failure

脚本返回非零退出码

runner_system_failure

Runner 系统故障

stuck_or_timeout_failure

Job 卡住或超时

6.3 timeout:超时控制

long-build:
  timeout: 2h 30min        # 自定义超时时间
  script:
    - ./build-all.sh

默认超时因 Runner 和项目设置而异(通常 1 小时),你可以按需调整。


七、综合示例:智能流水线

将所有流程控制机制组合在一起:

workflow:
  name: '$CI_COMMIT_BRANCH ($CI_COMMIT_SHORT_SHA)'
  rules:
    - if: $CI_COMMIT_MESSAGE =~ /\[skip ci\]/
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG =~ /^v/

stages:
  - lint
  - test
  - build
  - deploy-staging
  - deploy-prod

lint:
  stage: lint
  interruptible: true
  rules:
    - changes:
        - src/**/*
  script: npm run lint
  allow_failure: true

test-matrix:
  stage: test
  interruptible: true
  parallel:
    matrix:
      - NODE: [18, 20, 22]
  image: node:${NODE}
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script: npm test
  retry:
    max: 1
    when:
      - runner_system_failure

build:
  stage: build
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG
  script: npm run build
  artifacts:
    paths: [dist/]

deploy-staging:
  stage: deploy-staging
  needs: [build]
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  script: ./deploy.sh staging
  environment:
    name: staging

deploy-prod:
  stage: deploy-prod
  needs: [deploy-staging]
  rules:
    - if: $CI_COMMIT_TAG =~ /^v/
  when: manual
  script: ./deploy.sh production
  environment:
    name: production

八、小结与下篇预告

流程控制决策矩阵

你要控制什么

用什么关键字

是否创建 Pipeline

workflow:rules

某个 Job 是否运行

rules:if / rules:changes / rules:exists

Job 何时执行

when: manual / when: delayed

Job 之间的依赖顺序

needs(DAG 模式)

同时跑多少个实例

parallel / parallel:matrix

失败后要不要重试

retry

失败是否阻塞后续

allow_failure

下篇预告

我们一步步搭建了"骨架"、装上了"手脚"、学会了"思考",现在是时候关注工程化能力了。第五篇《进阶与复用:include / extends / trigger / environment / services》将教你如何用模块化的方式组织大型 CI/CD 配置,告别"千行 YAML",打造可复用、可维护的 CI/CD 体系。


参考资料:

原创

(四) 流程控制:rules - workflow - when - needs - parallel

本文链接: (四) 流程控制:rules - workflow - when - needs - parallel

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

文章目录