2. GitLab CI/CD核心机制精讲
理解 GitLab CI/CD,关键不是记住一堆名词,而是弄清一次提交之后,GitLab 到底按什么顺序、把什么交给谁、在哪里执行、执行结果又如何回到仓库。本节围绕八个核心对象展开:Pipeline 是整条流水线的总编排,Stage 是执行阶段,Job 是最小执行单元,Runner 是执行代理,Executor 是 Runner 内部真正跑任务的运行环境,Artifacts 是产物,Cache 是缓存,变量体系则贯穿始终,决定每个 Job 拿到什么上下文。
一、从一次 push 到流水线启动
当开发者向 GitLab 推送代码或创建合并请求时,GitLab 会读取仓库根目录下的 .gitlab-ci.yml,解析出 Pipeline 结构。Pipeline 不是“一个脚本”,而是一张编排图:它包含若干 Stage,每个 Stage 下挂若干 Job。默认情况下,同一 Stage 内的 Job 并行执行,不同 Stage 按声明顺序串行推进,只有前一个 Stage 全部成功,后一个 Stage 才会开始。
例如下面这段配置定义了三阶段流水线:
stages:
- build
- test
- deploy
build-app:
stage: build
script:
- echo "compiling..."
- mkdir -p dist && echo "app-binary" > dist/app.bin
artifacts:
paths:
- dist/
test-unit:
stage: test
script:
- test -f dist/app.bin && echo "unit test pass"
deploy-staging:
stage: deploy
script:
- echo "deploy to staging"
only:
- main
这里 build-app 属于 build 阶段,test-unit 属于 test 阶段,deploy-staging 属于 deploy 阶段。Pipeline 会先跑 build,再跑 test,最后跑 deploy。若 test-unit 失败,deploy 阶段不会启动。
二、Runner 与 Executor:任务到底在哪里跑
Job 本身只是“要做什么”的描述,真正执行它的是 Runner。Runner 是安装在某台机器或某个集群上的代理进程,它向 GitLab 注册后,持续轮询是否有可领取的 Job。领取到 Job 后,Runner 根据自身配置选择一个 Executor 来执行。
Executor 决定执行环境形态,常见类型包括:
- shell:直接在当前主机 shell 中执行,速度快,但环境隔离弱。
- docker:每个 Job 启动一个容器,环境干净、可复现,是最常用方式。
- docker+machine:在 docker 基础上自动创建和销毁云主机,适合弹性扩容。
- kubernetes:每个 Job 作为一个 Pod 运行,适合已有 K8s 的团队。
假设 Runner 配置为 docker executor,并指定镜像 alpine:3.19,那么 build-app 的 script 实际是在一个临时 alpine 容器里执行的。容器结束后默认销毁,因此 Job 之间不会自动共享文件系统,这正是 Artifacts 和 Cache 存在的意义。
三、Artifacts 与 Cache:两种“传递”机制
Artifacts 和 Cache 都涉及文件传递,但目的完全不同。Artifacts 是 Job 的产出物,用于后续 Stage 消费。例如 build-app 把 dist/ 声明为 artifacts,那么 test-unit 和 deploy-staging 默认会自动下载这份产物,从而拿到 dist/app.bin。Artifacts 上传到 GitLab 服务器,可在 Job 页面下载,也可设置 expire_in: 1 week 控制保留时间。
Cache 则是为了加速,不保证存在。典型场景是缓存 node_modules/ 或 .m2/repository。Cache 按 key 匹配,key 可以基于分支、文件哈希或固定字符串。若 key 不匹配或缓存被清理,Job 仍应能正常执行,只是会慢一些。因此,Artifacts 用于“必须传递”,Cache 用于“尽量复用”,二者不可混用。
四、变量体系:Job 的上下文来源
变量决定 Job 在运行时能读到什么。GitLab 变量按优先级从低到高大致为:预定义变量、项目/组/实例级变量、.gitlab-ci.yml 中定义的变量、Job 级变量、Pipeline 触发时传入的变量。高优先级覆盖低优先级。
预定义变量由 GitLab 自动注入,例如 CI_COMMIT_BRANCH 表示当前分支,CI_PIPELINE_ID 表示流水线编号,CI_JOB_STAGE 表示当前阶段。自定义变量可在项目 Settings → CI/CD → Variables 中配置,也可在 YAML 中声明:
variables:
APP_ENV: staging
REGISTRY: registry.example.com
deploy-staging:
stage: deploy
variables:
APP_ENV: staging-deploy
script:
- echo "env=$APP_ENV registry=$REGISTRY branch=$CI_COMMIT_BRANCH"
该 Job 中 APP_ENV 被 Job 级变量覆盖为 staging-deploy,而 REGISTRY 继承全局值。若变量包含密钥,应勾选 Protected 和 Masked,避免日志泄露。
五、关键判断:一次流水线如何推进
把上述机制串起来看:GitLab 解析 YAML 得到 Pipeline 与 Stage 顺序;Runner 领取 Job 后按 Executor 创建执行环境;Job 运行时读取变量、执行 script;成功后上传 Artifacts、按需写入 Cache;下一 Stage 的 Job 下载 Artifacts 继续执行。若任一 Job 失败,后续 Stage 默认阻塞,除非配置 allow_failure: true 或 when: manual。
掌握这八个对象及其关系后,后续设计多环境交付时,就能有意识地规划 Stage 边界、Job 粒度、Runner 标签、产物传递路径和变量分层,而不是把所有逻辑堆进一个 Job。