GitLab Omnibus Docker 内存优化实战:从 4.7 GiB 降到 3.2 GiB
在低内存 NAS 上运行 GitLab Omnibus Docker,通过官方推荐的配置优化,内存占用降低约 1.5 GiB,同时保持 3-5 人并发使用的稳定性。
背景
GitLab Omnibus 是一个"全家桶"打包方案,包含了 Puma(Web 服务器)、Sidekiq(后台任务)、PostgreSQL、Redis、Gitaly(Git RPC 服务)等众多组件。即使是默认配置,在一台 16 GB 内存的 NAS 上,内存占用也会达到 4-5 GB。
我的场景是个人/小团队使用(3-5 人),并不需要 GitLab 默认为中大规模部署预留的资源。本文记录了如何在不影响多人使用的前提下,通过官方文档推荐的配置项进行内存优化。
优化前状态分析
首先需要了解内存都花在了哪里:
组件 内存占用
Puma ~2.9 GB
PostgreSQL ~2.4 GB
Gitaly ~1.1 GB
Sidekiq ~1.1 GB
Redis ~0.3 GB
其他组件 ~0.5 GB
─────────────────────
总计 ~4.7 GB
Puma 和 PostgreSQL 是最大的两个内存消耗者。优化的核心思路是:降低并发上限、关闭不需要的服务、调优内存分配器。
优化方案
1. Puma 单进程模式(节省约 1.5 GB)
GitLab 默认 Puma 使用多 worker 进程(类似 Nginx 的 prefork 模型)。对于小团队,可以切换到单进程 + 多线程模式:
ruby
# 使用单进程模式(禁用 cluster mode)
puma['worker_processes'] = 0
# 关闭 Puma 内置的 metrics exporter
puma['exporter_enabled'] = false
原理 :worker_processes = 0 时,Puma 不会 fork 子进程,而是以单进程 16 线程运行。对于 3-5 人的并发量完全够用。每个 Puma worker 进程约占 1-1.5 GB,省掉额外 worker 能节省大量内存。
影响:并发请求处理能力略有下降,但 3-5 人使用完全无感。
2. Sidekiq 并发调低(节省约 0.3 GB)
Sidekiq 默认并发 20,对于小团队来说过高:
ruby
sidekiq['concurrency'] = 5
# 关闭 Sidekiq metrics
sidekiq['metrics_enabled'] = false
原理:每个并发槽占用一个数据库连接和一定的内存。5 个并发足以处理小团队的后台任务(CI、邮件、后台迁移等)。
3. jemalloc 内存分配器调优(节省约 0.3 GB)
GitLab 使用 jemalloc 作为内存分配器。通过调整其 decay 策略,可以让内存更快归还给操作系统:
ruby
gitlab_rails['env'] = {
"MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000"
}
gitaly['env'] = {
"MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000"
}
原理:jemalloc 默认的 dirty page decay 时间是 10 秒,muzzy page decay 是 15 秒。调低到 1 秒可以让释放的内存更快被 OS 回收,减少 RSS 峰值。
4. Gitaly 并发限制(节省约 0.1 GB)
限制 Gitaly 对单个仓库的并发 RPC 调用:
ruby
gitaly['configuration'] = {
concurrency: [
{ 'rpc' => "/gitaly.SmartHTTPService/PostReceivePack", 'max_per_repo' => 3 },
{ 'rpc' => "/gitaly.SSHService/SSHUploadPack", 'max_per_repo' => 3 },
]
}
gitaly['env'] = {
"GITALY_COMMAND_SPAWN_MAX_PARALLEL" => "2"
}
原理 :限制 git push 和 git clone/pull 的并发数,避免大量 Git 操作时 Gitaly fork 过多子进程。
5. 关闭不需要的服务
GitLab 默认启用了大量服务,对于小团队场景很多用不到:
ruby
# 监控相关(小规模部署不需要)
prometheus['enable'] = false
alertmanager['enable'] = false
node_exporter['enable'] = false
redis_exporter['enable'] = false
postgres_exporter['enable'] = false
gitlab_exporter['enable'] = false
# GitLab Agent Server (KAS) - 如果不用 K8s 集成
gitlab_kas['enable'] = false
# GitLab Pages - 如果不需要静态站点托管
gitlab_pages['enable'] = false
pages_nginx['enable'] = false
# Container Registry - 如果不用 Docker 镜像仓库
registry['enable'] = false
6. PostgreSQL 连接数
默认 max_connections 是 200,配合 Sidekiq 并发 5 + Puma 单进程,50 连接足够:
ruby
postgresql['max_connections'] = 50
7. 邮件发送
容器内默认使用 sendmail,但 Omnibus Docker 镜像并不包含 sendmail。如果不需要邮件通知功能,直接禁用:
ruby
gitlab_rails['gitlab_email_enabled'] = false
如果需要邮件功能,可以配置 SMTP:
ruby
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.example.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "your-email@example.com"
gitlab_rails['smtp_password'] = "your-password"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
完整配置示例
以下是适用于低内存环境的完整 gitlab.rb 优化配置:
ruby
# === 基础配置 ===
external_url 'https://gitlab.example.com'
gitlab_rails['gitlab_ssh_host'] = 'gitlab.example.com'
gitlab_rails['gitlab_shell_ssh_port'] = 1022
# === Nginx(反向代理模式)===
nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['proxy_set_headers'] = {
"Host" => "$http_host",
"X-Real-IP" => "$remote_addr",
"X-Forwarded-For" => "$proxy_add_x_forwarded_for",
"X-Forwarded-Proto" => "https",
"X-Forwarded-Ssl" => "on"
}
# === 关闭不需要的服务 ===
prometheus['enable'] = false
alertmanager['enable'] = false
node_exporter['enable'] = false
redis_exporter['enable'] = false
postgres_exporter['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false
gitlab_pages['enable'] = false
pages_nginx['enable'] = false
registry['enable'] = false
# === 内存优化 ===
# Puma 单进程模式
puma['worker_processes'] = 0
puma['exporter_enabled'] = false
# Sidekiq 并发调低
sidekiq['concurrency'] = 5
sidekiq['metrics_enabled'] = false
# PostgreSQL 连接数
postgresql['max_connections'] = 50
# jemalloc 内存分配器调优
gitlab_rails['env'] = {
"MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000"
}
# Gitaly 并发限制
gitaly['configuration'] = {
concurrency: [
{ 'rpc' => "/gitaly.SmartHTTPService/PostReceivePack", 'max_per_repo' => 3 },
{ 'rpc' => "/gitaly.SSHService/SSHUploadPack", 'max_per_repo' => 3 },
]
}
gitaly['env'] = {
"MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000",
"GITALY_COMMAND_SPAWN_MAX_PARALLEL" => "2"
}
# 邮件(按需选择其一)
gitlab_rails['gitlab_email_enabled'] = false
优化效果
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 内存占用 | 4.74 GiB | 3.24 GiB | -1.5 GiB (31.6%) |
| Puma 进程数 | 2-4 | 1 | 减少 66-75% |
| Sidekiq 并发 | 20 | 5 | 减少 75% |
| PostgreSQL 连接 | 200 | 50 | 减少 75% |
| 运行服务数 | 15+ | 9 | 关闭 6+ 服务 |
优化后在 3-5 人并发使用场景下,Web 响应、Git 操作、CI 运行均无明显感知差异。
验证方法
优化后可以通过以下方式确认配置生效:
bash
# 检查 Puma 进程数(应只有 1 个 worker)
docker exec gitlab ps aux | grep puma
# 检查 Sidekiq 并发(应显示 -c 5)
docker exec gitlab ps aux | grep sidekiq
# 查看内存占用
docker stats gitlab --no-stream
# 检查所有服务状态
docker exec gitlab gitlab-ctl status
# 检查死信队列(应为 0)
docker exec gitlab gitlab-rails runner "puts Sidekiq::DeadSet.new.size"
注意事项
-
适用场景:本方案适用于 3-5 人小团队。如果团队规模超过 10 人或 CI 负载较重,建议适当调高 Sidekiq 并发和 Puma worker 数。
-
reconfigure 生效 :修改
gitlab.rb后需要执行gitlab-ctl reconfigure才能生效,Puma 和 Sidekiq 会自动重启。 -
jemalloc 参数 :
dirty_decay_ms和muzzy_decay_ms设为 1000ms 是一个平衡点。设为 0 会让内存归还最快,但可能增加 CPU 开销。 -
邮件功能:禁用邮件后,用户注册、MR 通知等邮件功能将不可用。如需保留,建议配置 SMTP 而非 sendmail。
-
监控 :关闭 Prometheus/Exporter 后,GitLab 内置的监控面板将不可用。如果需要监控,可以保留
gitlab_exporter。