跳到主要内容

GitLab 高可用架构

GitLab 单机 Omnibus 适合中小团队;当 RTO/RPO、并发 Git 操作或 CI 峰值成为瓶颈时,需要拆组件并消除单点。高可用不是简单多复制几份 VM,而是按组件设计故障域、数据一致性和运维复杂度之间的平衡。

GitLab 官方参考架构分 3K / 5K / 10K / 25K / 50K 用户档位;本章归纳通用模式,具体规格以当前版本 Reference Architectures 为准。

1. GitLab高可用需求

先量化目标再选型:

指标典型生产目标
RPO0–15 分钟(视是否 Geo/同步复制)
RTO< 1 小时
并发 Gitpeak clone/fetch QPS
CI 并发同时在线 Runner 与 Job 数
仓库规模总 GB、最大 monorepo

高可用组件优先级:

  1. PostgreSQL(元数据真相源)— 必须冗余;
  2. Gitaly(Git 存储)— 仓库不可用则平台失效;
  3. Redis(队列、缓存)— 可重建但会丢 Sidekiq 队列;
  4. Rails/Puma、Workhorse、Sidekiq — 无状态,可水平扩展;
  5. Registry / 对象存储 — 多副本或云原生存储。

2. 单机架构分析

默认 Omnibus 单机:

GitLab Omnibus 单机架构与单点风险

单点风险:

组件故障影响
磁盘全站不可用,可能数据丢失
PostgreSQL无法登录、MR、CI 调度
Gitaly无法 push/pull
Redis队列积压、会话失效
PumaWeb UI 502,Sidekiq 仍可能跑 Job

第一步优化往往是 外置 PostgreSQL + 外置 Redis + 对象存储,Rails 仍单机,已消除最大数据单点。

3. 外置PostgreSQL

推荐 Patroni + etcd 或云托管 RDS/Aurora/Cloud SQL。Omnibus 配置 /etc/gitlab/gitlab.rb

postgresql['enable'] = false
gitlab_rails['db_adapter'] = 'postgresql'
gitlab_rails['db_host'] = 'pg-primary.internal'
gitlab_rails['db_port'] = 5432
gitlab_rails['db_database'] = 'gitlabhq_production'
gitlab_rails['db_username'] = 'gitlab'
gitlab_rails['db_password'] = '<from-vault>'

# 只读副本(可选,用于 Geo 或报表)
gitlab_rails['db_load_balancing'] = { 'hosts' => ['pg-replica1.internal', 'pg-replica2.internal'] }
sudo gitlab-ctl reconfigure
sudo gitlab-rake gitlab:db:configure
sudo gitlab-rake db:migrate

注意:GitLab 仍要求主库可写;读副本仅用于特定读场景。连接池使用 PgBouncer 时选 transaction pooling 并遵循 GitLab 文档中的 session 限制。升级 GitLab 前确认外置 PG 版本在兼容矩阵内。

4. 外置Redis

Omnibus 禁用内置 Redis 并指向 Sentinel 或托管 Redis:

redis['enable'] = false
gitlab_rails['redis_host'] = 'redis-sentinel.internal'
gitlab_rails['redis_port'] = 26379
gitlab_rails['redis_sentinels'] = [
{ 'host' => 'sentinel1.internal', 'port' => 26379 },
{ 'host' => 'sentinel2.internal', 'port' => 26379 },
{ 'host' => 'sentinel3.internal', 'port' => 26379 }
]
gitlab_rails['redis_password'] = '<redis-password>'

Redis 故障时 Sidekiq 队列可能丢失在途 Job,但 Git 数据仍在 Gitaly。应对 CI 关键 Job 设计幂等与重试;会话类数据丢失表现为用户需重新登录。生产 Redis 开启持久化(AOF)并监控内存;不要用无持久化的单节点 Redis 支撑大型 Sidekiq。

5. Gitaly Cluster

Gitaly Cluster(原 Praefect)将 Git 仓库分布到多个 Gitaly 节点,通过 Praefect 路由与复制:

Gitaly Cluster 中 Praefect 的路由与仓库复制

/etc/gitlab/gitlab.rb 片段(Rails 节点):

gitaly['enable'] = false
git_data_dirs({
"default" => {
"path" => "/var/opt/gitlab/git-data",
"gitaly_address" => "tcp://praefect.internal:2305",
"gitaly_token" => '<praefect-external-token>'
}
})

Gitaly 节点单独安装 Omnibus 或 Gitaly package,配置 storage 名称与 Praefect 一致。迁移现有仓库到 Cluster 应使用官方 gitlab-backup + 迁移工具,或按版本文档执行 gitlab-rake gitlab:gitaly:* 系列命令,不要手工 rsync 单仓库目录。

Gitaly Cluster 运维成本显著高于单机 Gitaly;仓库总容量超过数 TB 或 clone 峰值高时再引入。

6. GitLab多节点架构

典型 3 节点 Web + 独立 Sidekiq + 外置 PG/Redis + Gitaly Cluster:

GitLab 多节点高可用参考架构

Rails 节点配置相同 gitlab.rb(secrets 必须一致),共享对象存储:

gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts'
gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs'
gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads'

Sidekiq 可独立扩容:

# 专用 Sidekiq 节点
puma['enable'] = false
nginx['enable'] = false
sidekiq['max_concurrency'] = 50

负载均衡器需支持 WebSocket(ActionCable)、大文件 Git HTTP 和长连接;健康检查路径 /help/users/sign_in。Sticky session 对 Rails 通常非必须(若 session 存 Redis/Cookie),但 Git LFS 大上传需调大超时。

7. Kubernetes高可用部署

官方 GitLab Helm Chart 适合云原生 HA:

helm repo add gitlab https://charts.gitlab.io/
helm repo update

# 最小 HA:外置 PG、Redis、对象存储
helm upgrade --install gitlab gitlab/gitlab \
-f values.yaml \
--namespace gitlab \
--timeout 600s

values.yaml 关键项:

global:
hosts:
domain: example.com
psql:
host: pg.example.com
redis:
host: redis.example.com
minio:
enabled: false
appConfig:
object_store:
enabled: true

gitlab:
webservice:
minReplicas: 2
sidekiq:
minReplicas: 2
gitaly:
persistence:
enabled: true
size: 500Gi

生产建议 Gitaly 用 StatefulSet + 快磁盘;备份用 gitlab-backup Job 或 Velero + 外置 DB 快照。Helm 升级前对照 chart 与 GitLab 版本对应表。