3. 集群化部署模式选型

当单台 GitLab Runner 主机已经无法稳定承载流水线负载时,真正需要决策的不是“加机器”这么简单,而是选择哪种扩展形态:把单机做大(垂直扩展)、把实例做多(水平扩展),还是两者结合(混合部署)。同时还要决定 Runner Manager(即 gitlab-runner 进程本身)是集中部署还是分散部署。这两个决策相互独立又彼此影响,选错方向会导致后续治理成本成倍增加。

三种扩展模式的本质差异

垂直扩展指提升单台 Runner 主机的 CPU、内存、磁盘 IO 和网络带宽,让同一台机器能并发跑更多 Job。它的优点是架构不变、配置不变、运维路径最短,所有 Runner 仍注册在同一个 Manager 下,缓存和镜像层天然复用。缺点是存在物理上限,且单点故障风险随规模放大——一台 64 核机器宕机,等于同时损失几十个并发槽位。

水平扩展指增加 Runner 实例数量,每个实例可以是独立主机、虚拟机或容器。它突破了单机上限,天然具备故障隔离能力,配合 GitLab 的 Job 分发机制,某个 Runner 掉线只会影响正在其上运行的 Job。代价是缓存分散、镜像拉取重复、配置需要统一管理,且并发 Job 数量增长后,GitLab 服务端的 Job 调度压力也会上升。

混合部署是前两者的组合:保留少量大规格 Runner 承担重负载 Job(如大型编译、镜像构建),同时用大量中小规格 Runner 处理轻量 Job(如单元测试、lint)。这种模式最贴近真实生产,但要求对 Job 做标签(tag)划分和路由设计,否则重活轻活混跑会拖垮整体吞吐。

三种扩展模式与 Manager 部署形态对照 垂直扩展(Scale Up) 单台大规格主机 32C / 128G / NVMe concurrent = 24(示例) 优点:架构简单、缓存复用 风险:单点故障、物理上限 水平扩展(Scale Out) Runner-1 8C/16G Runner-2 8C/16G R-N … 优点:故障隔离、弹性好 代价:缓存分散、配置管理复杂 Job 由 GitLab 服务端分发 单实例掉线仅影响在跑 Job 混合部署(Hybrid) 重型 Runner tag: build-heavy 轻量 Runner 池 tag: test-light 按 Job 标签路由 重活不挤占轻活资源 前提:标签体系必须清晰 否则重轻混跑拖垮吞吐 Runner Manager 部署形态:集中式 vs 分布式 集中式 Manager Manager 主节点 config.toml 统一 Executor 池 docker / k8s 配置集中、缓存统一、审计简单 Manager 成为单点,扩容受限于单进程 分布式 Manager Manager A 区域 1 Manager B 区域 2 Manager C 区域 3 故障域隔离、就近执行、弹性强 配置漂移风险、缓存不共享、治理成本高

如何判断该选哪一种

决策的核心不是“哪种更先进”,而是看瓶颈在哪里。可以用三个问题快速定位:

  • 瓶颈是单机资源还是调度能力?如果 gitlab-runner 进程本身 CPU 打满、Job 排队但机器资源还有余量,说明是 Manager 调度瓶颈,垂直扩展无效,必须水平拆分 Manager。
  • Job 是否同质?如果所有 Job 都是同一种构建任务、资源需求接近,水平扩展最直接;如果 Job 差异极大(有的跑 30 分钟编译,有的 10 秒 lint),混合部署配合标签路由更合理。
  • 故障容忍度如何?核心发布流水线不能因单机宕机而中断,就必须水平扩展或分布式 Manager;内部工具类流水线可以接受短暂中断,垂直扩展的单点风险可以接受。

集中式与分布式 Manager 的取舍

集中式 Manager 的典型形态是一台(或主备两台)主机运行 gitlab-runner,通过 config.toml 统一管理所有 executor。它的优势在于配置只有一份、缓存目录统一、日志集中、升级只需操作一处。当并发量在单进程可承受范围内(经验上 concurrent 设置在 20~50 之间,具体取决于 Job 类型和主机规格),集中式是运维成本最低的选择。

分布式 Manager 则是多个 gitlab-runner 进程各自注册到同一个 GitLab 项目或群组,每个 Manager 管理自己的 executor 池。它解决了单进程调度上限和单点故障问题,也支持跨区域就近执行。但代价是:config.toml 需要在多个节点间同步,缓存不再共享(除非外挂共享存储),日志需要聚合,版本升级需要滚动操作。如果缺乏配置管理工具(如 Ansible、Chef)或容器编排平台,分布式 Manager 很容易演变成“配置漂移”的重灾区。

一个实用的折中方案:用容器化方式部署 Runner,把 config.toml 通过 ConfigMap 或挂载卷注入,Manager 本身无状态化。这样既能水平扩展 Manager 实例,又保持配置来源唯一,兼顾了分布式的弹性和集中式的可管理性。

选型决策表(示例参考)

下表给出一组基于常见场景的选型建议,参数为示例值,实际需结合自身 Job 画像调整。

场景特征 推荐扩展模式 Manager 形态 关键配置要点
Job 同质、并发 < 30、单机房 垂直扩展 集中式 concurrent=20,大规格主机,本地缓存
Job 同质、并发 > 50、需故障隔离 水平扩展 分布式 多 Runner 实例,统一 tag,共享对象存储缓存
Job 差异大(重编译 + 轻测试) 混合部署 集中式 + 分布式结合 重型 Runner 打 build-heavy 标签,轻量池打 test-light
多区域团队、就近执行要求高 水平扩展 分布式 每区域独立 Manager,配置用 IaC 统一管理

落地时的关键检查点

无论选择哪种模式,落地前建议确认以下几点:

  1. 标签体系先于扩展。水平扩展和混合部署都依赖 tag 做 Job 路由,如果 tag 命名混乱,扩展后 Job 会随机落到不合适的 Runner 上。建议按“能力 + 规格”命名,如 docker-large、shell-small。
  2. 缓存策略要提前设计。水平扩展后本地缓存失效,应尽早接入 S3/MinIO 等共享缓存,或在 config.toml 中配置 [runners.cache] 指向统一存储。
  3. 监控指标要覆盖 Manager 本身。除了 Job 成功率,还要采集 gitlab-runner 进程的 CPU、内存、goroutine 数量,以及 Job 排队时长。排队时长持续上升通常意味着 Manager 调度能力不足,而非 executor 不够。
  4. 升级路径要可回退。分布式 Manager 升级时逐台操作,先摘除流量(暂停 Runner)、升级、验证、再恢复。集中式升级则需安排维护窗口。
不要在没有标签规划和缓存方案的情况下直接水平扩展。多个 Runner 实例各自拉取镜像、各自维护缓存,会导致网络带宽和存储成本快速上升,实际吞吐提升可能远低于预期。

总结来说,垂直扩展适合规模可控、追求简单稳定的场景;水平扩展适合需要弹性与故障隔离的场景;混合部署适合 Job 画像差异明显的成熟团队。Manager 层面,集中式优先保证可管理性,分布式优先保证可用性与扩展性,而容器化 + 配置外置是兼顾两者的务实路径。选型的最终依据始终是自身的 Job 特征、故障容忍度和运维能力,而非某一种模式的“先进性”。