一、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 package1.5 rules 中 when 的可选值
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 做"粗筛",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: stop3.4 allow_failure:允许失败不阻塞
security-scan:
stage: test
script:
- run-security-scan.sh
allow_failure: true # ← 即使失败,也不阻塞后续阶段典型场景:代码风格检查、安全扫描——这些"建议性"的检查不应该阻塞构建。
四、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 值:
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八、小结与下篇预告
流程控制决策矩阵
下篇预告
我们一步步搭建了"骨架"、装上了"手脚"、学会了"思考",现在是时候关注工程化能力了。第五篇《进阶与复用:include / extends / trigger / environment / services》将教你如何用模块化的方式组织大型 CI/CD 配置,告别"千行 YAML",打造可复用、可维护的 CI/CD 体系。
参考资料: