技术深度解析:Kubernetes 上的 GitLab Runners、Operator 安装、Helm 参数、自动扩缩容及 FinOps 成本模型。如需简版,请阅读停止为闲置 CI 付费。
大多数团队为持续集成付费的方式,仿佛每个夜晚和周末仍是周一早晨。服务器持续运行,磁盘空间持续占用。没有人正在合并代码——而账单却毫无察觉。这句话不是口号;它是固定 Runner 集群的默认形态。
本文是GitLab Server 和 Kubernetes 上的 GitLab Runner实操指南的技术配套:Kubernetes 执行器如何将每个 CI 任务转换为临时 Pod,如何实现容量的动态配置与释放,以及该设计如何释放巨大的成本节约,在夜间和周末需求骤降时回收 CPU、内存和存储空间。
先观看两场演示,再以本文档作为书面架构与成本模型参考。
1. Runners 与流水线— 基于 Kubernetes 的 GitLab Runner 工作负载自动扩缩容。
观看:完整的 GitLab Runners 与 CI/CD 在 Kubernetes 上的部署· 通俗版本:停止为闲置 CI 付费
2. HA 集群上的 GitLab Server Kubernetes— 几分钟内通过 Operator 部署 GitLab。
观看:使用 Operator 在 HA Kubernetes 集群中部署 GitLab· 文档:GitLab Operator 安装
1. 论点
GitLab on Kubernetes + Kubernetes executor将 CI 容量的单位从“我们整个月拥有的机器”转变为“为任务租用的 pods(和节点)”。Runner 管理器保持精简且始终在线。任务 pod 在构建时出现,构建后消失。借助集群自动伸缩,工作节点遵循相同的曲线。这就是如何保护周一早间的吞吐量,并避免在周二凌晨 03:00 和安静的周六支付周一早间的价格。
用一句话概括——与入门指南相同的一句话:为峰值配置资源,为低谷释放资源。
2. 昂贵的习惯,被表述为一种架构异味
传统的 CI 通常看起来像一支永久舰队:一组固定的构建机器,始终在线“以防万一”。当流量稳定时,这种方式行得通;但当需求呈尖峰状时,它只会浪费钱。
- 白天:开发人员推送分支、打开合并请求、运行测试——需求激增。
- 傍晚和夜间:活动减少,但机器仍在消耗 CPU 和内存。
- 周末:通常接近空闲——但存储卷和云节点可能仍被预留并计费。
你支付的不是“已完成的构建”,而是无论是否有人使用都存在的容量。固定舰队还会积累粘性状态:“在 runner 3 上运行正常”、漂移的包、永远不会过期的缓存。弹性容器并不自行解决纪律问题,但它们让“从零开始”成为默认选项。
3. 系统架构图
| 层级 | 角色 | 典型部署位置 |
|---|---|---|
| GitLab 服务器 | 源代码管理、CI 协调、注册表、UI/API | 通过 GitLab Operator / Helm 图表部署(例如 k3s 实验室) |
| Runner 管理器 | 注册代理,轮询任务 | Helm 版本在专用命名空间中运行(例如gitlab-runner) |
| 任务 Pod | 实际的构建/测试/打包步骤 | 由 Kubernetes 执行器为每个任务创建,随后删除 |
| 可选 DinD 服务 | Docker 在任务内部构建 | 位于任务旁边的特权服务容器 |
| 集群/节点自动伸缩器 | 在 Pod 压力条件下添加/移除工作节点 | 云 ASG、Cluster Autoscaler、Karpenter 或等效方案 |
普通指南中的类比在此层级仍然适用:GitLab Runner 是工人;Kubernetes 是调度器,仅在包裹(任务)到达时呼叫工人,然后将其遣返。
4. 在集群中安装 GitLab(操作者路径)
Day 1 培训路径使用官方操作者安装 GitLab,因此服务器与运行器共享相同的 Kubernetes 基础架构。配套视频使用操作者在 HA Kubernetes 集群中部署 GitLab在几分钟内演示了该安装过程。前置条件:集群需具备 ingress、Helm、kubectl以及 cert-manager(当图表管理 TLS 时)。
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm install gitlab-operator gitlab/gitlab-operator \
--create-namespace \
--namespace gitlab-system
kubectl -n gitlab-system get deployment gitlab-controller-manager
# Apply the GitLab custom resource (pin chart version in the manifest)
kubectl -n gitlab-system apply -f deploy_gitlab_server.yaml
示例 CR 结构(根据您的环境自定义域和颁发者邮箱):
apiVersion: apps.gitlab.com/v1beta1
kind: GitLab
metadata:
name: gitlab
spec:
chart:
version: "9.2.2"
values:
global:
hosts:
domain: "example.com"
ingress:
configureCertmanager: true
certmanager-issuer:
email: you@example.com
首次安装通常需要 10–15 分钟,在此期间 web 服务、Sidekiq、数据存储及相关组件完成初始化。从集群密钥中获取初始 root 密码:
kubectl get secret gitlab-gitlab-initial-root-password -n gitlab-system \
-o jsonpath='{.data.password}' | base64 -d
参考:GitLab 操作者安装(该页面 Helm 标签页)。图表概览:docs.gitlab.com/charts· 安装指南:charts 安装。
5. 使用 Kubernetes 执行器的 GitLab 运行器
GitLab 运行器是与 GitLab CI/CD 协作以在流水线中运行任务的应用程序。使用Kubernetes 执行器时,管理器不会自行编译。对于每个任务,它会:
- 创建一个 Pod(并根据配置添加辅助/服务容器)。
- 将日志流式传输回 GitLab。
- 收集制品和退出状态。
- 删除 Pod——将 CPU 和 RAM 归还给集群。
创建/运行/删除循环是第一个成本杠杆。已完成的工作不应在夜间占用专用机器。
5.1 Helm 安装模式
训练脚本创建命名空间、传递注册令牌,并可能安装多个版本(例如基于 Alpine 和基于 Ubuntu 的 Runner),以便作业可以选择不同的环境。官方流程:使用 Helm 图表安装 GitLab Runner;值参考:配置 GitLab Runner Helm 图表。
helm upgrade --install --namespace gitlab-runner gitlab-runner-alpine \
-f config-runner-alpine.yaml \
--set serviceAccount.create=true \
gitlab/gitlab-runner \
--create-namespace
从 GitLab UI(实例/组/项目 Runner)或操作者管理的密钥中获取令牌。优先使用现代 Runner 认证令牌;注册令牌正逐步弃用(面向 GitLab 18)。切勿提交活动令牌— 实验室脚本有时包含需要本地替换的占位符。
5.2 影响规模与隔离的关键值
来自 Workstation 模板(gitlab-runner-values-template.yaml/ generatedconfig-runner-*.yaml):
| Setting | 为何重要 |
|---|---|
concurrent | 该管理器同时运行的最大任务数。白天高峰时调高(培训笔记提到繁忙实验室中为数十个,如 20–40)。在集群限制前进行软节流。 |
runners.privileged/ executorprivileged | 若无需 DinD,通常可收紧。 |
[runners.kubernetes].namespace | 任务 Pod 的部署位置——应与 GitLab 系统组件保持分离。 |
默认image/ 辅助镜像 | 锁定标签以确保 alpine/ubuntu 池的可复现性。 |
[[runners.kubernetes.services]]DinD | Sidecardocker:dind用于镜像构建;仅按需配置注册表镜像/不安全注册表。 |
RBACclusterWideAccess | 仅当任务必须管理集群级资源时使用;生产环境中优先遵循最小权限原则。 |
| host aliases / DNS 配置 | 实验室中集群内 GitLab 和注册表主机名的便捷配置。 |
gitlabUrl: http://gitlab-webservice-default.gitlab-system.svc.cluster.local:8080/
concurrent: 2
rbac:
create: true
clusterWideAccess: true
runners:
privileged: true
config: |
[[runners]]
environment = ["GIT_SSL_NO_VERIFY=1"]
[runners.kubernetes]
namespace = "gitlab-runner"
image = "alpine/git:latest"
service_account = "gitlab-runner"
privileged = true
仅靠 CPU 无法实现并发,只会延长队列。请将concurrent与真实的节点空闲容量或节点自动伸缩配合使用。
6. 两级(实际上是四级)自动伸缩
"在 Kubernetes 上自动伸缩 GitLab Runner" 不是一个开关。叠加这些杠杆:
- 任务 Pod 弹性— 内置于 Kubernetes 执行器中。零任务 → 零任务 Pod。仅此一项即可消除共享集群上大部分按任务产生的浪费。
- Runner
concurrent及多个 Runner 部署— 将 alpine 与 ubuntu(或 CPU 与更大规模的构建器)分开,避免专用容量因错误配比而闲置。 - 集群/节点自动伸缩— 待处理 Pod 增加节点;空闲节点在晚间高峰过后自动释放。
- 可选的日程感知策略— 在日历上降低并发上限或按日程缩节点池,作为自然需求下降的额外保障。
超大规模场景的故事相同,但振幅更尖锐:队列深入时向外扩展,随后激进地释放资源,确保一周中安静的半天在账单上不会与忙碌的半天相仿。
6.1 关于 GitLab Runner 语境下"空闲"的说明
某些执行器会保留少量空闲机器以保持温热,以便在无需冷启动延迟的情况下吸收下一个任务。在 Kubernetes 上,冷启动通常是创建 Pod(数秒),而非启动虚拟机(数分钟)。更倾向于让 Pod 归零,并接受短暂的调度延迟,而不是保留一整夜的空闲节点"以防万一"。如果必须维持一个最小基线,请根据值班现实来设定该基线的大小——而非周一的合并风暴。
6.2 动态配置与取消配置端到端流程
追踪一个流水线任务:
- 开发者推送代码;GitLab 在待处理队列中创建任务。
- Runner 管理器认领该任务并向 API 请求一个 Pod。
- 如果集群中 CPU/内存不足,自动伸缩器会添加节点(配置)。
- Pod 运行脚本、上传制品,然后退出。
- Pod 被删除,资源归还到池中(任务级别的取消配置)。
- 当许多节点在超过缩放下限阈值后仍然空闲——通常在晚间和整个周末之后——节点会被移除(基础设施级别的取消配置)。
这个完整循环就是视频中提到的超大规模 GitLab Runner 用于成本优化的含义:并非某个花哨的开关,而是任务生命周期与集群弹性协同工作。
7. 成本模型:巨额节省出现在哪里
务必精确。自动伸缩并不能让构建免费。它只是让你不必在非高峰时段支付高峰费率。节省来自于将支出与实际需求相匹配——来自基础指南的四个要点,针对运维人员进行了扩展。
7.1 仅在有人(或机器人)工作时进行扩容
当忙碌的早晨涌入数十个流水线时,Kubernetes 会并行调度多个任务 Pod,直至达到并发和集群限制。当合并压力真实存在时,吞吐量才会显现。
7.2 需求消失时果断缩减规模
任务完成后,Pod 随之消失。借助集群自动扩缩容(或合理规模的节点池),未使用的云节点会自动退出节点池。夜间和周末——通常是产品团队最安静的时段——正是你应该率先停止付费的容量。
7.3 停止浪费 CPU、RAM 和存储
| 资源 | 常驻运行器 VM | Kubernetes 任务 Pod + 节点自动扩缩容 |
|---|---|---|
| CPU | 队列空闲时预留核心处于闲置状态 | Pod 退出时释放;节点可自动缩容 |
| RAM | Agent 操作系统 + 空闲执行器全天候驻留 | 每次 Pod 删除时内存随之释放 |
| 存储 | 每台 VM 上的热数据盘和镜像层 | 默认使用临时性临时存储;共享缓存变为显式且可指定大小的选项 |
一个月下来,安静时段占据了大部分时间。回收夜间和周末的容量,正是节省成本产生复利效应的关键。
7.4 为成果付费,而非为家具付费
你仍需为 GitLab 和轻量级控制平面(运行器管理器 + 集群基础组件)付费。你所停止付费的,是一堆空椅子的仓库。
7.5 直觉上的理解(并非人为制造的基准)
假设白天可持续需要相当于 20 个忙碌执行器槽位,而夜间和周末仅需 2 个。固定规模的舰队按 20 个全天候计费。弹性池在白天支付约 20 个,在安静时段支付约 2 个(加上控制平面)。对于许多产品团队,安静时段占整个月的很大比例——因此回收这些时段是节省变得巨大的方式,而无需发明营销百分比。财务部门将本地节点小时价格相乘;架构工作的任务是让计费账户中的空闲时段真正变为空闲。
巨大的成本节省体现在:周一的峰值不再决定周二凌晨三点的账单——以及周六的寂静终于在发票上也显得安静了。
7.6 你仍然有意为之而支付的费用
- GitLab Server 组件——按用户和 CI 协调规模配置,而非编译农场。
- Runner 管理器部署——规模小于作业农场。
- 有意为之的缓存(依赖代理、PVC 等)——有帮助,但已配置规模;缓存并非免费存储。
- 特权 DinD——方便但更重;当密度和隔离比熟悉度更重要时,请考虑 Kaniko/BuildKit。
8. CI/CD 实践中的流水线
当 Runner 在线后,.gitlab-ci.yml定义阶段和任务。GitLab 负责调度;Kubernetes 执行器将 Pod 实例化。保持流水线对成本的诚实:
- 在重型镜像构建之前,尽早对 lint/单元测试失败。
- 使用
rules和workflow,使草稿分支不会扩散出完整的矩阵。 - 优先使用具有清晰键的共享缓存,而非无限制的每台 VM 磁盘增长。
- 将任务标记到正确的 Runner 池(alpine 与 ubuntu、小型与大型构建器)。
stages: [lint, test, build]
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
lint:
stage: lint
image: alpine:3.19
script:
- echo "cheap checks first"
test:
stage: test
tags: [kubernetes, alpine]
script:
- echo "unit tests"
build:
stage: build
tags: [kubernetes, dind]
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- echo "heavy image build only on default branch"
经济理念与平台理念相同:不要在没有廉价检查就会失败的情况下调度昂贵的工作,也不要为那些周六永远不会到来的任务保持专用 Runner 处于温暖状态。
9. 安全与多租户说明
临时 Pod 改善了卫生状况(更少的粘性状态),但特权 DinD 和集群范围的 RBAC 可能扩大爆炸半径。大多数团队的实用默认值:
- 在专用命名空间中运行任务 Pod,并设置 ResourceQuotas 和 LimitRanges。
- 尽可能优先使用非特权构建;通过特定标签隔离 DinD Runner。
- 避免将长期有效的云凭证挂载到每个任务中;为每条流水线注入短期令牌。
- 将 Runner 注册令牌视为秘密——当人员离职或实验室共享时进行轮换。
- 如果多个团队共享一个集群,请分离 Runner 管理器(以及可选的节点池),以便一个嘈杂的邻居无法让整个农场保持高温——并保持成本故事可按团队归因。
10. 可观测性证明节省效果
你不能声称夜间和周末有节省,而不进行查看。至少跟踪以下内容:
| 信号 | 什么是"良好"的状态 |
|---|---|
| 按小时统计的 Job Pod 数量 | 工作日工作时段出现峰值;夜间和周末接近地板值 |
| 待处理 Pod | 仅在峰值时短暂出现尖峰;持续待处理意味着并发度/节点不足 |
| 节点 CPU / 节点数量 | 跟踪 Pod 需求;空节点不应长时间滞留 |
| Runner 管理器 CPU/RAM | 相对于 Job Farm 保持平稳且较小 |
| 按每周小时计的云账单 | 切换后,安静时段明显更便宜 |
如果夜间 Pod 数量下降但节点账单没有下降,那么需要调整的是缩容设置——而不是 GitLab。
11. 固定 VM 与 Kubernetes 执行器(决策表)
| 固定运行器 VM | Kubernetes 执行器 + 自动扩缩 | |
|---|---|---|
| 容量单位 | 整台机器,始终分配 | 每任务一个 Pod(可选节点) |
| 周一高峰 | 排队或超额购买 VM | 提高并发 + 扩展节点 |
| 夜间/周末 | VM 保持运行仍计费 | Pod 消失;节点可离开 |
| CPU / RAM / 存储浪费 | 空闲时结构性浪费 | 默认回收 |
| 漂移/"在运行器 3 上有效" | 常见 | 减少(默认临时) |
| 运维复杂度 | 初始较低 | 较高(需要集群技能) |
仅在您确实拥有平稳的 24×7 需求或存在禁止使用集群的限制时,才选择固定 VM。所有其他人拥有尖峰式人工驱动流水线,都在支付"家具税"。
12. 您并未放弃的内容
自动扩缩并不意味着"失去控制"。您仍然可以设置并发数、允许镜像、DinD 权限、网络策略和注册范围。关键在于在保留这些控制的同时,让未使用的容量蒸发——与通俗语言文章中的保证相同,现在通过 RBAC、命名空间和独立的运行器发布来强制执行。
13. 运行清单
- Pin 操作者/图表版本;升级时需谨慎。
- 轮换 runner 令牌;在发布前从任何脚本中清除 lab 令牌。
- 隔离命名空间:GitLab 系统与 runner 任务。
- 监控待处理的 pods——待处理数量上升意味着峰值时并发或节点容量不足。
- 监控空闲节点小时数——节点在夜间持续空闲意味着缩容延迟或池策略需要调整。
- 将特权 runner 限制为确实需要它们的任务。
- 独立于 runner 弹性对 GitLab 进行备份。
- 弹性 CI 上线后,按每周小时审查账单——夜间和周末的费用应明显下降。
14. 适用对象
- 在 Kubernetes 上实施 GitLab CI 的平台工程师和 SRE。
- 用 executor pods 替代常驻 runner VM 的 DevOps 负责人。
- 需要 CI 像按使用量计费的公用事业而非固定家具的工程与财务合作伙伴。
15. 官方 GitLab 文档
这些页面是上述 Helm 部署和扩展行为的权威参考。版本变更时,请优先参考这些页面而非博客文章。
Kubernetes 上的 GitLab Server
- 安装 GitLab Operator— 培训演示中使用的 Operator + Helm 安装路径。
- GitLab Helm 图表— 顶层图表文档。
- 使用 Helm 图表安装 GitLab— 通过图表而非 Operator 部署 GitLab 时。
- gitlab-runner 子图表(GitLab 图表)— 主图表中与 GitLab 捆绑的 runner(区别于独立的 runner 图表)。
GitLab Runner Helm 图表
- 使用 Helm 图表安装 GitLab Runner—
helm repo add gitlab,安装/升级,OCI 图表说明。 - 配置 GitLab Runner Helm 图表—
concurrent,配置模板,RBAC,缓存,镜像选择。 - gitlab-runner 图表
values.yaml— 完整默认值(包括可选的 HPA 占位符)。
Kubernetes 执行器和自动伸缩
- Kubernetes 执行器— 作业 Pod、辅助组件、服务(如 DinD)、资源请求、RBAC 动词。
- 配置自动伸缩(Kubernetes 执行器/图表)— 暂停 Pod、
[runners.kubernetes.autoscaler],周期策略(夜间/周末空闲)。 - 自动伸缩 GitLab Runner— 通用自动伸缩模型(也涵盖分布式缓存)。
- 规划和管理工作队— 工作队级别的伸缩和运维。
- 高级配置(
config.toml)— 嵌入在 Helmrunners.config中的全局concurrent和执行器部分。
GitLab 中的 CI 作业、构建和 Runner 设置
- 在 GitLab 中配置 Runner— 注册、标签、run-untagged、受保护的 Runner。
- 使用 Docker 在 CI 中构建镜像— DinD 和替代方案(当
privileged/ Docker 服务在 Runner 配置中启用时相关)。
为夜间和周末成本控制,结合:(1) Kubernetes 执行器作业 Pod 缩至零,(2) 图表concurrent和自动伸缩器策略配合非高峰时段idle_count = 0,以及 (3) 集群/节点自动伸缩使空闲节点离开池 — 如第 6–7 节所述。
16. 回到视频和仓库
YouTube 课程 —约 20 分钟完成 GitLab。使用 Kubernetes自动扩展 GitLab Runner 工作负载,展示了 Kubernetes 上的 GitLab、通过 Helm 的 Runner,以及超大规模成本方案:动态创建和销毁基础设施,让您无需为空闲的夜晚和周末支付峰值费用。请使用本仓库中的课程构建提示gitlab-runners-k3s-hyperscale-course.prompt.md,以上方官方文档作为版本化权威来源。对于同一理念的面向非技术人员的表述,请参阅停止为空闲 CI 付费。
结语
Kubernetes 不仅托管 GitLab Runner。正确使用它,将改变 CI 的经济模式:按需创建、空闲时销毁、人类下班时回收 CPU/内存/存储。这就是超大规模模式——任何愿意以常驻集群换取队列式 Pod 的团队均可采用。
从观看视频开始,在实验室中搭建操作节点和 Runner Helm,开启节点自动扩展,然后查看周六的账单是否终于安静了。
由Workstation发布。