一、include:把千行 YAML 拆成乐高积木
include 允许你将 .gitlab-ci.yml 拆分成多个文件,或者引用外部模板,是 GitLab CI/CD 配置模块化的核心。
GitLab 支持六种 include 来源:
1.1 include:local:同仓库拆分(最常用)
# .gitlab-ci.yml(主文件)
include:
- local: '/ci/build.yml'
- local: '/ci/test.yml'
- local: '/ci/deploy.yml'
stages:
- build
- test
- deploy# ci/build.yml
build-backend:
stage: build
image: golang:1.22
script: go build ./...
build-frontend:
stage: build
image: node:20
script: npm run build# ci/test.yml
unit-test:
stage: test
script: go test ./...
lint:
stage: test
script: golangci-lint run目录结构一览:
my-project/
├── .gitlab-ci.yml ← 入口文件
└── ci/
├── build.yml ← 构建相关
├── test.yml ← 测试相关
└── deploy.yml ← 部署相关1.2 include:project:跨项目共享模板
适用于公司级别的共享 CI/CD 模板库:
include:
- project: 'devops/shared-ci-templates'
ref: v2.0.0 # 强烈建议指定版本!
file: '/templates/nodejs.yml'
- project: 'devops/shared-ci-templates'
file: '/templates/docker-build.yml'⚠️ 安全提示:建议用 Git Tag(v2.0.0)或完整 SHA 指定 ref,避免模板仓库变更导致所有项目 Pipeline 突然全部挂掉。
1.3 include:template:使用官方模板
GitLab 提供了大量开箱即用的 CI/CD 模板,涵盖 SAST 安全扫描、Auto DevOps、多种语言框架等:
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Code-Quality.gitlab-ci.yml查看所有可用模板:GitLab CI Templates
1.4 include:rules:条件引入
include:
- local: '/ci/security-scan.yml'
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # 只在默认分支跑安全扫描
- local: '/ci/e2e-test.yml'
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # MR 时跑 E2E1.5 合并策略与优先级
当同一个 Job 在多个 include 文件中都有定义时,最后定义的那个生效。include 的评估顺序是:
① include 引入的文件先评估
② .gitlab-ci.yml 主文件后评估
③ 同名的配置,后定义的覆盖先定义的这意味着你可以在主文件中"覆盖"引入的模板中某个 Job 的部分配置:
# 引入模板
include:
- template: Jobs/Build.gitlab-ci.yml
# 覆盖模板中 build Job 的某些配置
build:
image: node:22 # ← 覆盖模板中的镜像版本
variables: # ← 添加模板中没有的变量
BUILD_FLAGS: "--production"二、extends:消除重复配置
2.1 基本用法
# 定义可复用的"基类"
.node-job:
image: node:20-alpine
before_script:
- npm config set registry https://registry.npmmirror.com
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
# 继承基类,覆盖/补充
lint:
extends: .node-job
stage: lint
script:
- npm run lint
test:
extends: .node-job
stage: test
script:
- npm test命名以 . 开头的 Job 被称为"隐藏 Job"——GitLab 不会把它们当作真正的 Job 来执行,仅用于被 extends 引用。
2.2 多层继承
.base:
before_script:
- echo "基础准备"
.node:
extends: .base
image: node:20
.linter:
extends: .node
before_script:
- echo "代码检查准备"
eslint:
extends: .linter # 继承了 .base + .node + .linter
script:
- npx eslint src/2.3 extends vs include 的选择
💡 两者不互斥:可以在 include 引入的模板基础上再用 extends 做二次继承。
三、trigger:多级流水线
3.1 触发下游项目
trigger-deploy:
stage: deploy
trigger:
project: ops/infrastructure-repo # 下游项目
branch: main
strategy: depend # 等待下游 Pipeline 完成后才继续
variables:
APP_VERSION: $CI_COMMIT_SHORT_SHA
TRIGGERED_BY: $CI_PROJECT_NAMEstrategy: depend 意味着当前 Pipeline 会等待下游 Pipeline 完成后,才能进入下一个阶段。这在多仓库关联部署时非常有用。
3.2 父子 Pipeline(Parent-Child)
这是 GitLab 13.2+ 引入的强大功能——在一个 Pipeline 中动态生成子 Pipeline:
# .gitlab-ci.yml(父 Pipeline)
generate-config:
stage: build
script:
- ./generate-child-pipeline.sh # 生成子 Pipeline 配置
artifacts:
paths:
- child-pipeline.yml
child-pipeline:
stage: test
trigger:
include:
- artifact: child-pipeline.yml # 使用上一步生成的配置
- job: generate-config
strategy: depend一个极端实用的例子:Monorepo 中根据代码变更动态决定跑哪些子项目的 CI:
# generate-child-pipeline.sh
#!/bin/bash
echo "stages:" > child-pipeline.yml
echo " - test" >> child-pipeline.yml
# 检测哪些子项目有变更
for project in frontend backend admin; do
if git diff --name-only HEAD~1 | grep "^$project/"; then
cat >> child-pipeline.yml << EOF
${project}-test:
stage: test
script:
- cd ${project}
- npm test
EOF
fi
done3.3 三种触发方式对比
四、environment:环境管理与部署追踪
4.1 声明环境
deploy-staging:
stage: deploy
script: ./deploy.sh
environment:
name: staging
url: https://staging.example.com
deploy-production:
stage: deploy
script: ./deploy.sh
environment:
name: production
url: https://example.com效果:
GitLab 自动在 Deployments → Environments 页面中展示每个环境的部署历史
每个 Merge Request 中能看到"部署到了哪个环境"
可以直接在 GitLab UI 中查看部署的应用(通过 url 链接)
4.2 环境级别的变量范围
deploy:
stage: deploy
variables:
DB_HOST: staging-db.example.com # staging 环境的数据库
environment:
name: staging
url: https://staging.example.com
on_stop: stop-staging # ← 关联停止部署的 Job
script:
- ./deploy.sh staging
stop-staging:
stage: deploy
variables:
GIT_STRATEGY: none # 不需要拉代码
when: manual
environment:
name: staging
action: stop # ← 停止环境的动作
script:
- ./destroy.sh staging4.3 自动停止环境
review:
stage: deploy
script: ./deploy-review-app.sh
environment:
name: review/$CI_COMMIT_REF_SLUG # ← 动态环境名!每个分支独立
url: https://$CI_COMMIT_REF_SLUG.review.example.com
on_stop: stop-review
auto_stop_in: 3 days # ← 3 天后自动停止(清理资源)这样,每个 MR 都会自动创建一个独立的环境用于预览(Review App),3 天后自动销毁。
4.4 Protected Environment:部署审批
在 GitLab UI 中 → Settings → CI/CD → Protected Environments,你可以设置:
哪些用户/角色可以部署到某环境
部署是否需要审批
配合 when: manual,实现生产环境的审批流程。
五、services:为 Job 提供附加服务
5.1 基本概念
services 启动一个额外的容器,为 Job 容器提供辅助服务——最常见的是数据库。
integration-test:
image: node:20
services:
- postgres:16-alpine # ← 启动一个 PostgreSQL 容器
variables:
POSTGRES_DB: testdb
POSTGRES_USER: tester
POSTGRES_PASSWORD: secret
# 注意:连接数据库时用 hostname "postgres",不是 "localhost"
DATABASE_URL: "postgresql://tester:secret@postgres:5432/testdb"
script:
- npm test关键理解:Job 容器和 service 容器在同一个 Docker 网络中,Job 可以通过 service 的镜像名(如 postgres)来访问它。
5.2 自定义别名
integration-test:
services:
- name: postgres:16-alpine
alias: db # ← 自定义别名
variables:
DATABASE_URL: "postgresql://tester:secret@db:5432/testdb"5.3 常用服务组合
# Node.js + PostgreSQL + Redis
fullstack-test:
image: node:20
services:
- postgres:16-alpine
- redis:7-alpine
variables:
PGHOST: postgres
REDIS_URL: redis://redis:6379
script:
- npm test
# Java + MySQL
java-test:
image: maven:3.9-eclipse-temurin-21
services:
- mysql:8.4
variables:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: testdb
JDBC_URL: jdbc:mysql://mysql:3306/testdb
script:
- mvn test5.4 启动等待
某些服务(如数据库)启动需要时间。GitLab Runner 内置了健康检查,但你也可以用 docker-wait 或脚本做自定义等待:
services:
- name: postgres:16-alpine
command: ["postgres", "-c", "max_connections=200"]
script:
- |
echo "等待 PostgreSQL 就绪..."
for i in $(seq 1 30); do
if pg_isready -h postgres -U tester; then
echo "PostgreSQL 已就绪"
break
fi
sleep 1
done
- npm test六、release:自动发布
release-job:
stage: deploy
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
script:
- echo "Creating release $CI_COMMIT_TAG"
release:
name: 'Release $CI_COMMIT_TAG'
tag_name: $CI_COMMIT_TAG
description: './CHANGELOG.md'
assets:
links:
- name: 'binary-linux-amd64'
url: 'https://example.com/releases/$CI_COMMIT_TAG/binary-linux-amd64'
- name: 'binary-darwin-arm64'
url: 'https://example.com/releases/$CI_COMMIT_TAG/binary-darwin-arm64'推送一个语义化版本标签(如 v1.2.0),GitLab 会自动创建一个 Release 条目,包含 Release Notes 和资产链接。
七、综合示例:Monorepo 的模块化 CI/CD 架构
my-monorepo/
├── .gitlab-ci.yml
├── ci/
│ ├── workflow.yml # workflow:rules
│ ├── common.yml # extends 基类
│ ├── frontend/
│ │ ├── build.yml
│ │ ├── test.yml
│ │ └── deploy.yml
│ └── backend/
│ ├── build.yml
│ ├── test.yml
│ └── deploy.yml# .gitlab-ci.yml
include:
- local: '/ci/workflow.yml'
- local: '/ci/common.yml'
- local: '/ci/frontend/build.yml'
- local: '/ci/frontend/test.yml'
- local: '/ci/frontend/deploy.yml'
- local: '/ci/backend/build.yml'
- local: '/ci/backend/test.yml'
- local: '/ci/backend/deploy.yml'
stages:
- build
- test
- deploy-staging
- deploy-prod# ci/common.yml
.frontend-base:
image: node:20-alpine
before_script:
- cd frontend && npm ci
rules:
- changes:
- frontend/**/*
.backend-base:
image: golang:1.22
before_script:
- cd backend
rules:
- changes:
- backend/**/*# ci/frontend/deploy.yml
deploy-frontend-staging:
extends: .frontend-base
stage: deploy-staging
script: npm run deploy:staging
environment:
name: staging
url: https://staging.example.com八、小结与下篇预告
配置工程化路径
单个 .gitlab-ci.yml # 入门
↓
include:local 按阶段拆分 # 模块化
↓
extends 消除重复 # DRY 原则
↓
include:project 跨项目复用 # 组织级共享
↓
include:component 发布到目录 # 生态化下篇预告
理论和方法论已全部就位。第六篇《实战场景 + 排错 + 最佳实践》是本系列的收官之作——我们不再讲解新的关键词,而是给你拿来即用的场景模板(Node.js / Java / Docker / Monorepo)、常见错误的排查指南,以及经过验证的最佳实践清单。
参考资料: