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)划分和路由设计,否则重活轻活混跑会拖垮整体吞吐。
如何判断该选哪一种
决策的核心不是“哪种更先进”,而是看瓶颈在哪里。可以用三个问题快速定位:
- 瓶颈是单机资源还是调度能力?如果
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 很容易演变成“配置漂移”的重灾区。
config.toml 通过 ConfigMap 或挂载卷注入,Manager 本身无状态化。这样既能水平扩展 Manager 实例,又保持配置来源唯一,兼顾了分布式的弹性和集中式的可管理性。
选型决策表(示例参考)
下表给出一组基于常见场景的选型建议,参数为示例值,实际需结合自身 Job 画像调整。
| 场景特征 | 推荐扩展模式 | Manager 形态 | 关键配置要点 |
|---|---|---|---|
| Job 同质、并发 < 30、单机房 | 垂直扩展 | 集中式 | concurrent=20,大规格主机,本地缓存 |
| Job 同质、并发 > 50、需故障隔离 | 水平扩展 | 分布式 | 多 Runner 实例,统一 tag,共享对象存储缓存 |
| Job 差异大(重编译 + 轻测试) | 混合部署 | 集中式 + 分布式结合 | 重型 Runner 打 build-heavy 标签,轻量池打 test-light |
| 多区域团队、就近执行要求高 | 水平扩展 | 分布式 | 每区域独立 Manager,配置用 IaC 统一管理 |
落地时的关键检查点
无论选择哪种模式,落地前建议确认以下几点:
- 标签体系先于扩展。水平扩展和混合部署都依赖 tag 做 Job 路由,如果 tag 命名混乱,扩展后 Job 会随机落到不合适的 Runner 上。建议按“能力 + 规格”命名,如
docker-large、shell-small。 - 缓存策略要提前设计。水平扩展后本地缓存失效,应尽早接入 S3/MinIO 等共享缓存,或在
config.toml中配置[runners.cache]指向统一存储。 - 监控指标要覆盖 Manager 本身。除了 Job 成功率,还要采集
gitlab-runner进程的 CPU、内存、goroutine 数量,以及 Job 排队时长。排队时长持续上升通常意味着 Manager 调度能力不足,而非 executor 不够。 - 升级路径要可回退。分布式 Manager 升级时逐台操作,先摘除流量(暂停 Runner)、升级、验证、再恢复。集中式升级则需安排维护窗口。
总结来说,垂直扩展适合规模可控、追求简单稳定的场景;水平扩展适合需要弹性与故障隔离的场景;混合部署适合 Job 画像差异明显的成熟团队。Manager 层面,集中式优先保证可管理性,分布式优先保证可用性与扩展性,而容器化 + 配置外置是兼顾两者的务实路径。选型的最终依据始终是自身的 Job 特征、故障容忍度和运维能力,而非某一种模式的“先进性”。