大规模开源 DevOps:自己运行 GitLab

源代码是几乎每家技术公司都同意属于关键资产的那一样东西,同时也是大多数公司放在自己并不拥有的基础设施上、置于自己没有选择的司法辖区之下、依据一份自己并未仔细读过的合同来托管的东西。通常这样的安排没有问题。但知道另一条路要付出什么代价仍然值得,因为十多年来,GitLab 让自行托管整个开发生命周期变得真正可行。
它同时也是一款免费层比多数人以为的更慷慨、运维负担比多数人以为的更沉重的产品。这两件事在投入之前都该搞清楚,所以这篇指南要讲的是自管 GitLab 究竟是什么、免费层真正给了你什么,以及造成大部分痛苦的三个运维问题。
GitLab 是什么
不是一个外挂了各种附件的 Git 托管。一个 Rails 应用、PostgreSQL、Redis、用于仓库存储的 Gitaly、跑后台任务的 Sidekiq,再加上一个容器镜像仓库,打包成一套系统,涵盖版本控制、代码评审、议题跟踪、CI/CD、软件包与容器镜像仓库、安全扫描和部署。
这种覆盖广度就是全部论点。GitHub 加 Actions 加 Dependabot 加一个包仓库加一个项目跟踪器,能拼出可比的功能集,但那是由零件拼起来的。GitLab 是一个应用,一套权限模型,一个数据库。这要么正是你想要的,要么超出你的需要,是哪一种取决于你实际打算把生命周期的多大一部分放在同一个地方运行。
架构上最关键的事实,与用 Matomo 自托管分析、用 Mautic 自托管营销自动化或用 Mattermost 自托管团队沟通是同一个:它跑在你放它的地方。你的仓库,你的 CI 日志,你的构建产物,你的数据库。
授权的真实情况,直说
这一点是真的容易搞混,值得说清楚,因为混淆的方向恰好和人们的预期相反。
源码有两个发行版。Community Edition 采用 MIT 许可。Enterprise Edition 有自己更严格的许可,适用于仓库中的 ee/ 目录。到这里为止,听起来就是常见的开放内核模式。
让人意外的地方在于:几乎所有人安装的那个 Linux 包,是 Enterprise Edition 的构建,而在没有导入许可证密钥时,它以 Free 层运行,表现得就像 Community Edition。也就是说,除非你刻意选了 CE 包,否则你运行的并不是那个 MIT 许可的发行版。实践中这很少要紧,但如果你自托管的理由是严格的开源政策而不是数据控制权,那就要紧得很,而几乎没有人去核对。
商业层级是 Free、按年计费每用户每月 29 美元的 Premium,以及价格面议的 Ultimate。Premium 增加高级 CI/CD、更好的项目管理和优先支持。Ultimate 增加安全与合规套件:应用安全测试、供应链安全、依赖扫描。两个付费层现在都附带用于 AI 功能的 GitLab Credits,Premium 每用户每月 12 美元,Ultimate 是 24 美元。
而下面这个事实会改变多数团队的算法,并且与 Mattermost 的情况正好相反:自管的 Free 层没有用户数上限。 人们听说过的五用户限制,只适用于 GitLab.com 上的私有群组。自托管的 Free 给你无限用户、版本控制、CI/CD 和镜像仓库,存储和 runner 由你自备。一个一百人的工程组织完全可以整个跑在上面。
你放弃的是安全扫描、合规报告、高级审批规则和支持。如果你受《网络韧性法案》约束,并且希望依赖扫描和 SBOM 生成内建在流水线里,而不是从几个独立工具拼起来,那就是一场关于 Ultimate 的对话。对其他大多数团队来说,Free 不是试用期,而是一个站得住脚的长期答案。
怎么搭建
小规模部署
GitLab 比看上去重。文档给出的单节点基线是 8 vCPU 和 16GB 内存,而且与大多数厂商最低配置不同,这个数字是诚实的,不是乐观的。可以硬塞进 8GB,但你会感觉到,而且应该关掉 swap,因为让这个应用去换页比干脆没有那点内存更糟。
PostgreSQL 是唯一受支持的数据库。用哪个版本取决于你的 GitLab 版本:17.x 要 PostgreSQL 14.14 到 16.x,18.x 要 16.5 到 17.x,19.x 要 17.x。推荐 Redis 7.2,最低 7.0,Valkey 7.2 可作替代。只支持独立实例,因为 Redis 的集群版和 serverless 变体都不受支持。
用 Linux 包安装。虽然有 Helm chart、Operator、Docker 镜像和从源码构建的路径,但 Linux 包是最成熟的选择,也正是 GitLab.com 自己跑的那一套。它自带 PostgreSQL、Redis 和 Sidekiq,所以一台机器加一个配置文件就能得到一个可用实例。
# /etc/gitlab/gitlab.rb
external_url 'https://git.example.com'
# Let's Encrypt, on by default when external_url is https
letsencrypt['enable'] = true
letsencrypt['contact_emails'] = ['ops@example.com']
# Keep Puma and Sidekiq honest on a small box
puma['worker_processes'] = 2
sidekiq['max_concurrency'] = 9
# Move artefacts and uploads off local disk early
gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['connection'] = {
'provider' => 'AWS',
'region' => 'eu-central-1',
'aws_access_key_id' => 'REPLACE_ME',
'aws_secret_access_key' => 'REPLACE_ME'
}
一条 gitlab-ctl reconfigure 之后你就有了一个实例。第一次就把 external_url 设对,因为这个值最后会固化进克隆地址、webhook 和镜像仓库地址里。
生产部署
GitLab 发布了从 1000 到 50000 用户的参考架构,即使你一个都不打算实施也值得一读,因为它们展示了哪个组件会最先成为瓶颈。
最省钱的建议来自 GitLab 自己,而且是在反对复杂性:在 3000 用户以下,他们推荐扎实的备份策略而非高可用。文档在这一点上罕见地坦率,指出基于备份的方案恢复时间确实更慢,但意味着小得多的架构和更低的维护成本。超过 3000 用户,或者一旦宕机就真的会让公司停摆的地方,高可用才成为建议。
把这话当真。一个备份做得好、恢复演练过的单节点,实际上比一个一知半解的高可用集群更可靠,也便宜得多。
从一开始就把构建产物、上传文件、LFS 对象和镜像仓库的镜像放进对象存储。理由和别处一样:让节点保持无状态、备份可控、迁移可行。
会出问题的三件事
上面这些文档里都有。下面这些才是会引发事故的。
你的备份里没有解开它的那把钥匙
这是本文最重要的一段。
gitlab-backup create 覆盖了相当多东西:数据库、仓库、LFS 对象、CI 产物和作业日志、镜像仓库镜像、wiki、上传文件、Pages 内容、Terraform 状态、代码片段。它没有覆盖的是配置目录,具体来说就是 /etc/gitlab/gitlab-secrets.json。
这个文件保存着数据库的加密密钥。文档对后果讲得毫不含糊:一旦丢失,GitLab 应用将无法解密数据库中任何被加密的值。也就是 CI/CD 变量、令牌、双因素密钥和集成凭据。你会得到一份能恢复出实例、但那个实例读不了自己秘密的备份。
同样被排除在外的还有:/etc/gitlab/gitlab.rb、TLS 密钥和证书、SSH 主机密钥,以及在配置了对象存储之后对象存储里的内容。最后这一条专门坑那些在架构上做对了、却随后假设备份已经涵盖它的人。
所以要单独备份 /etc/gitlab,把它放在与归档不同的地方,因为它就是那份归档的钥匙,然后把整套东西恢复到一台一次性机器上,确认你能登录并读出一个 CI 变量。没验证过的备份不算备份,而在 GitLab 这里,没验证过的恢复通常就是坏的。
升级不能一步到位
GitLab 有强制升级停靠点,而且这不是建议。你跳不过去。自 17.5 起停靠点是可预测的,落在 x.2、x.5、x.8 和 x.11,所以从 18.0 升到 19.2 意味着途中要经过 18.2、18.5、18.8、18.11 和 19.0。
每个停靠点都伴随后台迁移,必须完全跑完才能进入下一步。在迁移还在运行时就启动下一次升级,正是实例落入只有官方支持才能理清的状态的原因。在大实例上,这些迁移可能要跑好几个小时。
两个实际结论。定期升级,因为拖了一年的升级就是一个连着做升级的周末。以及永远取目标次版本的最新补丁版而不是第一个补丁版,文档对此有明确说明。GitLab 维护着一个替你计算升级路径的工具,用它比自己推算要好。
真正的成本在 runner 上
GitLab 服务端不跑你的 CI。GitLab Runner 是一个独立组件,由你安装、配置并付费,跑在你提供的基础设施上。自管的 Free 完全不含任何计算分钟数,因为根本没有附带的算力可给:机器你自己带。
这通常是笔划算的买卖,因为一旦量级认真起来,专用 runner 的每分钟成本低于任何托管 CI,而且你能给每个构建配上它需要的硬件。但这是实打实的基础设施工作。你要就 executor 做决定,是 shell、Docker 还是 Kubernetes;要就自动伸缩做决定,好让 runner 不至于凌晨三点空转;还要就缓存做决定,那是四分钟流水线和十四分钟流水线之间的差别。
把 runner 集群作为单独一项列进预算。那些只看 GitLab 节点来估算自托管成本的团队会大幅低估,随后以一队排着等的作业的形式发现这个缺口。
从 GitHub 搬出来
GitHub 导入器很好,明显优于多数厂商的迁移工具,它能带过来仓库数据、分支、LFS 对象、议题和 pull request 及其评论、评审和讨论回复、wiki 页面、发布及附件、标签、里程碑、分支保护规则,以及带角色映射的协作者。
有记录的缺口值得提前规划。组织和 group 不会迁过来,所以群组结构由你重新设计而不是继承,这通常是件好事。GitHub Actions 的工作流不会转换成 GitLab CI。2017 年之前的 pull request 评论因为 GitHub API 的限制会作为独立话题导入,而评论数超过大约三万条的仓库需要启用备用的评论导入方式。
由于 GitHub 对议题和 pull request 都用 #,而 GitLab 区分二者,部分交叉引用不会正确解析。东西不会丢,但旧讨论里的链接可能指向错误的对象。
把 CI 的重写当作真正的项目来规划,因为它就是。其余的只是一次你可以运行并检查的导入。
欧洲视角
对在欧洲经营的公司来说,成本之上还叠了一层合规维度。源代码、构建流水线和产物属于一家技术公司所持有的最敏感的东西,而它们住在哪里,越来越是别人问你的问题,而不是你自己选择回答的问题。
自托管把它们放进一条你能控制的边界之内,一举简化了 GDPR 的数据传输分析和 NIS2 的供应链问题,而这正是《云与人工智能发展法案》所围绕的同一个主权论点。
更直接的关联是《网络韧性法案》。如果你把软件投放到欧盟市场,你会需要依赖清单、漏洞处理和一套协同披露流程。这些义务是在构建流水线里满足的,而不是在一份文档里,而把流水线、镜像仓库和扫描放在同一个由你运维的系统里,会让证据的产出比从四家供应商那里东拼西凑轻松得多。
什么时候别折腾
如果你们不到二十个工程师,没有监管压力,也没人对代码住在哪里有强烈看法,就用 SaaS。运维投入的代价会超过订阅费。
如果你的组织深深扎在 GitHub 生态里,就诚实地算算会失去什么。Actions、市场,以及每个你要招的候选人对这个平台的天然熟悉,都是实打实的资产,答案并不自动是 GitLab 胜出。
而如果没有人愿意认领这个实例,那就别开始。GitLab 回报的是那个给它打补丁、盯着 runner 集群、演练恢复的人。没有那个人,它会退化成一台没打补丁、却装着你最宝贵资产的机器,那比你想逃离的 SaaS 更糟。
我们能帮上什么
我们为在欧洲经营的公司部署和运维自托管的开发基础设施,包括没人喜欢的那些部分:跨越强制停靠点的升级序列、能正确自动伸缩的 runner 集群、迁往对象存储,以及真正被恢复演练过的备份方案。
如果你想要一套尺寸诚实的 GitLab 部署、一次由做过 CI 重写的人规划的 GitHub 迁移,或者一次关于你现有备份能否扛住真实故障的评估,请写信到 office@c9group.dev。关于我们的基础设施工作,详见 AWS 成本优化页面。
如果你正在组装一整套自托管技术栈,同样的道理也适用于分析、营销自动化和团队沟通。
发布日期:2026年8月8日 分类:DevOps、开源、隐私