GitLab CI/CD 落地:Runner 注册与流水线模板实战
GitLab CI/CD 落地:Runner 注册与流水线模板实战
上一篇文章里 GitLab 平台已经跑起来了,但开发还在找我手动拉代码、打包、传服务器。有次周五下午发版,我连做了六次”拉码、打包、scp、解压、换软链”,第七次是回滚。当天晚上我就把流水线搭了起来——人肉发布这件事,重复三次以上就该交给机器。
一、GitLab CI 的基本模型
GitLab CI/CD 的逻辑不复杂:
- 代码仓库里放一个
.gitlab-ci.yml文件,描述”要做什么”; - Runner 是执行这些任务的代理,注册到 GitLab 之后领任务、干活、回报结果;
- 推送代码或创建 MR 触发流水线,按阶段顺序执行。
三个角色的分工:GitLab 负责调度,Runner 负责执行,yml 文件负责定义流程。运维的活主要在两块:把 Runner 管好,把 yml 模板写好给开发用。开发不需要懂 Runner 装在哪,只要知道”推代码之后跑去哪看结果”。
二、Runner 的注册与执行器选择
Runner 可以注册在三个级别:项目级、组级、实例级。项目级最省事,实例级最通用,企业里一般按”组级 + 标签区分用途”来铺。
1 | # 1. 注册(在 Runner 所在机器上执行) |
执行器(executor)的选择我踩过一次坑,值得展开说:
| 执行器 | 特点 | 适用场景 |
|---|---|---|
| shell | 直接跑在 Runner 机器上,起步最快 | 简单构建,但环境互相污染 |
| docker | 每个任务一个容器,环境隔离 | 大多数场景推荐 |
| kubernetes | 跑在 K8s 集群里,弹性扩缩 | 大型团队、构建量大 |
一开始我用 shell 执行器图省事,结果两个项目依赖的 Node 版本打架,构建时好时坏。换成 docker 执行器之后,每个任务生成一个干净容器,这类玄学问题直接消失。”环境隔离”这四个字,值这一次改造。
给 Runner 打标签是为了分流:镜像构建的活儿给标签 build 的 Runner,部署任务给标签 deploy 的 Runner——生产部署的 Runner 可以放到内网、单独配权限,构建的放外边跑,互不影响。
1 | # 2. 状态检查三连,排障时常用 |
三、.gitlab-ci.yml 模板逐段拆解
这份模板是给开发的标准件,我一般直接放进项目根目录:
1 | stages: # 流水线阶段,按顺序执行 |
几个关键点:
stages定义阶段顺序,同一阶段的 Job 并行,前一阶段全绿才进下一阶段;tags决定这个 Job 由哪台 Runner 执行,写错标签的直接后果是任务一直挂着不跑——这是新人最常问的”为什么流水线卡住了”的原因之一;only: main限定触发分支,避免 feature 分支一推就触发部署;when: manual给生产部署加一道人工闸门,点一下才执行。
镜像标签用 $CI_COMMIT_SHORT_SHA 是我坚持的规范:每次构建的镜像都可以追溯到具体提交,出问题能精确定位到”哪一次构建、哪一次提交”,比 latest 标签靠谱得多。
四、变量与密钥管理
1 | # 项目 → Settings → CI/CD → Variables |
三条红线:
- 敏感信息一律走 CI/CD Variables,禁止写死在
.gitlab-ci.yml里——yml 是跟代码一起进仓库的,写密码等于把密码提交进 git 历史; - 变量勾 Protected 之后,只有保护分支上的流水线能读到,feature 分支拿不到生产凭据;
- Masked 让日志自动打码,但别依赖它——调试时
echo $DB_PASSWORD这种动作一旦习惯化,迟早出事。
五、日常运维的三个高频问题
Runner 离线。处理顺序:gitlab-runner status 看进程 → gitlab-runner verify 测连通 → 检查机器负载和网络到 GitLab 的通路 → 确认注册 token 没被清理。最隐蔽的一种是 token 被管理员重置后没重新注册,表现是”进程在跑但一直不领任务”。
流水线卡住不执行。先看是不是 tags 写错或者对应 Runner 全忙:Runner 的并发数(config.toml 里的 concurrent)是固定的,一个 Runner 同时只接有限个任务,构建高峰时会排队。第二个常见原因是磁盘满——Runner 机器被构建缓存和镜像撑爆,任务起不来。
构建慢。三个方向:加 cache 关键字缓存依赖目录;换更大的 Runner 机器;给 Docker 配镜像加速。构建时间从 8 分钟压到 3 分钟那次,主要收益就来自依赖缓存。
小结
GitLab CI 落地就三件事:Runner 用 docker 执行器保证环境干净、yml 模板把阶段和触发条件写死、密钥全部进 Variables。这三步做完,开发侧的体验就是”推代码 → 看结果”,运维侧也不用再当人肉发布机。


