2. GitLab Runner 部署与注册

在 GitLab CI/CD 中,流水线的定义写在 .gitlab-ci.yml 里,但真正把 script 跑起来的,是 GitLab Runner。Runner 是一个独立于 GitLab 服务端的进程,它主动向 GitLab 拉取待执行的作业(Job),在本地或容器中执行,再把日志和结果回传。理解 Runner 的类型、安装注册方式、标签与并发控制,以及不同执行器的差异,是搭建自动化测试与发布流水线的基础。

一、Runner 类型:共享、专用与群组

从归属范围看,Runner 主要分为三类。共享 Runner(Shared Runner)由 GitLab 管理员注册,所有项目都可以使用,适合小团队快速起步,但资源竞争激烈、环境不可控。专用 Runner(Specific Runner)注册到某个具体项目,只服务该项目,适合需要特定依赖、特定网络或特定硬件的场景。群组 Runner(Group Runner)注册到某个群组,群组下所有项目共享,是介于两者之间的折中方案,常用于一个团队维护多个微服务仓库的情况。

选择原则很直接:如果作业需要访问内网数据库、需要 GPU、需要 macOS 或 Windows 环境,或者需要缓存大量依赖,就应该使用专用或群组 Runner;如果只是跑轻量的单元测试和构建,共享 Runner 足够。实际生产中常见的是“共享 Runner 跑通用任务 + 专用 Runner 跑部署和集成测试”的混合模式。

二、安装与注册

以 Linux 上安装 GitLab Runner 为例,官方仓库方式最稳妥:

# 添加官方仓库并安装
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner

# 查看版本,确认安装成功
gitlab-runner --version

安装完成后需要注册。注册的本质是把 Runner 与 GitLab 实例建立信任关系,并给它分配标签和执行器。注册前先在 GitLab 项目或群组的 Settings → CI/CD → Runners 中获取注册令牌(Registration Token)。注册命令如下:

sudo gitlab-runner register \
  --url "https://gitlab.example.com/" \
  --registration-token "GR1348941xxxxxxxxxxxx" \
  --executor "docker" \
  --docker-image "alpine:latest" \
  --description "docker-runner-for-test" \
  --tag-list "docker,test,linux" \
  --run-untagged="false" \
  --locked="false"

其中 --tag-list 决定这个 Runner 能接哪些作业,--run-untagged 决定是否接受没有标签的作业。注册成功后,配置文件通常位于 /etc/gitlab-runner/config.toml,可以在这里调整并发数、缓存目录等参数。

三、标签与并发控制

标签(Tag)是作业与 Runner 之间的匹配规则。在 .gitlab-ci.yml 中给作业写 tags: [docker, test],GitLab 只会把该作业派发给同时带有这两个标签的 Runner。标签设计要避免过细或过粗:过细会导致某个 Runner 空闲而其他作业排队,过粗则会让不合适的作业落到错误环境上。常见做法是按“执行器类型 + 操作系统 + 用途”三层命名,例如 docker、linux、deploy。

并发控制有两个层面。第一层是 Runner 级别的 concurrent,写在 config.toml 的 [runners] 段或全局段,表示该 Runner 进程最多同时执行多少个作业。第二层是单个 Runner 的 limit,限制某个具体 Runner 配置能同时跑几个作业。如果一台机器 CPU 是 8 核,跑 Docker 执行器时通常把 concurrent 设为 4 到 8,具体取决于每个作业的资源消耗。设置过大反而会因为资源争抢导致作业超时。

如果发现作业一直处于 pending 状态,优先检查三件事:标签是否匹配、Runner 是否在线、concurrent 是否已被占满。

四、执行器差异

执行器(Executor)决定作业在什么环境中运行,是 Runner 配置中最关键的选择。常见执行器对比如下:

执行器隔离性典型用途注意事项
shell无简单脚本、固定机器依赖直接装在宿主机,易污染
docker容器级构建、单元测试需处理镜像拉取与缓存
docker-machine虚拟机级需要独立主机的场景已逐步被替代
kubernetesPod 级弹性伸缩的集群环境配置复杂,依赖 K8s
parallels / virtualbox虚拟机级需要完整 OS 的测试资源开销大

对大多数自动化测试与发布流水线来说,docker 执行器是首选:环境可复现、启动快、清理方便。它的工作方式是每个作业启动一个容器,把仓库代码挂载进去,在容器内执行 script。如果作业需要 Docker 命令本身(例如构建镜像),可以在 config.toml 中挂载 /var/run/docker.sock,或使用 docker:dind 服务,但要注意安全边界。

下面这张图把 Runner 的注册关系、标签匹配与执行器选择串在一起,帮助建立整体认识:

GitLab 服务端 项目 / 群组 CI/CD 作业调度 注册令牌 Registration Token GitLab Runner 进程 config.toml concurrent = 4 tags: docker, test, linux executor = docker 注册 作业 Job tags: [docker, test] script: npm test 标签匹配 docker 执行器 容器隔离,推荐 shell 执行器 宿主机直跑,易污染 k8s 执行器 Pod 弹性伸缩 并发控制 concurrent 全局上限 / limit 单 Runner 上限 匹配流程:作业提交 → GitLab 按 tags 筛选在线 Runner → 检查 concurrent 余量 → 派发到对应执行器 → 执行 script → 回传日志与产物 若标签不匹配或并发已满,作业保持 pending;若 Runner 离线,作业不会被派发。

五、实践中的配置要点

在真实项目中,建议把 Runner 配置纳入版本管理。例如用 Ansible 或 Terraform 统一安装 Runner,用模板生成 config.toml,避免手工修改导致环境漂移。对于 Docker 执行器,可以在 config.toml 中配置 pull_policy = "if-not-present",减少重复拉取镜像的时间;同时设置 cache_dir 和 volumes,让依赖缓存和构建产物在作业之间复用。

另外要注意,注册到项目还是群组会影响令牌的可见范围。项目级 Runner 的令牌只对单个项目有效,群组级 Runner 的令牌对整个群组有效。如果团队有多个仓库需要共用同一套 Runner,优先注册到群组,再通过标签区分不同作业的用途,这样既减少重复部署,又保留调度灵活性。

最后,Runner 的版本应与 GitLab 服务端保持兼容。GitLab 官方建议 Runner 版本不低于服务端版本,且不要跨越大版本升级。升级前先在测试项目上验证,确认执行器、缓存和标签行为没有变化,再推广到生产 Runner。