GitLab Omnibus Docker 内存优化实战:从 4.7 GiB 降到 3.2 GiB

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 pushgit 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"

注意事项

  1. 适用场景:本方案适用于 3-5 人小团队。如果团队规模超过 10 人或 CI 负载较重,建议适当调高 Sidekiq 并发和 Puma worker 数。

  2. reconfigure 生效 :修改 gitlab.rb 后需要执行 gitlab-ctl reconfigure 才能生效,Puma 和 Sidekiq 会自动重启。

  3. jemalloc 参数dirty_decay_msmuzzy_decay_ms 设为 1000ms 是一个平衡点。设为 0 会让内存归还最快,但可能增加 CPU 开销。

  4. 邮件功能:禁用邮件后,用户注册、MR 通知等邮件功能将不可用。如需保留,建议配置 SMTP 而非 sendmail。

  5. 监控 :关闭 Prometheus/Exporter 后,GitLab 内置的监控面板将不可用。如果需要监控,可以保留 gitlab_exporter

参考

相关推荐
我是Superman丶9 小时前
Docker 命令自用
运维·docker·容器
ai产品老杨10 小时前
深度解析:基于 Docker 与 GB28181 的企业级 AI 视频管理平台——实现 X86/ARM 异构计算与全场景边缘计算架构
人工智能·docker·音视频
Slow菜鸟10 小时前
Docker 学习篇(七)| 实战 — 用 Docker 构建 SpringBoot + Vue 全栈项目
spring boot·学习·docker
树下水月11 小时前
docker 常用命令
docker·容器·eureka
好奇的菜鸟12 小时前
Java开发常用中间件,Docker安装。
java·docker·中间件
=蜗牛=13 小时前
Docker 简单部署 ClickHouse 超详细图文步骤
clickhouse·docker·容器·部署·图文
Slow菜鸟14 小时前
Docker 学习篇(五)| Docker 常用命令
学习·docker·容器
梵得儿SHI15 小时前
(第三篇)Spring AI 架构设计与优化:容器化与云原生部署,基于 K8s 的 AI 应用全生命周期管理
java·ci/cd·docker·云原生·kubernetes·容器化·spring ai
m0_7375393715 小时前
基于LNMP的综合实验
容器·kubernetes