尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

GitLab CE私有仓库搭建与运维:基于Docker Compose的完整实践

发布时间:2026/9/26 17:07:01

资讯中心
01
ARTICLE

GitLab CE私有仓库搭建与运维:基于Docker Compose的完整实践

GitLab CE私有仓库搭建与运维:基于Docker Compose的完整实践
很多团队最开始用 GitHub、Gitee 这类托管平台等仓库一多、成员权限一复杂就发现免费额度根本不够用代码也总有一种“寄人篱下”的感觉。GitLab 私有仓库搭建这几年几乎成了中小团队自建代码托管的标准答案把代码放在自己的服务器上速度快、权限细、还能顺手跑 CI/CD。这篇文章把我从零开始部署 GitLab CE 的完整过程记录下来包括部署选型、详细参数、日常管理、备份维护和一堆踩坑实录希望能给正准备动手的读者省几天时间。1. 部署前想清楚的三件事1.1 硬件配置与规模预估先说结论GitLab 是一个“看起来轻、实际很吃资源”的应用。很多新手给一台 1核2G 的云服务器就敢跑 GitLab CE结果启动没多久就 OOM这是最常见的开局失败方式。按我的实践经验两三人的小团队、仓库体积不大2核4G 勉强能跑起来但磁盘 IO 稍微一忙页面就开始转圈体验很一般。五到十人的团队建议直接 8核16G 起步系统盘至少 50G另外单独挂一块 100G 以上的数据盘放 Git 仓库和数据库备份。为什么这么吃资源因为 GitLab CE 是“全家桶”架构里面同时跑着 PostgreSQL、Redis、Sidekiq 后台任务队列、Puma Web 服务、Nginx 网关还有一堆监控和后台进程。我用 Docker 部署时观察过容器刚启动的瞬间内存峰值能冲到 3G 以上稳定后也要 1.5G 到 2G。开了 GitLab Runner 跑流水线的话内存又要再往上加。磁盘容量反而更该往大里估Git 仓库全是增量提交一个看似不大的项目几年后.git目录膨胀到几个 GB 很正常而且 GitLab 自带的备份机制会生成压缩包备份目录往往是数据目录的一半以上。还有一点很少人提GitLab 的 IO 性能直接影响用户体验。并发 push 和代码检索时机械硬盘的随机读写延迟无法忍受所以我建议操作系统和数据目录分开放GitLab 的持久化数据目录放到 SSD 盘上性能和后续备份都会从容很多。1.2 原生安装还是 Docker 部署部署方式上我直接给出建议除非你已经非常熟悉 GitLab 的 RPM/DEB 包管理体系否则用 Docker Compose 部署是目前性价比最高的方案。这不是偷懒而是给未来的升级、迁移、回滚省下大量时间。原生安装最大的痛点是依赖一致性。GitLab 依赖的 Ruby、PostgreSQL、Redis 版本都有严格对应关系系统升级软件库时很容易把 GitLab 的环境搞坏排查起来非常痛苦。用 Docker 之后整个应用环境被锁在镜像里宿主机只需要装 Docker 和容器运行时升级 GitLab 时替换镜像重新启动就行回滚也只是切回旧镜像的事。镜像版本选型也要注意。目前gitlab/gitlab-ce的 latest 已经走到 17.x 甚至更新版本GitLab 对底层操作系统版本的要求也在不断提高。热搜词里出现 gitlab 19 只支持 Ubuntu 24.04 这类信息指的是原生安装包对宿主机 OS 版本有严格限制如果你用 Docker宿主机是 20.04 还是 24.04 影响不大因为容器内部的基础镜像是独立封装的。不过老旧系统上的 Docker 版本可能偏旧安装 Docker 时还是要确认一下。1.3 域名、端口与 HTTPS 规划GitLab 对外暴露两个入口Web 端的 HTTP/HTTPS默认是 80 和 443SSH 协议的 Git 操作默认是 22 端口。这两个端口规划相当关键尤其是 SSH。很多人部署完发现git clone gitserver:group/project.git连不上十有八九是宿主机 22 端口被自带的 OpenSSH 服务占用了。GitLab 容器内部有自己独立的 SSH 服务需要映射到宿主机的一个非默认端口比如 2222。这样一来clone 地址要写成ssh://gitserver:2222/group/project.git或者给成员配一个 SSH config 文件把 Port 2222 隐藏起来否则第一次教同事拉代码时他们会一头雾水。HTTPS 证书我建议优先用 Lets Encrypt 自动签发。GitLab 自带letsencrypt配置项能自动申请证书但实际用下来我更推荐把 GitLab 放在 Nginx/Caddy 反向代理后面由反向代理统一管理证书和 443 端口。如果纯内网使用自签名证书也不是不行前提是把 CA 证书导入所有开发机的信任列表否则 Git 操作会一直报证书校验失败很影响体验。2. 基于 Docker Compose 的实际部署记录2.1 安装 Docker 并准备持久化目录这一节我直接给一套我在生产环境中验证过的完整流程。先装 Docker 和 Compose 插件Ubuntu 下几条命令搞定这里省略安装过程的具体命令默认读者已经完成了这一步重点讲目录规划。GitLab 容器需要三个持久化目录/etc/gitlab放配置文件/var/log/gitlab放日志/var/opt/gitlab放仓库数据、数据库文件、备份包里面还包含shared、repositories、backups这些子目录。我习惯在宿主机上建一个统一的数据根目录比如/data/gitlab下面再分config、logs、data三个子目录。挂载时注意这三个目录千万不要合并成一个挂载点否则重装容器时配置文件很容易被数据目录里的内容干扰。准备目录的同时要顺手检查一下端口占用情况。GitLab 容器默认暴露 80、443、22 三个端口宿主机上的端口映射我建议这样规划容器 80 映射宿主 8080或直接 80看反向代理怎么接、容器 443 映射宿主 8443、容器 22 映射宿主 2222。端口定下来之后后面所有配置和文档都围绕它写减少认知混乱。还有个小细节GitLab 的external_url配置会影响页面内所有资源的链接地址。如果直接设置成 IP 加端口比如http://192.168.1.101:8080那生成的项目 clone 地址会自动带上这个 IP 和端口后续迁移域名会很痛苦。我建议直接规划好域名哪怕暂时用内网域名也先把external_url写成完整的域名形式后面加 HTTPS 或换 IP 都只是改一个配置的问题。2.2 编写 docker-compose.yml 并启动下面是我实际使用的docker-compose.yml精简版生产环境主要就靠它version: 3.8 services: gitlab: image: gitlab/gitlab-ce:17.0.1-ce.0 container_name: gitlab restart: always hostname: gitlab.example.com environment: GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.example.com nginx[listen_port] 80 gitlab_rails[gitlab_shell_ssh_port] 2222 unicorn[worker_processes] 2 puma[worker_processes] 2 postgresql[shared_buffers] 256MB prometheus_monitoring[enable] false # 备份保留策略 gitlab_rails[backup_keep_time] 604800 ports: - 8080:80 - 8443:443 - 2222:22 volumes: - /data/gitlab/config:/etc/gitlab - /data/gitlab/logs:/var/log/gitlab - /data/gitlab/data:/var/opt/gitlab shm_size: 2g ulimits: nofile: soft: 1048576 hard: 1048576几个配置点我说一下原因。hostname要和external_url里的域名保持一致否则邮件链接和 clone 地址会错乱。gitlab_shell_ssh_port是让 GitLab 知道 SSH 服务被映射到了哪个外部端口这样页面生成的 SSH clone 地址会自动带:2222成员复制就能直接用不需要手动改。内存优化方面我关掉了 Prometheus 监控这个组件单独就要占几百 MB 内存小团队用不上可以先关掉。unicorn我改成puma新版本默认是 Puma不再是旧文档里的 Unicorn。postgresql[shared_buffers]设成 256MB 是给数据库缓存兜底避免默认值过大挤占容器内存。shm_size: 2g很关键GitLab 内部组件大量使用共享内存默认 64MB 太小会导致页面加载时报No space left on device这类诡异错误。启动命令就一条docker compose up -d然后docker compose logs -f gitlab看启动日志。第一次启动大概要三到五分钟看到curl探测返回 200 或者日志里出现GitLab is ready字样就说明起来了。2.3 初始化配置与首次登录GitLab 启动完成后默认初始化密码放在容器内的/etc/gitlab/initial_root_password文件里有效期为 24 小时。先执行这条命令拿到密码docker exec gitlab cat /etc/gitlab/initial_root_password文件里只有一行Password: xxx拿到后立刻用root登录 Web 界面。第一次登录系统会强制要求改密码这个流程没什么坑但有两件事建议紧接着做一是开启两步验证GitLab 管理员的账号一旦泄露整个代码库都危险二是在「偏好设置」里把默认语言改成中文界面汉化虽然不是 100% 完整但主要功能菜单都能看懂。紧接着要检查页面顶部提示的“检查管理员的用户名和邮箱”。GitLab 新版本强化了管理员账号的安全性如果 root 的邮箱还没确认系统会一直出现警告条。到「管理区域 → 用户」里找到 root把邮箱确认状态改一下警告条就会消失。这个阶段如果遇到 Web 页面打不开优先看两处一是docker ps确认容器状态不是 “Restarting”二是docker logs gitlab 21 | tail -50绝大多数启动失败都是端口被占或配置语法错误。配置文件在宿主机/data/gitlab/config/gitlab.rb改完必须执行docker exec gitlab gitlab-ctl reconfigure让配置生效只重启容器是不够的。2.4 从第一天起就做对的 HTTP 和 SSH 配置很多人把 GitLab 跑起来之后就要开始建仓库这没错但有些配置最好第一天就做完不然后面改起来成本很高。第一件是统一 SSH 使用习惯。GitLab 的 SSH clone 地址默认有两种展示格式githost:group/project.git和ssh://githost:port/group/project.git。当我把容器 22 映射到宿主 2222 后页面会自动生成带端口的ssh://格式。为了让团队成员的 clone 命令更简洁我建议在每台开发机的~/.ssh/config里加一段Host gitlab HostName 192.168.1.101 User git Port 2222 IdentityFile ~/.ssh/id_ed25519这样 clone 地址就变成了gitgitlab:group/project.git好看又好记。这个配置文件在管理和迁移时非常有用后面换服务器 IP 了只改开发机的HostName就能继续用。第二件是限制 Web 端直接 push。GitLab 允许用户在 Web 页面直接编辑文件并提交这对新手很友好但生产仓库很容易因为手滑改坏代码。最好在「项目 → 设置 → 仓库 → Protected branches」里把主干分支设置为Developers can merge同时取消Allow force push这样主干只能在本地改完再推送Web 编辑按钮会变灰。第三件是关掉注册功能。默认情况下 GitLab 的登录页有“注册”链接任何人都能自己注册账号这对私有仓库来说是个安全隐患。在「管理区域 → 设置 → 通用 → 注册限制」里关闭“启用注册”然后去「用户列表」里手动创建成员账号。私有仓库的成员管理必须由管理员一手控制这是最基本的权限边界。3. 日常管理项目、用户与权限3.1 创建项目并导入已有代码GitLab 建项目本身没什么难度填个名称、选可见性等级就行难点在权限分级。私有仓库的项目可见性有三个级别Private仅项目成员可见、Internal登录用户可见、Public所有人可见。企业内部代码我建议全部设 Private公开的项目单独开辟一个命名空间来放。导入已有代码是很常见的迁移需求。GitLab 支持从 GitHub、Gitee、Bitbucket 甚至其他 GitLab 实例导入用的都是平台自身的 API。如果源平台有大量仓库和成员导入时可以直接把成员关系带过来省去重新配置权限的功夫。从 GitHub 导入时需要先在 GitHub 生成一个 access token这个 token 的权限要至少包含repo和read:org否则导入私有仓库会失败。还有一种土办法也经常用本地中转式导入。把旧仓库 clone 到本地加上新地址的 remote再 push 上去。这种方法对小仓库最省事不依赖 API 平台的兼容性。注意 push 时最好带上镜像参数--mirror能保留所有分支、标签和历史记录。3.2 SSH 密钥配置与 clone 流程新成员入职标配流程一般分三步生成密钥、配置到 GitLab、测试连通。生成密钥的标准公式是ssh-keygen -t ed25519 -C usernamecompany用 ed25519 算法比 RSA 更安全且生成更快我几年前就开始推荐这个算法了。密钥生成后把~/.ssh/id_ed25519.pub的内容整段复制到「用户设置 → SSH 密钥」里有效期可以先不填。测试 SSH 连通性有个经典命令ssh -T gitgitlab如果看到Welcome to GitLab, username!就说明配置成功。如果提示Permission denied (publickey)优先排查是不是连到了错误的端口ssh -T -p 2222 gitgitlab可以显式指定端口试一次。这里有一个很多人没注意的细节同一台电脑上同时使用多个 Git 账号时SSH 密钥会冲突。需要在~/.ssh/config里为不同的 Host 指定不同的IdentityFile比如公司 GitLab 用 work 密钥、GitHub 用个人密钥否则默认只使用id_rsa或id_ed25519经常出现“这个仓库能 clone、那个仓库不行”的诡异现象。3.3 分支保护与权限划分GitLab 的权限模型虽然不是最复杂的但也有几个层级Guest、Reporter、Developer、Maintainer、Owner。Guest 只能看 issueReporter 可以看代码但不可以 pushDeveloper 可以 push 和提 MRMaintainer 可以改项目设置、管理分支Owner 拥有项目的一切权限。我的习惯是核心研发给 Developer组长给 Maintainer管理层默认 ReporterOwner 只保留给项目负责人和方法人角色。分支保护是我在大量实操后越来越重视的功能。默认情况下 GitLab 阻止直接 push 到main分支但很多人没意识到它能做得更细。比如保护 Release 分支禁止任何直接 push只允许通过 MR 合入保护测试环境专属分支限制只有 CI 机器人能写。这些保护规则在「项目 → 设置 → 仓库 → Protected branches」里配置每增加一条就是给团队作业流程上一层保险。另外一个容易被忽略的机制是 Code Owners。在代码仓库里添加CODEOWNERS文件指定特定目录下文件的变更必须经过对应负责人的 approve这样就能做到“基础设施代码必须过运维的 MR业务代码必须过组长”的精细管控。这个功能对中大型团队很有价值配置一次后续的 MR 流程会自动检查。4. 备份、恢复与更新升级4.1 备份策略与手工复盘部署完成后的最重要的事不是建仓库而是定好备份策略。GitLab 官方提供了内置备份工具gitlab-backup create它会打包数据库、仓库文件、上传、用户数据在容器执行命令是docker exec -t gitlab gitlab-backup create备份包生成在/var/opt/gitlab/backups目录对应宿主机挂载的/data/gitlab/data/backups。默认备份包按时间戳命名比如1720000000_2024_07_04_17.0.1_gitlab_backup.tar文件名里带版本号恢复时版本必须一致这点后面会重点说。光有备份还不行要定期做恢复演练。我见过不少团队“备份了三年、恢复时却出问题”的悲剧因为备份文件在磁盘上静默损坏是常态定期验证备份完整性比备份本身更重要。我的建议是每周全量备份一次保留最近七天然后把一份备份包通过scp或rclone同步到另一台机器防止服务器整体故障时备份也跟着没了。恢复流程也要提前测一遍。标准的恢复命令是docker exec -t gitlab gitlab-backup restore BACKUP1720000000_2024_07_04_17.0.1执行后会弹出一个确认提示输入yes继续。恢复前必须停止相关服务避免数据库写入导致数据不一致。我在测试环境演练过多次流程本身不复杂但如果你是第一次做强烈建议找一台闲置服务器完整走一遍真正出故障的时候才不至于手忙脚乱。4.2 跨版本升级中的坑GitLab 升级是私有仓库维护里最容易翻车的事。它的升级策略是“逐小步频升级”官方明确不建议跨越多个大版本直接升。比如从 15.0 到 17.0必须先升 15.x 最后一版再升 16.x最后到 17.x。原因是数据结构和配置文件的迁移脚本是按版本递进的跨太大可能直接报错。用 Docker 升级的常规操作是改镜像标签再重建容器。比如当前是 17.0.1要升到 17.0.2把镜像 tag 改掉执行docker compose pull后再次up -d。升级前务必备份尤其是数据库备份这是唯一能让你在升级失败后全身而退的后路。升级中有一类问题容易被忽略默认配置项因为版本更新变得不兼容。GitLab 的gitlab.rb里的很多配置项在升级后可能被移除或改名重新配置时会打印DEPRECATED警告。所以升级完成后要习惯性看一条命令docker exec gitlab gitlab-rake gitlab:check它会输出各项组件状态比如Database schema is up to date、Redis version is compatible等。看到红字再逐个排查不要直接开新功能。5. 常见问题排查实录5.1 账户审批与登录异常问题热词里有一条很典型“your account is pending approval from your gitlab administrator”。这种情况通常发生在管理员开启了注册审批模式用户注册后不会自动激活必须等管理员审核。解决方法是登录管理员账号进入「管理区域 → 用户」页签在“待审批”列表里找到目标用户点击批准并设置初始密码后告诉用户。把这个问题放大来看团队协作时要避免管理员的账号变成瓶颈。我建议明确一位甚至两位管理员各自拥有独立的管理员账号而不是所有人都共用一个 root。不然某位管理员请假了新人入职就卡在审批环节非常尴尬。还有一个登录常见报错“Login failed. Check API token or GitLab version. Log in via Git if the version is too old”或类似提示。遇到这种问题先别慌这个报错通常出现在旧版本 GitLab 的 API 兼容性上你的 Git 客户端或者某些自动化工具调用 API 时走不通了。排查思路分三步先确认 GitLab 版本和 Git 客户端版本是否过旧再确认 API token 是否有效最后确认调用的接口路径是否被新版弃用。如果是一台老服务器上几年前的 GitLab最稳妥的出路是升级到当前支持的版本。5.2 Docker 方式 GitLab 内存占用过高GitLab 吃内存是永恒的吐槽点热词里专门有一条 “docker gitlab 占用内存过多”。我实测过默认配置下 GitLab CE 启动后内存轻松超过 3G主要是 Prometheus 监控、Grafana、Sidekiq 和 Puma 在竞争资源。我的优化组合拳是这样的第一关闭 Prometheus 和系统监控相关组件。部署 yml 里设置prometheus_monitoring[enable] false内存立刻降一截。第二限制后台任务并发。Sidekiq 默认队列并发数很高在配置里加上sidekiq[concurrency] 10左右能明显降低内存峰值。第三Puma 的 worker 数设置成和 CPU 核数相当别用默认的最大值在每个 worker 上能省不少内存。这样优化下来4G 内存的小服务器跑一个小团队还是有机会的。但是真到了几十人的规模我还是建议加内存毕竟 GitLab 的内存增长是和活跃用户数、并发操作数强相关的。5.3 .pack 文件过大与仓库瘦身热词里有条很具体“gitlab pack-xxx.pack 文件很大”。这个问题我遇到太多次了典型的场景是有人误把构建产物、依赖包、大文件提交进了 Git 历史而且是从项目早期就混进去的后期怎么删文件都没用因为 Git 的历史里还存着这些对象的快照。排查方法很简单先看哪个.pack占用最多du -sh /data/gitlab/data/repositories/**/*.git找到体积异常的仓库后可以用git count-objects -vH查看对象数量确认是历史大对象的问题。修复思路是用git filter-repo清理历史或者用 GitHub 风格的git filter-branch不太推荐慢且易错。更省事的方法是把当前代码导出成一个全新仓库把历史记录全部舍弃——很多团队最后就是走这条路毕竟“历史不重要”比辛辛苦苦 rewrite 历史省事得多。如果还希望保留历史可以使用 Git LFS 把大文件剥离出去。GitLab 自带了 LFS 支持把大文件走 LFS 之后.git目录会明显瘦下来但要注意 GitLab 的 LFS 存储也会占磁盘还是要定期做清理。5.4 代码量与注释率统计热词里有“gitlab 仓库代码量和注释率统计”这个问题几乎每个周期汇报前都会有人来问。GitLab 本身没有内置的代码量统计报表但它的 API 和第三方工具可以完成这件事。基础的做法是直接看仓库的提交历史统计每个工程的分支、Tag、成员提交数进阶做法是用git log --since --until --author组合出某时间段的代码提交量脚本写起来也不复杂。更严格一点的统计靠第三方工具比如 Cloc、GitStats、SonarQube 的代码分析能力来统计注释率和重复率。我的经验是不要过度纠结“代码量”这个指标。行数只能说明“生产了多少行”说明不了“删了多少行”、“重构了多少”。我自己做代码统计时更关注的是提交频次、MR 合并周期、评论回复率这类能反映协作质量的指标这些在 GitLab 的各类报表页面里都有现成视图。5.5 HTTPS 证书失效与 clone 地址漂移前面规划 HTTPS 时提过证书这里再补一个常见坑Lets Encrypt 证书默认有效期只有 90 天很多自建 GitLab 到期后证书不会被自动续期导致 Web 页面直接访问不了。排查时用curl -v https://gitlab.example.com看证书过期时间如果确实是证书问题重新跑一次 acme.sh 或者检查反向代理的自动续期定时任务就行。另一个坑是 clone 地址漂移也就是 GitLab 页面生成的 clone URL 时不时变成错误的 IP 或端口。这种问题多半出在external_url和容器端口映射没有对齐。如果你改过端口或加过反向代理记得同步改external_url配置并重新 reconfigure否则页面上的地址还是旧参数。这类“看着像巧合”的问题其实都是配置不一致慢慢积累出来的。6. 实际操作中的感受与建议我把这套 GitLab 私有仓库从部署到日常维护跑了一整年最大的体会是部署本身不难难的是把权限、备份、升级这些“看不见”的部分提前规划好。多数团队其实不缺文档缺的是在出了问题之前就把最佳实践落地。在实际使用中最让我省心的是 Docker 方案带来的可迁移性。有一次要换服务器我直接把整个/data/gitlab目录用 rsync 同步到新机器重新起容器数据原样复现整个过程不到半小时。相比起原生安装这种“目录级迁移”的体验真的是降维打击。如果你想在这个基础上有后续扩展GitLab 的生态里还有 CI/CD 流水线、容器镜像仓库、Wiki 知识库这些配套能力。等团队流程稳定之后它们会是下一个很自然的发力方向。先从一套稳定可靠的私有仓库开始后面每个扩展都顺理成章。最后再分享一个小技巧在 GitLab 的「管理区域 → 设置」里把“项目删除保护”打开要求用户输入项目名才能删除。这个功能看起来不起眼却能防止手滑把整段历史断送掉我建议每一位管理员都去开。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。