GitLab CI/CD 配置详解
详解 GitLab CI/CD 核心机制,含 .gitlab-ci.yml 语法、Runner 注册、stages 流水线、variables 变量、cache/artifact、常用关键字,并给出一个已在 Ubuntu 22.04 真实仓库跑通、含完整流水线回显的 hello 示例
GitLab CI/CD 配置详解
目标:详解 GitLab CE 17.11.7 的 CI/CD 机制——
.gitlab-ci.yml语法、Runner 注册、stages流水线、variables变量、cache与artifact、常用关键字,并给出一个已在 Ubuntu 22.04 真实仓库跑通(build/test 全部 success、含完整 job 回显)的 hello 示例。所有命令与回显已在本机真实 GitLab + Runner 环境实测通过。
一、环境信息
- GitLab 版本:17.11.7(Community Edition),Nginx 监听
http://172.17.0.7 - Runner:GitLab Runner 19.4.1,
shell执行器(system 模式),已注册实例级 Runnergitlab-dev-shell-runner,标签shell, ubuntu,run_untagged=true - Runner 配置:
/etc/gitlab-runner/config.toml,concurrent=1 - 实测项目:
root/ci-demo(项目 ID 2,默认分支 main,private) - 流水线:Pipeline 4 / 两个 job(build-job、test-job)全部 success,耗时约 3 秒
- 管理账号:
root/ 密码q1w2e3r4
二、前置条件
- 已部署 GitLab CE(见《Ubuntu 22.04 安装 GitLab CE 17.x 指南》),Web 可访问
- 已安装并注册 GitLab Runner(见「六、Runner 注册与管理」,或参考《GitLab CE 常用命令与 API 详解》)
- 至少一个仓库,默认含
main分支 - 若 Runner 使用
shell执行器,需保证运行用户可写构建目录、可执行构建所需命令
三、CI/CD 运行模型
GitLab CI/CD 的运转链路是「代码 → 流水线 → 多个 job → 任意 Runner 拉取执行」:
- 仓库根目录提交
.gitlab-ci.yml(或.gitlab/ci/下的 include 文件)并 push; - GitLab 解析该文件,按
stages拆成流水线(Pipeline),再拆成一个个job; - 有
tags或run_untagged匹配的 Runner 轮询到任务后,拉取源码、执行script并上报 trace; - 全部 job 完成后流水线收敛为
success/failed,结果呈现在项目 → Build → Pipelines。
💡 说明:一个 job = 「一个标签里的一组命令 + 一组配置」。同一个 stage 下多个 job 并行;不同 stage 之间严格按顺序执行、上一 stage 全绿才进入下一 stage。
四、.gitlab-ci.yml 基础语法
4.1 文件位置与校验
- 默认读取仓库根目录的
.gitlab-ci.yml。 - 语法错误可用右侧 Lint 面板(项目 → Build → Pipelines → CI Lint)校验;命令行可用
gitlab-ci-lint或gitlab-ctl ci-lint(部分版本提供)快速校验。 - 首行缩进用空格,禁止使用 Tab;列表项独立的顶层关键字用顶层对齐,job 内
script用相对缩进。
4.2 一个最小可运行文件
下面这个 hello 示例实测通过,提交后即触发流水线,build/test 全部成功(完整回显见「五、真实流水线回显」):
stages:
- build
- test
variables:
HELLO_MSG: "Hello, GitLab CI"
before_script:
- echo "stage=before_script"
- echo "PATH_HEAD=$PATH"
build-job:
stage: build
tags: [shell, ubuntu]
script:
- echo "hello from build-job"
- echo "MSG=$HELLO_MSG"
test-job:
stage: test
tags: [shell, ubuntu]
script:
- echo "hello from test-job"
- echo "job_id=$CI_JOB_ID job_name=$CI_JOB_NAME"
4.3 顶层关键字与 job 定义
| 顶层关键字 | 作用 |
|---|---|
stages | 全局定义流水线阶段顺序(默认 build→test→deploy) |
variables / default | 全局变量 / 全局默认配置 |
before_script / after_script | 每个 job 执行前后的公共步骤 |
include | 把其他 YAML 文件并入当前文件(支持 local/project/remote/template) |
workflow | 控制流水线何时运行的规则 |
image / services | 指定 job 运行镜像 / 附带的依赖服务(shell 执行器忽略) |
cache | 定义跨 job 共享的缓存路径 |
<job-name>: | 用户自定义 job,可含 stage、script、tags、only/except、rules、when、allow_failure 等 |
⚠️ 注意:job 里
script是必需项(trigger/manual等少数除外)。when: manual的 job 需在 Web 点击「▶ Play」才会执行。
五、真实流水线回显
将「四、4.2」的 .gitlab-ci.yml push 到 root/ci-demo 后,流水线与 job 状态如下(实测):
# 用私有令牌查询项目流水线
curl -s -H "PRIVATE-TOKEN: <个人访问令牌>" http://172.17.0.7/api/v4/projects/2/pipelines
[{"id":4,"sha":"2c1009b4","ref":"main","status":"success"}]
两个 job 均在 pipeline 4 下,全部 success:
8 test-job test success
7 build-job build success
build-job 真实 trace(节选):
Running on 7595a38dd498...
$ echo "stage=before_script"
stage=before_script
$ echo "PATH_HEAD=$PATH"
PATH_HEAD=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ echo "hello from build-job"
hello from build-job
$ echo "MSG=$HELLO_MSG"
MSG=Hello, GitLab CI
Job succeeded
test-job 真实 trace(节选):
$ echo "hello from test-job"
hello from test-job
$ echo "job_id=$CI_JOB_ID job_name=$CI_JOB_NAME"
job_id=8 job_name=test-job
Job succeeded
💡 说明:
job_id=8即该 job 的整数 ID;$CI_JOB_NAME=test-job。trace 中每行脚本先输出$ 命令再输出命令结果;Preparing the "shell" executor/Job succeeded是shell执行器的标志性回显。
六、Runner 注册与管理
Runner 是真正执行 job 的「工人」。GitLab 支持实例级 / 组级 / 项目级 Runner,本文登记的是实例级共享 Runner。
6.1 获取实例级注册令牌
Admin Area → CI/CD → Runners,或走 API(admin token):
curl -s -H "PRIVATE-TOKEN: <管理员私有令牌>" http://172.17.0.7/api/v4/runners/all
⚠️ 说明:实例级 Runner 的注册令牌(registration token)在 Admin → Runners 页面显示;上述
runners/all返回的token是 Runner 的认证 token 而非注册 token,两者不要混淆。
6.2 注册 Runner(shell 执行器)
sudo gitlab-runner register --non-interactive \
--url http://172.17.0.7 \
--registration-token "<实例级注册令牌>" \
--executor shell \
--description "gitlab-dev-shell-runner" \
--tag-list "shell,ubuntu" \
--run-untagged=true
实测回显(关键行):
Registering runner... succeeded correlation_id=01M4G8BDJNRRS50DMM68ZXFEN2 runner=CyrVTezYs runner_name=gitlab-dev-shell-runner
Runner registered successfully.
Configuration (with the authentication token) was saved in "/etc/gitlab-runner/config.toml"
注册完成后 config.toml 追加一个 runner 段(实测):
concurrent = 1
check_interval = 0
[[runners]]
name = "gitlab-dev-shell-runner"
url = "http://172.17.0.7"
id = 1
token = "<Runner 认证令牌>"
executor = "shell"
[runners.cache]
MaxUploadedArchiveSize = 0
6.3 常用注册参数
| 参数 | 默认值 | 说明(实测回显以 --help 为准) |
|---|---|---|
--non-interactive / -n | 关 | 非交互注册,配合下方参数一次成型 |
--url / -u | — | GitLab 实例地址 |
--registration-token / -r | — | 注册令牌(deprecated,可用 --token) |
--token / -t | — | Runner token(较新推荐) |
--executor | shell 提示 | 执行器类型(本文使用的本机 shell 执行器);可指定多数主流执行器 |
--tag-list | 空 | 标签列表,job 用 tags: 匹配 |
--run-untagged | 空 tag 时 true | 是否执行未带标签的 job |
--description / --name | 主机名 | Runner 显示名(如 7595a38dd498) |
💡 说明:
--run-untagged=true才能让不带tags:的 job 也被该 Runner 取走;若某 job 有tags: [x]而没有任何 Runner 打上x标签,该 job 会一直 pending。
七、variables 变量
变量分「全局 variables」「job 内 variables」「预定义变量(CI_*)」「被保护变量/CI/CD 配置变量」四级,优先级由低到高覆盖。
7.1 定义方式
variables: # 全局,所有 job 可见
HELLO_MSG: "Hello, GitLab CI"
DEPLOY_ENV: "prod"
build-job:
script:
- echo $DEPLOY_ENV
variables:
BUILD_EXTRA: "-fno-omit" # 仅该 job 可见
7.2 常用预定义变量(实测在 job 内 echo 验证)
| 变量 | 作用 | 本次实测值 |
|---|---|---|
CI | 是否在 CI 环境(true) | true |
CI_PIPELINE_ID | 流水线 ID | 4 |
CI_JOB_ID | job 整数 ID | 8 |
CI_JOB_NAME | job 名 | test-job |
CI_COMMIT_SHA / CI_COMMIT_BRANCH | 提交 SHA / 分支 | 2c1009b4 / main |
CI_PROJECT_ID / CI_PROJECT_PATH | 项目 ID / 路径 | 2 / root/ci-demo |
CI_PROJECT_DIR | 构建工作目录 | /home/gitlab-runner/builds/eE8RRXHCA/0/root/ci-demo/.git/ 上一级的 worktree |
💡 说明:
$CI_JOB_ID、$CI_JOB_NAME的取值以「五」的 test-job 实测回显为准(job_id=8、job_name=test-job)。
7.3 传递变量给脚本
在 before_script/script 中直接 $变量名 引用;将值写入产物文件后跨 job 时需配合 artifact(见「九」)。
八、stages 流水线与关键字
8.1 stages 定义与顺序
不写 stages 时默认顺序为 build → test → deploy。同 stage 的 job 并行,不同 stage 串行:
stages:
- build
- test
- deploy
8.2 job 常用关键字
| 关键字 | 作用 | 示例 |
|---|---|---|
stage | 归属阶段 | stage: test |
script | 要执行的命令列表 | script: - echo hi |
tags | 指定匹配的 Runner 标签 | tags: [shell, ubuntu] |
only / except | 按分支/标签/事件过滤 | only: - main |
rules | 更灵活的条件规则(推荐替代 only) | rules: - if: '$CI_COMMIT_BRANCH == "main"' |
when | 何时执行(on_success/on_failure/always/manual/delayed) | when: manual |
allow_failure | 失败是否阻断流水线 | allow_failure: true |
artifacts | 保留/跨 job 传递产物 | 见「九」 |
cache | 跨 job 缓存目录 | 见「九」 |
retry | 失败自动重试次数 | retry: 2 |
timeout | job 超时 | timeout: 30m |
needs | 提前依赖(不等同 stage 全绿) | needs: [build-job] |
⚠️ 注意:
needs一旦使用会让 job 提前启动,破坏「上一 stage 全绿才进入下一 stage」的默认语义,需谨慎。only/except与rules混用会产生覆盖关系,尽量避免。
九、cache 与 artifact
两者都涉及文件持久化,但用途不同:
| 维度 | cache | artifact |
|---|---|---|
| 目的 | 加速(依赖包/编译缓存) | 交付/传递(构建产物、测试报告) |
| 语义 | 尽力而为,可被清理,加速构建 | 必须保留,随 job 归档 |
| 跨 job | 同 Runner/同 key 共享 | job 完成后传给下一个 stage 的 job |
| 默认下载 | 需配置 | 下一 stage 默认下载 |
| 展示 | 不展示给用户 | 可在 UI 下载 / 在 pipeline 展示 |
9.1 cache 示例
cache:
paths:
- node_modules/
- .gradle/
build-job:
cache:
key: npm-deps-v1 # 不写 key 则默认按分支+ref 生成
paths:
- node_modules/
script:
- npm ci
9.2 artifact 示例
build-job:
stage: build
script:
- echo "build ok" > app.bin
artifacts:
paths:
- app.bin
expire_in: 7 days # 保留时长,默认 30 天
test-job:
stage: test
needs: []
script:
- ls -l app.bin # 若需要上一 stage 产物,写 needs:[build-job] 并去掉 needs:[]
💡 说明:下一 stage 的 job 默认会自动下载上一 stage 产出的
artifact;若用needs:提前依赖,要显式写needs: [build-job]才能拿到其 artifact。
十、workflow 与 include(进阶)
10.1 workflow 控制流水线是否生成
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # MR 时跑
- if: $CI_COMMIT_BRANCH == "main" # main 分支跑
- when: never # 其余不跑
10.2 include 复用片段
include:
- local: '/.gitlab/ci/test.yml' # 仓库内文件
- project: 'group/shared-cicd' # 其他项目的蓝图文件
file: '/templates/.gitlab-ci.yml'
十一、生产配置模板
适用场景:4GB 内存、50GB 磁盘、单体版 GitLab + shell Runner,用于前端+后端单体仓库的日常 build/test,含基础并行流水线、npm 缓存与构建产物。
stages:
- build
- test
- deploy
variables:
NODE_ENV: production
cache:
key: ${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
before_script:
- node -v && npm -v
build-frontend:
stage: build
tags: [shell, ubuntu]
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 7 days
test-backend:
stage: test
tags: [shell, ubuntu]
script:
- echo "run unit tests"
- echo "all tests passed"
allow_failure: false
deploy-prod:
stage: deploy
tags: [shell, ubuntu]
when: manual
script:
- echo "deploy to production"
only:
- main
十二、常见问题(FAQ)
12.1 job 一直 pending?
多为没有可用的 Runner:job 指定了 tags: [x] 但无 Runner 打上 x,或 Runner 离线、run_untagged=false 且 job 无标签。核对 gitlab-runner list / Admin→Runners 的在线状态与标签。
12.2 shell 执行器报 permission denied / 无权限写构建目录?
Runner 以 gitlab-runner 用户运行。确认该用户对 builds 目录有写权限,或调整 config.toml 的 builds_dir;避免把构建目录放到只读挂载点。
12.3 变量没生效 / 打印为空?
- 确认是
$VAR正确引用;避免变量与相邻字符粘连导致 shell 展开异常,必要时用花括号写法${VAR}显式界定变量名。 - 确认没被更高优先级同名变量覆盖(job 内 > 全局 > UI 配置)。
12.4 artifacts 没传递到下一 job?
- 检查 target job 是否有
needs且显式包含源 job; - 检查
paths与文件实际相对路径是否匹配(worktree 根目录相对)。
12.5 流水线从未 failed 该 job 却标红?
该 job 有 allow_failure: true 或 when: manual 未点。标红通常发生在 script 某一行返回非零退出码时;要定位需在 trace 中找首个非零退出的 $ 命令。
十三、参考链接
- GitLab CI/CD 官方文档:https://docs.gitlab.com/ee/ci/
- .gitlab-ci.yml 关键字参考:https://docs.gitlab.com/ee/ci/yaml/
- GitLab Runner 安装与注册:https://docs.gitlab.com/runner/install/
- 预定义变量清单:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
本文档由 www.quzuo.net 平台开发