作者前言 :这是一篇面向初学者、兼顾进阶实践的 GitLab CE(Community Edition,社区版)CI/CD 学习手册。我会把"是什么 / 怎么搭 / 怎么写 / 怎么避坑"串成一条线,重点讲清楚那些官方文档里分散、教程里常被一笔带过、却恰恰决定你流水线是否好用的关键点。全文图文并茂,配流程图、可执行示例与官方 URL,可直接跟着做。
环境约定:GitLab CE 自建实例(Omnibus 安装),GitLab Runner 注册采用 GitLab 15.10+ 的 authentication token 流程 (
glrt-前缀)。本文写作时参考 GitLab 17.x 文档,旧版本个别关键字(如only/except)已标记废弃。
目录
- [为什么要学 GitLab CI/CD](#为什么要学 GitLab CI/CD)
- [核心概念全景:Pipeline / Stage / Job / Runner](#核心概念全景:Pipeline / Stage / Job / Runner)
- [GitLab CE 的安装与 CI/CD 前置配置](#GitLab CE 的安装与 CI/CD 前置配置)
- [安装并注册 GitLab Runner](#安装并注册 GitLab Runner)
- [
.gitlab-ci.yml完全入门](#.gitlab-ci.yml 完全入门) - [第一个完整流水线(Node.js 示例)](#第一个完整流水线(Node.js 示例))
- 进阶关键字与实战技巧
- [Cache 与 Artifacts:最容易混淆的一对](#Cache 与 Artifacts:最容易混淆的一对)
- [Deploy(部署)与 Environment](#Deploy(部署)与 Environment)
- 常见报错与调试秘籍
- [CE 与 EE 的功能边界(选型必读)](#CE 与 EE 的功能边界(选型必读))
- 学习路线与参考资源
1. 为什么要学 GitLab CI/CD
很多团队用过 Jenkins、GitHub Actions,但对 GitLab 内置的 CI/CD 望而却步。其实 GitLab CI/CD 最大的优势是"一体化":代码仓库、Merge Request、Issue、Runner、流水线全在一个产品里,不需要 Webhook 对接、不需要额外账号、不用装插件。
一句话定义:
GitLab CI/CD 是一套内置的持续集成 / 持续交付引擎。你在仓库根目录放一个
.gitlab-ci.yml,每次git push或创建 MR 时,GitLab 自动按它定义的流程跑构建、测试、部署。
它的几个"独到价值":
- 流水线即代码(Pipeline as Code) :所有流程写在
.gitlab-ci.yml里,随代码一起版本化、一起走 MR 评审。改流水线本身也要经过 Code Review------这是质量保障常被忽视的一环。 - 原生集成 MR:测试不通过,MR 就被挡住无法合并,天然形成质量门禁。
- Runner 可私有化:自建 Runner 跑在自家机器 / K8s 上,敏感代码不出内网(这对金融、政务场景尤其关键)。
💡 独到见解 :很多教程把 CI/CD 讲成"自动跑测试"。真正成熟的理解是------CI/CD 是"把软件交付的每一个人为动作都变成可重复、可回滚的代码" 。从这个角度看,
.gitlab-ci.yml不是配置文件,而是你团队交付流程的"可执行说明书"。
2. 核心概念全景:Pipeline / Stage / Job / Runner
先建立整体心智模型,后面每学一个关键字都"知道它属于哪一层"。

图 1:从 git push 到部署的完整链路。GitLab 服务端负责编排,Runner 负责执行,Cache/Artifacts 负责数据流转。
四个核心概念,层层包含:
| 概念 | 类比 | 说明 |
|---|---|---|
| Pipeline(流水线) | 一条完整的"交付流程" | 一次触发(push / MR / schedule)产生一条 Pipeline |
| Stage(阶段) | 流程中的大步骤 | 如 build → test → deploy,Stage 之间串行 |
| Job(作业) | 一个具体任务 | 如 unit-test、build-docker,同一 Stage 内的 Job 并行 |
| Runner(执行器) | 干活的工人 | 真正执行 Job 的进程,由 Executor(docker/shell/k8s 等)决定运行环境 |
🌟 关键认知 :Stage 串行、Job 并行------这是理解执行顺序的"第一性原理"。比如
test阶段挂了,后面的deploy默认就不会跑。
层级关系见图 2:

图 2:Pipeline → Stage → Job 的包含关系。同一 Stage 内多个 Job 并行(受 Runner 并发数约束)。
一次完整流程的时序:
开发者 git push
↓
GitLab 读取 .gitlab-ci.yml,创建 Pipeline
↓
按 stages 顺序:build → test → deploy
↓ (每个 stage 内的 jobs 并行)
Runner 领取 Job,在指定镜像/环境中执行 script
↓
成功 → 进入下一 stage;失败 → 流水线终止(可配置 allow_failure)
↓
deploy 完成 → 部署到目标环境
更多必须掌握的术语:
- Executor :Runner 运行 Job 的方式。
docker(推荐,隔离好)、shell(直接跑在宿主机)、kubernetes(云原生)等。 - Artifact / Cache:产物与缓存,详见第 8 章。
- Variable(变量) :可在 UI 或 YAML 中定义的键值对,敏感信息(Token、密码)务必用 CI/CD Variables(支持 masked & protected)。
3. GitLab CE 的安装与 CI/CD 前置配置
本手册聚焦 CI/CD,安装部分仅给出最小可用路径。生产部署请参考官方文档做资源规划与备份。
3.1 安装 GitLab CE(Omnibus 一键包)
官方推荐 Omnibus 包(所有组件打包在一起)。以 Ubuntu/Debian 为例:
bash
# 安装依赖
sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates
# 添加 GitLab 包仓库
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
# 安装 CE(EXTERNAL_URL 改成你的域名/IP)
sudo EXTERNAL_URL="https://gitlab.example.com" apt-get install gitlab-ce
安装完成后访问 https://gitlab.example.com,设置 root 密码即可。
- 📖 官方安装文档:https://about.gitlab.com/install/
- 📖 Omnibus 配置:
/etc/gitlab/gitlab.rb,改完记得sudo gitlab-ctl reconfigure。
3.2 开启 CI/CD 并注册 Runner
新版本 GitLab 中,Runner 采用新式的 "authentication token" 流程(Project / Group / Instance 三级):
- 进入项目:Settings → CI/CD → Runners → New project runner
- 选择操作系统(Linux/macOS/Windows)
- 复制生成的 token(形如
glrt-xxxxxxxx)------这是 15.10+ 推荐方式 - 用该 token 注册 Runner(见第 4 章)
⚠️ 版本注意 :旧式的 Registration Token 已在 15.6 废弃,并将在 GitLab 18.0 移除 。网上大量老教程用的
--registration-token参数在新版会报错410 Gone。新部署请一律使用 authentication token(--token glrt-xxx)。
4. 安装并注册 GitLab Runner
GitLab Runner 是一个独立程序(Go 二进制),建议装在独立于 GitLab 服务端的机器上,避免抢资源。
4.1 安装 Runner
bash
# Linux (Ubuntu/Debian)
curl -sS https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner
# 验证
gitlab-runner --version
- 📖 Runner 安装文档:https://docs.gitlab.com/runner/install/
4.2 注册 Runner(非交互模式,推荐)
bash
sudo gitlab-runner register \
--non-interactive \
--url "https://gitlab.example.com/" \
--token "glrt-xxxxxxxxxxxxxxxxxxxx" \
--executor "docker" \
--docker-image "alpine:latest" \
--description "docker-runner" \
--tag-list "docker,linux" \
--run-untagged="true" \
--locked="false"
参数说明:
| 参数 | 含义 |
|---|---|
--url |
GitLab 实例地址 |
--token |
上一步复制的 authentication token(glrt- 前缀) |
--executor |
执行器类型:docker / shell / kubernetes 等 |
--docker-image |
兜底镜像(YAML 未指定时用它) |
--tag-list |
Job 通过 tags: 匹配到该 Runner |
配置写入 /etc/gitlab-runner/config.toml。
4.3 Executor 怎么选?(独到建议)
| Executor | 隔离性 | 适用场景 |
|---|---|---|
| docker ✅推荐 | 强(每 Job 一个干净容器) | 绝大多数构建、测试 |
| shell | 无(直接跑宿主机) | 需要访问宿主机硬件/特定编译器、GPU |
| kubernetes | 很强 | 云原生、大规模弹性 |
| docker+machine | 强+弹性 | 需要自动伸缩的大团队 |
💡 经验之谈:
- 学习与中小团队首选
dockerexecutor------环境干净、可复现,CI 结果不受宿主机污染。- 永远不要 把不可信代码用
shellexecutor 跑在同一台机器上------Job 能以gitlab-runner用户权限读取该用户可见的一切。- 生产如需自动伸缩,考虑
docker-machine或 Kubernetes executor。
4.4 启动与验证
bash
sudo gitlab-runner start
sudo gitlab-runner list # 查看已注册 Runner
回到 GitLab 页面 CI/CD → Runners ,应能看到 Runner 处于 Online 绿色状态。
5. .gitlab-ci.yml 完全入门
所有流水线逻辑都写在这个文件里,放在仓库根目录。GitLab 会在每次触发时自动读取它。
5.1 最小可用示例
yaml
# .gitlab-ci.yml
stages:
- test
run-tests:
stage: test
image: node:20
script:
- npm install
- npm test
推送后,GitLab 自动创建 Pipeline 并执行。入门要点:
stages:声明阶段列表,有顺序。stage: test:把 Job 归入某个阶段。image:Job 运行的 Docker 镜像(用dockerexecutor 时)。script:要执行的 shell 命令列表(这是唯一必填字段)。
5.2 关键字的"分类地图"(记忆框架)
与其死记关键字,不如按"职责"分类理解:
| 类别 | 关键字 | 作用 |
|---|---|---|
| 结构 | stages, workflow |
定义流水线骨架 |
| Job 基础 | script, stage, image, before_script, after_script |
定义"做什么" |
| 控制执行 | rules, when, needs, dependencies, allow_failure, retry |
定义"何时/如何做" |
| 数据传递 | cache, artifacts, dependencies |
定义"数据怎么流" |
| 环境/部署 | environment, deploy |
定义"部署到哪" |
| 复用 | default, variables, include, extends, !reference |
定义"如何复用/参数化" |
🌟 独到见解 :把 YAML 当成"声明式编程"来读------你描述期望的最终状态(要跑哪些 job、在什么条件下、产出什么),而不是写一堆 if/else 脚本 。遇到复杂逻辑时,优先用
rules、needs、extends,而不是塞进一个巨大的script。
6. 第一个完整流水线(Node.js 示例)
下面是一个生产级可参考的 Node.js 项目流水线,覆盖 install → test → build → deploy,包含缓存与产物:
yaml
# .gitlab-ci.yml
stages:
- install
- test
- build
- deploy
variables:
NODE_ENV: test
# ===== 1. 安装依赖(并缓存)=====
install-deps:
stage: install
image: node:20
script:
- npm ci
cache:
key:
files:
- package-lock.json
paths:
- node_modules/
artifacts:
paths:
- node_modules/
expire_in: 1 hour
# ===== 2. 测试阶段(两个 Job 并行)=====
lint:
stage: test
image: node:20
script:
- npm run lint
needs: [install-deps] # 不等待前一 stage,直接按依赖跳转
unit-test:
stage: test
image: node:20
script:
- npm run test:unit -- --coverage
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
when: always # 即使失败也收集报告
# ===== 3. 构建 =====
build-prod:
stage: build
image: node:20
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 day
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_BRANCH == "develop"'
# ===== 4. 部署(按分支区分环境)=====
deploy-staging:
stage: deploy
image: alpine:latest
script:
- echo "Deploy to staging..."
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com
rules:
- if: '$CI_COMMIT_BRANCH == "develop"'
deploy-production:
stage: deploy
image: alpine:latest
script:
- echo "Deploy to production..."
- ./deploy.sh prod
environment:
name: production
url: https://www.example.com
when: manual # 需手动点击触发(生产防护)
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
这个例子里的"干货"讲解
needs:打破 stage 串行 :lint只需install-deps完成即可开始,不必等install阶段所有 job 结束------缩短总耗时。rules:控制部署环境:develop 分支 → 预发,main 分支 → 生产。when: manual:生产部署必须人工确认,避免误发。cache+artifacts双管齐下 :cache加速依赖安装,artifacts把node_modules/dist可靠传递给后续 job。
📖 YAML 关键字完整参考:https://docs.gitlab.com/ci/yaml/
7. 进阶关键字与实战技巧
7.1 rules ------ 控制 Job 何时运行(取代 only/except)
rules 是现代 GitLab CI 的核心控制流 。它由一组 if 规则组成,从上到下匹配:
yaml
deploy:
script: echo "deploy"
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"' # 定时流水线
when: manual
allow_failure: true
- if: '$CI_COMMIT_BRANCH == "main"' # main 分支:正常跑
- if: '$CI_COMMIT_TAG' # 打 tag 也跑
- when: never # 其余情况:跳过
常用内置变量:
| 变量 | 含义 |
|---|---|
$CI_COMMIT_BRANCH |
当前分支名 |
$CI_DEFAULT_BRANCH |
项目默认分支(推荐用这个代替硬编码 main) |
$CI_COMMIT_TAG |
若为 tag 则非空 |
$CI_PIPELINE_SOURCE |
触发来源:push / merge_request_event / schedule / web 等 |
$CI_MERGE_REQUEST_IID |
MR 编号(用于区分 MR 流水线) |
⚠️ 重要 :
only/except已进入维护模式,官方明确建议迁移到rules。rules表达能力更强(支持正则=~、变量判断、组合条件)。
- 📖 rules 官方文档:https://docs.gitlab.com/ci/jobs/job_rules/
- 📖 Job 控制:
rulesvsonly/except:https://docs.gitlab.com/ee/ci/jobs/job_control.html
rules vs only/except 迁移示例(官方等价写法):
yaml
# 旧写法(废弃)
job:
only:
- main
- /^release-.*$/
- schedules
# 新写法(推荐)
job:
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_COMMIT_BRANCH =~ /^release-.*$/'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
7.2 needs + dependencies ------ 有向无环图(DAG)加速
默认流水线按 stage 串行。用 needs 可以声明 Job 间依赖,GitLab 会构建 DAG,不依赖的 Job 立即并行:
yaml
unit-test:
stage: test
needs: [install-deps] # 只等 install-deps,不等整个 install 阶段
dependencies 则控制"从哪些 Job 下载 artifacts"。
7.3 extends / !reference ------ 复用,别复制粘贴
yaml
.default-job:
image: node:20
before_script:
- npm ci
test-a:
extends: .default-job
script: [npm run test:a]
test-b:
extends: .default-job
script: [npm run test:b]
💡 独到建议 :把"公共部分"抽成
.base(带点号前缀表示隐藏 Job,不会被执行),团队规范由此落地。这是把流水线从"能跑"变成"可维护"的分水岭。
7.4 default ------ 全局默认值
yaml
default:
image: node:20
retry: 1
timeout: 10 minutes
7.5 include ------ 拆分大型配置
把公共 CI 模板抽到单独文件甚至独立仓库,用 include 引入------适合多项目共享规范。
8. Cache 与 Artifacts:最容易混淆的一对
这是新手踩坑最密集的地方。看图理解:

图 3:左上为 rules 决策逻辑;下方对比 Cache 与 Artifacts。
8.1 一张表彻底分清
| 维度 | Cache(缓存) | Artifacts(产物) |
|---|---|---|
| 目的 | 加速(保存依赖) | 跨 stage 传递文件 |
| 典型内容 | node_modules/、.npm/、.gradle/ |
构建包、测试报告、覆盖率 |
| 可靠性 | 尽力而为,可能被回收 | 可靠,上传到 GitLab |
| 作用域 | 项目内跨 pipeline 共享(默认) | 同一条 pipeline 内跨 job |
| 过期 | 按 cache policy | expire_in(默认 30 天) |
| 口诀 | 可丢的优化 | 后续依赖的数据 |
8.2 Cache 最佳实践
yaml
cache:
key:
files:
- package-lock.json # lock 文件变 → 缓存 key 变 → 重建
paths:
- node_modules/
- 把
key绑定到 lock 文件:依赖不变就复用缓存,变了就重建,兼顾速度与正确性。 - 用
policy: pull-push/pull/push精细控制某 job 只拉不推或只推不拉。
8.3 常见误区
❌ 错误 :"用 cache 在 stage 之间传构建产物。"
✅ 正确 :stage 间传递文件用
artifacts,cache 只用于依赖缓存。
原因:cache 是"尽力而为"、可能失效,且缓存与 artifacts 指向同一路径时可能互相覆盖(因为 cache 在 artifacts 之前恢复)。
- 📖 官方缓存文档:https://docs.gitlab.com/ci/caching/
9. Deploy(部署)与 Environment
9.1 environment 关键字
yaml
deploy-prod:
stage: deploy
script: ./deploy.sh prod
environment:
name: production
url: https://www.example.com
配置后,GitLab 侧边栏出现 Deployments → Environments ,可看到每次部署的版本、支持一键回滚(Rollback)。
9.2 部署保护(Protected Environment)
生产环境可在 Settings → CI/CD → Protected environments 设置:只有特定分支/Tag 才能部署。强烈建议给 production 加保护。
9.3 三种部署触发方式
| 方式 | 适用 |
|---|---|
when: manual |
人工审批后点击部署(生产推荐) |
rules + 分支 |
自动部署到对应环境 |
schedule |
定时发布 |
💡 独到建议 :成熟的交付模型是 "自动部署到 staging,人工确认后部署到 production"------把"可自动化"和"必须人拍板"清晰分开。
10. 常见报错与调试秘籍
10.1 This job is stuck or pending...
原因 :没有可用 Runner,或 Runner 的 tag 与 Job 的 tags: 不匹配。
解决:
- 检查 Runner 是否 Online(CI/CD → Runners)
- Job 有
tags: [docker]则 Runner 必须带对应 tag;或用tags: []+ Runner 勾选 "Run untagged jobs"
10.2 fatal: unable to access 'http://...' 克隆失败
原因 :Runner 无法访问 GitLab(网络/DNS)。
解决:确认 Runner 机器能访问 GitLab URL;自签名 HTTPS 需配置证书。
10.3 docker: command not found
原因 :用 docker executor 却没装 Docker,或 shell executor 的 Job 里调用 docker。
解决 :在 Job 中用 image: docker:24-dind + services: [docker:24-dind],并开启 privileged。
10.4 cache: no matching files / 缓存不命中
原因 :key 变化,或缓存被回收。
解决 :检查 key 规则;多 Runner 时配置 分布式缓存(S3 / MinIO) 保证共享。
10.5 调试技巧
- 本地验证 YAML 语法 :项目页 CI/CD → Editor 有内置 Lint。
CI_DEBUG_TRACE=true:在 Variables 里设置,可打印详细执行日志(注意会暴露密钥,用完即删)。rules: - when: manual隔离问题 Job,逐段跑。before_script打印环境 :- env | sort查看可用变量。
11. CE 与 EE 的功能边界(选型必读)
本节帮你在动手前确认:"CE 够不够用?"
GitLab 采用 Open Core(CE 开源免费 + EE 付费增强) 双轨制。CE 永久免费、MIT 协议、可商用。CI/CD 引擎本身在 CE 中已相当完整------内置 Runner、YAML 编排、并行 Job、基础 MR 流水线等核心能力 CE 都具备。
| 能力维度 | GitLab CE(免费) | GitLab EE(付费) |
|---|---|---|
| CI/CD 引擎 | ✅ Runner、YAML、并行 Job | ✅ 增强的流水线拓扑图、跨变量继承 |
| 安全扫描 | ⚠️ 基础 SAST | ✅ SAST/DAST、依赖扫描、License 合规 |
| 高可用 | ❌ 单机(所有服务同机) | ✅ PG/Redis/Gitaly 拆分、多节点 |
| 审计/治理 | ❌ 仅全局操作日志 | ✅ 细粒度审计、IP 白名单、SSO |
| 合规场景 | 需自研补足 | ✅ SOC2 / HIPAA 等 |
🌟 选型建议:
- 个人学习 / 小团队 / 源码不出内网 → CE 完全够用,CI/CD 能力不打折扣。
- 强合规(金融/政务)、需要 DAST/依赖扫描、高可用 → 评估 EE。
- ⚠️ 注意:自 2021 年起 GitLab 逐步把部分协作/治理能力从 CE 迁移到 EE(Open Core Progressive Licensing),且
gitlab.comSaaS 免费层有 CI 分钟数 / 并发数限制。自建 CE 不受分钟数限制(受你自己的硬件限制)。
- 📖 官方功能对比:https://about.gitlab.com/pricing/
12. 学习路线与参考资源
12.1 推荐学习路线
- 跑通最小流水线(第 5 章)→ 建立信心
- 加缓存 + artifacts(第 8 章)→ 提速、解决数据传递
- 用
rules控制环境(第 7、9 章)→ 实现真正的 CD - **抽公共模板(
extends/include)**→ 可维护 - 加保护环境 + 人工审批 → 生产可用
12.2 官方参考资源(建议收藏)
| 资源 | 链接 |
|---|---|
| GitLab 官方文档首页 | https://docs.gitlab.com/ |
| CI/CD 入门(Quick Start) | https://docs.gitlab.com/ci/quick_start/ |
.gitlab-ci.yml 关键字参考 |
https://docs.gitlab.com/ci/yaml/ |
| Runner 注册文档 | https://docs.gitlab.com/runner/register/ |
rules 官方文档 |
https://docs.gitlab.com/ci/jobs/job_rules/ |
| 缓存机制文档 | https://docs.gitlab.com/ci/caching/ |
| GitLab 安装 | https://about.gitlab.com/install/ |
12.3 结语
CI/CD 不是"学会一个工具",而是"建立一套工程纪律"。
GitLab CI/CD 把这套纪律浓缩成一个
.gitlab-ci.yml------它既是自动化脚本,也是团队交付规范的载体。建议你从今天的最小例子开始,每加一个关键字,都想想它解决了什么实际问题 。当你能熟练用rules控制环境、needs编排 DAG、cache/artifacts管理数据、environment做受保护部署时,你就已经超越了"入门",进入了"能设计交付系统"的阶段。祝你在 GitLab CI/CD 的路上越走越顺 🚀