
最近两周我一直在折腾一台老服务器4核8G内存CentOS 7团队从 5 人涨到 15 人代码仓库从 SVN 迁到 Git最后定下的方案就是 Docker 部署 GitLab 社区版。GitLab 这东西说实话挺重的——Ruby on Rails 写的自带 PostgreSQL、Redis、Nginx、Sidekiq 一堆组件直接装系统上依赖多、迁移难、升级容易踩雷。用 Docker 部署的话官方镜像把运行环境全部打包装好数据目录挂载到宿主机升级就是换镜像版本备份就是整个目录打包容错率高很多。这篇文章我不讲 Docker 基础概念就按实际经历来写从选型、分盘、配置 docker-compose、初始化、配 SSH 密钥到后面内存爆高、启动卡死、token 校验失败、仓库 pack 文件膨胀这些真实问题怎么排查全过一遍。你只要能照着一路操作下来基本能少走我走过的一大半弯路。1. 部署前要搞清楚的几件事1.1 docker部署gitlab的取舍逻辑有人会问官方不也提供 deb/rpm 包吗直接apt install gitlab-ce不就完了确实可以本地服务器装 Omnibus 包是最传统的做法但有几个痛点第一omnibus 包把 GitLab 所有依赖都集中装进系统目录你升级系统镜像或者尝试迁移机器时很容易把环境搞乱第二GitLab 升级频率很高几乎每个月一个小版本每次升级都要处理系统依赖变更纯手工升级很费时间第三团队环境里不只有 GitLab还跑着 CI runner、内网 DNS、项目文档站等一堆服务容器化之后资源隔离和编排都要方便得多。Docker 部署 GitLab 社区版核心思路是让 GitLab 跑在官方镜像的隔离环境里数据、配置、日志分别挂载到宿主机三个目录。这样宿主机是什么系统反而没那么重要了只要 Docker 能跑镜像照常运行。我之前在 CentOS 7 上装的 GitLab 偶尔会因为系统 openssl 库太老导致 HTTPS 握手出问题容器化之后镜像自带依赖这种问题直接消失。另一个容易被忽略的点是资源限制。Docker 可以给 GitLab 容器加--memory和--cpus参数直接锁死最大资源占用。GitLab 默认开启 Prometheus 监控全家桶内存动不动吃到 4G如果你不想让它在宿主机上抢占太多资源容器化是唯一可以干净利落做限流的方式。1.2 硬件红线内存到底怎么算GitLab 官方文档建议最低 4GB 内存实测这是个能启动但很憋屈的数字。我自己的感受是2GB 能跑但频繁卡死4GB 勉强能用8GB 才比较舒适16GB 以上对 50 人左右的小团队来说就很宽裕了。为什么会这么吃内存分解一下主要组件组件用途大致内存占用pumaRuby 应用服务器处理 Web 请求500MB - 1GBsidekiq后台任务队列处理邮件、CI、仓库大小计算等500MB - 1.5GBpostgresql主数据库300MB - 600MBredis缓存与任务队列100MB - 300MBprometheus exporter监控与指标采集500MB - 1GBnginx反向代理20MB - 50MB看到没光 Prometheus 监控全家桶就能吃掉将近 1GB。如果你的服务器内存只有 4GB部署完第一件事就该把监控组件关掉这个我后面第 5 章会给具体配置方法。磁盘方面GitLab 仓库、数据库、日志都在/var/opt/gitlab这个挂载目录里日志膨胀速度比你想的快得多尤其是频繁 push 大文件、跑CI 的时候。建议分一块独立数据盘至少留 50GB 空闲空间给数据卷生产环境按团队规模再往上加。我在部署时把整个$GITLAB_HOME放在了单独的 LVM 逻辑卷上这样万一系统盘挂了数据不受影响。1.3 镜像选型ce 还是 eelatest 还是锁版本Docker Hub 上官方镜像有gitlab/gitlab-ce和gitlab/gitlab-ee两个系列。社区版功能对绝大多数团队足够用了代码托管、分支保护、Merge Request、Issue 管理、CI/CD、容器镜像仓库都有。企业版多出来的主要是 LDAP 高级集成、审计事件、合规功能这些小团队基本用不上。所以直接用gitlab/gitlab-ce就好别选 ee否则你还要申请试用许可证到期不激活一部分功能会锁。镜像标签方面生产环境千万别用latest。为什么latest每次拉取都会追上最新版本而 GitLab 的升级路径要求跨大版本不能直接跳比如 15 升 17官方要求先升到 16 的某个中间版本。你用latest换上去可能容器直接起不来因为数据库迁移链条断了。正确做法是锁定一个大版本的具体 tag比如gitlab/gitlab-ce:17.4.1-ce.0稳定跑一段时间确认没问题再按官方升级路径逐步升。1.4 域名、端口和访问路径规划部署前最重要的一个决定GitLab 对外访问的根地址也就是external_url。它会直接写入 GitLab 配置影响 clone 地址、webhook 回调、CI 脚本里自动生成的 URL。我见过有人部署完不设置 external_url默认配置变成http://localhost然后团队成员访问时 URL 全是乱的。端口规划上Web 默认用 80 和 443SSH 默认用 22。现实问题是宿主机上 22 往往已经被系统 SSH 占用了所以容器映射时要把 GitLab 的 SSH 端口映射到 2222 或者其他自定义端口。后面 clone 的时候不能用githost:group/project.git这种简写而要用ssh://githost:2222/group/project.git或者改~/.ssh/config来解决这个我第 4 章详细说。如果打算用 HTTPS得有域名和证书。可以映射 443 端口并在 external_url 里写https://git.example.com然后把证书放到挂载目录的 ssl 子目录。没域名的内网环境就用 HTTP IP 地址完全够用。2. 实操第一步环境准备与 Docker 安装2.1 Linux 上的 Docker 安装Ubuntu/CentOSDocker 部署 GitLab 的前提环境很简单装好 Docker Engine 和 Docker Compose。Ubuntu 和 CentOS 的安装方式网上都有我这边快速过一遍我用的命令。Ubuntu 22.04 上安装 Dockersudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl enable --now dockerCentOS 7 上安装 Dockersudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl enable --now docker安装完确认docker --version和docker compose version都能正常输出。有个细节新版本 Docker Compose 是插件方式命令是docker compose中间有空格不是老式的docker-compose。网上很多教程还在写老命令如果你的机器装的是新版记得把所有docker-compose替换成docker compose。2.2 Windows 上用 Docker Desktop 的坑如果你是在 Windows 本地先做测试或者临时环境通常会装 Docker Desktop。这个工具本身很好用但有两个问题我遇到得最多一是启动时提示 virtualization support not detected二是 Docker Desktop 启动后 Docker Linux 环境连不上报类似failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinux的错误。第一种情况八成是 Windows 的虚拟化功能没开。去控制面板 - 启用或关闭 Windows 功能把 Hyper-V 和Windows 虚拟机监控程序平台这两项勾上重启电脑再打开 Docker Desktop。注意 Windows 家庭版没有 Hyper-V可以用 WSL2 后端需要在Windows 功能里勾选适用于 Linux 的 Windows 子系统。另外 BIOS 里的 VT-x / AMD-V 也必须开启这个在性能好的笔记本上基本默认开了老机器很可能被厂商关掉。第二种情况通常是 Docker Desktop 底层的 WSL2 发行版状态乱了。修复方法很直接右键 Windows 终端管理员运行wsl --shutdown再打开 Docker Desktop如果还不行去 Docker Desktop 设置里选WSL 2 based engine重启一次软件。实测下来 90% 的问题能解决。2.3 Docker Compose部署 GitLab 的组合工具有人会用docker run一条命令拉 GitLab但我不推荐。因为 GitLab 容器有端口映射、环境变量、三个数据卷、重启策略参数一大堆串在一条命令里既不直观也不好维护。用 Compose 文件所有配置都写进 YAML改配置、备份、恢复都方便。Compose 在这里真正解决的是配置声明和生命周期管理问题。你写一个docker-compose.yml启动、停止、查看日志都是docker compose up/down/logs清晰明确。GitLab 本身可以是单容器但配 CI 的时候你可能还会在这个 compose 文件里挂一个 gitlab-runner那时候 Compose 的优势就更明显了。3. 完整部署从 compose 文件到首次登录3.1 目录结构和 compose 配置在开始之前先规划好数据目录。我建议这样组织/home/gitlab/ ├── config/ # GitLab 配置文件对应容器 /etc/gitlab ├── logs/ # 日志对应容器 /var/log/gitlab └── data/ # 仓库、数据库对应容器 /var/opt/gitlab然后新建/home/gitlab/docker-compose.ymlservices: gitlab: image: gitlab/gitlab-ce:17.4.1-ce.0 restart: always container_name: gitlab hostname: git.example.com environment: GITLAB_OMNIBUS_CONFIG: | external_url http://git.example.com gitlab_rails[gitlab_shell_ssh_port] 2222 ports: - 80:80 - 443:443 - 2222:22 volumes: - /home/gitlab/config:/etc/gitlab - /home/gitlab/logs:/var/log/gitlab - /home/gitlab/data:/var/opt/gitlab shm_size: 256m有几个配置项我多说几句。restart: always保证宿主机器重启后容器自动拉起GitLab 这种服务没人会希望宕机后手动去 start。GITLAB_OMNIBUS_CONFIG是环境变量形式的配置入口。你可以在这里直接写 gitlab.rb 里的大部分配置项容器初始化时会自动生成/etc/gitlab/gitlab.rb。后面要调优内存、关监控也是改这个环境变量然后重启容器。shm_size: 256m很重要。GitLab 内部用的 Ruby 服务对共享内存敏感官方文档明确建议至少 256MB。不设置的话默认 64MB遇到高并发时可能出现奇怪的段错误或者 puma worker 频繁崩溃。hostname建议和external_url里的域名保持一致这样容器内部生成的项目 URL、邮件里的链接才不会写错。3.2 启动、初始化等待与状态确认进入/home/gitlab目录执行cd /home/gitlab docker compose up -d第一次启动不是秒开的。GitLab 要先准备数据库、跑迁移、生成密钥、启动一堆内部服务整个过程短则三五分钟长则十来分钟取决于机器性能和磁盘速度。期间不要反复重启容器容易把初始化流程打断。查看启动进度用docker compose logs -f能看到类似puma: starting、gitlab-workhorse: starting之类的日志。等yarn install和gitlab:setup这些流程走完日志里出现Listening on...或者Configuring GitLab之类的字样基本就快好了。然后浏览器访问你配置的external_url比如http://git.example.com。如果打不开先确认宿主机防火墙有没有放行 80/443/2222 端口sudo firewall-cmd --permanent --add-port80/tcp --add-port443/tcp --add-port2222/tcp sudo firewall-cmd --reload3.3 首次登录root 密码与基础设置GitLab 17.x 之后的版本在首次访问页面会让你自己设置 root 超级管理员的初始密码直接填两遍就可以登录了。但有一点要注意如果你设置了GITLAB_ROOT_PASSWORD环境变量那么初始密码由环境变量决定首次访问不会再出现设置页面。老版本15.x 及更早没那么人性化初始 root 密码会生成在容器内的/etc/gitlab/initial_root_password文件里且这个文件只在首次启动后 24 小时内存在过期自动删除。现在如果在 17.x 上没看到设置页可以进容器里看下这个文件docker exec -it gitlab cat /etc/gitlab/initial_root_password登录之后第一步点右上角头像进入 Preferences把语言切到简体中文顺手把 root 密码改掉改成自己的安全密码。第二步去 Admin Area - Settings - Sign-up restrictions把 Sign-up enabled 关掉不然任何人都能注册账号内网环境尤其要关。3.4 创建项目和导入现有代码登录后创建项目有三种方式新建空仓库然后git remote add指向本地已有代码通过 HTTP URL 直接导入 GitHub、Bitbucket 等平台的项目从本地磁盘通过 Web 上传项目文件最常用的还是第一种。假设你在本地已经有一个项目迁移流程是这样cd my-project git init -b main git add . git commit -m init project # 在 GitLab 新建空项目后把它作为远程仓库 git remote add origin http://git.example.com/group/my-project.git git push -u origin main推代码时可能提示认证用 root 账号的密码或者去 Settings - Access Tokens 生成一个 Personal Access Token 作为密码。导入私有 GitLab 仓库还有一种方式如果目标是另一个 GitLab 实例可以在创建项目时选择Import project - GitLab.com / GitLab self-managed填源实例的 URL 和 access token。团队从旧服务器迁到新 GitLab 时这个方法非常省事。4. 团队协作配置与代码统计4.1 SSH 密钥clone 不再输密码用 HTTP 方式 clone 和 push每次都要输入用户名密码一天下来烦得要死。配置 SSH 密钥是用了就回不去的体验。首先要说的是我们前面把 GitLab 的 SSH 端口映射成了宿主机 2222所以密钥配置完之后的 clone 地址会有点特殊。先在本机生成密钥ssh-keygen -t ed25519 -C youexample.com -f ~/.ssh/id_ed25519 cat ~/.ssh/id_ed25519.pub把公钥复制到 GitLab - Preferences - SSH Keys 页面粘贴保存。然后在克隆项目前要处理端口问题。GitLab 默认 SSH 端口在 Web 界面上显示的是ssh://gitgit.example.com:2222/group/project.git直接复制这个地址 clone 就行。如果你更习惯githost:path的简写方式需要在~/.ssh/config里加一段Host gitlab HostName git.example.com Port 2222 User git IdentityFile ~/.ssh/id_ed25519这样写完后clone 时可以简写成git clone gitlab:group/project.git有一点要说明GitLab Web 界面上生成的 clone 地址是根据external_url和gitlab_shell_ssh_port自动拼接的。如果你发现 Web 上显示的 SSH 地址还是默认 22 端口说明gitlab_shell_ssh_port没有生效回去检查 GITLAB_OMNIBUS_CONFIG 里的配置确认容器是否有重新 configure。4.2 成员角色权限划分GitLab 的权限模型是按角色分级的掌握这一套基本就能理清团队协作角色主要权限Guest只能看 Issue 和评论看不到代码Reporter可以看代码、提交 Issue、创建代码片段Developer可以 push 代码、管理 Wiki、创建分支Maintainer管理仓库设置、合并请求审批、标签和受保护分支Owner最高权限能移除仓库、修改项目可见性小团队常用组合是开发人员给 Developer技术负责人给 Maintainer产品/测试给 Reporter。注意受保护分支默认只有 Maintainer 可以合并提交开发如果要直接推到 main 分支需要调整规则。4.3 代码量与注释率统计热搜词里有个gitlab仓库代码量和注释率统计说实话 GitLab 免费版自带的分析功能很弱只有一页 Insights 基础图表。实战中用命令行反而更高效。统计代码行数可以用cloc这个工具多个语言的注释率直接算出来cloc --by-file --by-percent-calculated .它会把每种语言的文件数、代码行、注释行、空白行都列出来最后还能给出注释占比。统计提交量用 git log# 统计每个作者提交次数 git shortlog -sn --all # 按日期统计每天提交数 git log --prettyformat:%ad --dateformat:%Y-%m-%d | sort | uniq -c如果是想给项目组做个阶段汇报这些命令足够用了。曾经有个项目我们用它统计出某位同事一个月提交了 800 多次然后又发现同一个功能反复修改 20 多次数据一摆出来评审会上大家都很安静。数据不会骗人前提是你把它拉出来。5. 踩坑实录常见问题与排查5.1 内存占用过高一个配置项省掉 1GB我部署完第一次用docker stats查看那个数字有点吓人——容器直接吃掉了 4.7GB 内存。排查完发现大头在 Prometheus 及其全家桶 exporter。GitLab Omnibus 包默认会把 Grafana、Prometheus、Alertmanager 都启起来哪怕你根本没配告警。在docker-compose.yml的 GITLAB_OMNIBUS_CONFIG 里改成下面这样GITLAB_OMNIBUS_CONFIG: | external_url http://git.example.com gitlab_rails[gitlab_shell_ssh_port] 2222 prometheus_monitoring[enable] false grafana[enable] false alertmanager[enable] false node_exporter[enable] false redis_exporter[enable] false postgres_exporter[enable] false gitlab_exporter[enable] false puma[worker_processes] 2 puma[min_threads] 1 puma[max_threads] 4 sidekiq[max_concurrency] 5 sidekiq[min_concurrency] 2改完执行docker compose up -d容器会做一次 reconfigure等两分钟再用docker stats看内存基本能降到 2.5GB 左右。这个优化对 4GB 小内存机器来说是救命级别的。这里有个改配置的坑你直接进容器改/etc/gitlab/gitlab.rb当然也行但容器一旦被重新创建这个文件会被环境变量重新覆盖。所以所有持久化配置都应该写在 docker-compose.yml 的GITLAB_OMNIBUS_CONFIG里别折腾容器内部文件。5.2 启动失败/卡在 500磁盘、权限与 swapGitLab 启动后访问页面直接 500或者容器一直处于 unhealthy 状态十次里有八次是下面三个问题。第一挂载目录权限不对。容器内部以git用户运行UID 是 1000。如果宿主机上/home/gitlab目录权限不是 1000:1000GitLab 写数据报 Permission denied各种组件起不来。解决sudo chown -R 1000:1000 /home/gitlab第二磁盘满了。GitLab 的日志和数据库增长很快尤其是跑了 CI 之后。用df -h看看数据盘容量如果满了先清理日志再扩容。docker system logs 不能自动清理建议在 /etc/logrotate 里对$GITLAB_HOME/logs配置轮转策略。第三swap 空间不足会导致容器被 OOM Killer 杀掉。如果你的机器内存 4GB 以下强烈建议加 2GB swapsudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile在/etc/fstab里加一行/swapfile swap swap defaults 0 0保持开机自动挂载。5.3 Docker Desktop 的 virtualization support 报错这个问题在 Windows 上很经典。完整报错是 virtualization support not detected docker desktop failed to start because v...。核心原因就是虚拟化功能没开或者被占用。排查顺序我建议这样来Windows 功能里勾选 Hyper-V Windows Hypervisor Platform或者勾选适用于 Linux 的 Windows 子系统后用 WSL2 后端重启机器后进入 BIOS确认 Intel VT-x / AMD SVM 已开启如果机器装了老版本的 VirtualBox、VMware可能会抢占 Hyper-V 的虚拟化层Docker Desktop 起不来关闭它们再试补充一个我踩过的细节如果用的是 WSL2 后端并且之前手动安装过 WSL 发行版有时候 WSL 内核版本太旧会导致 Docker Desktop 在启动阶段卡住。wsl --update更新内核到最新就行。5.4 docker 网络不通容器内无法访问外网GitLab 容器里偶尔需要访问外网比如 clone 外部仓库、拉取依赖这时候如果网络不通要先分清是宿主机无法访问外网还是容器出口被防火墙拦了。排查docker exec -it gitlab bash -c ping -c 4 8.8.8.8 docker exec -it gitlab bash -c curl -I https://example.com如果 ping 通但 curl 超时一般是 DNS 问题看/etc/resolv.conf里的 DNS 是不是写成了宿主机内网地址。改为宿主机可用的 DNS 服务器或者直接把network_mode: bridge改成network_mode: host试试。后者让容器和宿主机共享网络栈基本能绕开 bridge 网络的 NAT 问题但代价是端口直接暴露安全性自行评估。另外常见坑宿主机开启了 firewalld 或 ufw默认会阻断 Docker 的 FORWARD 链流量。可以临时关掉验证sudo systemctl stop firewalld如果能通就是防火墙规则问题需要放行 docker 网段。5.5 login failed. check api token or gitlab version这个报错跑开发工具时经常看到比如某些 IDE 的 GitLab 插件、CI 脚本里调 API 时。报错完整意思是想让我们检查 API token 是否正确或者 GitLab 版本是否和客户端兼容。我遇到过的原因有三个Personal Access Token 过期了。去 GitLab 设置里重新生成注意勾选apiscope用的 API 地址不对。新版 GitLab API 根路径是/api/v4/有些老客户端默认请求/api/v3/自然校验失败GitLab 版本太老客户端用了新版 API。这时候只能升级 GitLab 或者换兼容的客户端工具顺便说一句如果你用的密码是账号密码而不是 tokenGitLab 17 之后 Web 登录已经完全支持但 API 调用还是建议走 token安全性更高也更容易管理权限范围。5.6 仓库 pack 文件很大项目仓库的.git目录越来越大最典型的现象就是git clone越来越慢甚至直接卡死仓库里一堆pack-xxx.pack文件巨大。根本原因通常是提交历史里混入了大文件比如不小心把 500MB 的模型文件或者 node_modules 压缩包提交进去了。预防方案是用 Git LFS 管理大文件。治疗方案是清理历史推荐用git filter-repo不要用老旧的 filter-branch慢且容易出错git filter-repo --strip-blobs-bigger-than 50M执行完后 force push 到远端同时在 GitLab 后台开启仓库清理功能项目 - Settings - Repository - Repository Cleanup。注意这个操作会重写所有提交哈希团队成员都得重新 clone必须通知到位再动手。如果只是本地感觉 pack 文件大、远端没问题执行git gc --aggressive --prunenow重新打包就行。GitLab 侧也可以在管理页面触发 GC不用单独上服务器。6. 备份、升级与运维心得6.1 备份方案不能只备份容器Docker 部署 GitLab最容易犯的错误就是想着docker commit做个镜像就算备份了这是大错。GitLab 数据分为两部分代码仓库和数据库由 GitLab 自带的备份机制处理配置文件和密钥必须单独备份否则恢复后仓库界面能开但 clone 不出代码因为加密密钥对不上。先看 GitLab 自带备份。新版命令是docker exec -t gitlab gitlab-backup create执行完成后备份文件会出现在宿主机/home/gitlab/data/backups/目录下类似1732212345_2024_11_22_17.4.1_gitlab_backup.tar这样的格式。老版本 GitLab 的命令是gitlab-rake gitlab:backup:create写脚本时注意区分版本。另外要把/home/gitlab/config目录整体打包这里面的gitlab.rb和gitlab-secrets.json特别重要。gitlab-secrets.json保存了 Rails 密钥丢了这个恢复后的 GitLab 大概率连登录都进不去。我建议写一个 cron 脚本每天凌晨做一次完整备份保存最近 7 天备份即可#!/bin/bash BACKUP_DIR/backup/gitlab mkdir -p $BACKUP_DIR # GitLab 数据备份 docker exec -t gitlab gitlab-backup create # 备份配置文件 tar czf $BACKUP_DIR/gitlab-config-$(date %F).tar.gz -C /home/gitlab config # 移动数据备份文件到备份目录 find /home/gitlab/data/backups -name *.tar -mtime -1 -exec cp {} $BACKUP_DIR/ \; # 清理 7 天前的备份 find $BACKUP_DIR -type f -mtime 7 -delete挂到 crontab 里0 3 * * * /root/backup_gitlab.sh6.2 恢复从备份到可用恢复比备份麻烦建议在动手前先把恢复流程演练一遍。这里记录一下标准步骤。创建新的 GitLab 容器确保数据目录挂载正确先把容器启动起来把gitlab-secrets.json和gitlab.rb恢复到对应位置把备份 tar 文件放到/home/gitlab/data/backups/执行恢复前停掉相关服务docker exec -it gitlab gitlab-ctl stop puma docker exec -it gitlab gitlab-ctl stop sidekiq docker exec -it gitlab gitlab-backup restore BACKUP1732212345_2024_11_22_17.4.1注意BACKUP后面是备份文件时间戳部分不含_gitlab_backup.tar后缀。恢复过程中会让你确认几次选择yes。恢复完重新 configure 并重启docker exec -it gitlab gitlab-ctl reconfigure docker exec -it gitlab gitlab-ctl restart我在实际恢复时踩过一个大坑恢复了仓库数据但忘了先恢复gitlab-secrets.json登录是能进去了仓库列表也有但所有 clone 都提示 failed因为项目访问令牌和仓库加密密钥全对不上。最后把 secrets 文件恢复并重启容器才解决。所以配置文件的备份永远不要跳过。6.3 升级策略和版本误区Docker 部署 GitLab 的升级逻辑很简单修改镜像 tag重新创建容器。但 GitLab 官方升级路径严格要求不能跨大版本跳级。比如 17.4.x 升级到 18.x得先升到 17 的最新 patch再进入 18。上个月有个热搜词是gitlab 19只支持ubuntu 24.04这其实是 GitLab 对原生安装包的系统兼容性要求我们用 Docker 部署就不受这个限制——GitLab 运行在镜像内部的固定 OS 环境里宿主机是 CentOS 7 还是 Ubuntu 22.04 都不影响。升级前一定先做一次备份然后按这个顺序执行# 1. 修改 docker-compose.yml 中的 image tag # 2. 拉取新镜像 docker compose pull # 3. 重建容器 docker compose up -d # 4. 查看日志确认迁移完成 docker compose logs -f | grep -i upgrade\|migrate升级完成后记得访问一次 Web 界面确认仓库、MR、CI 都正常。我一般会再执行一次docker exec -it gitlab gitlab-rake db:migrate:status确认数据库迁移全部完成。6.4 长期运维的几条心得文章最后分享几个我在实际运维中沉淀下来的习惯纯个人经验。第一是给容器加上资源限制防膨胀。在 docker-compose.yml 里加mem_limit: 4g和cpus: 4GitLab 出问题的时候最多吃到 4GB不会把宿主机拖死。配合监控脚本定期看docker stats内存涨到警戒值就该查截图还是异常消费。第二是日志必须轮转。GitLab 的日志在/home/gitlab/logs下增长非常快默认不轮转的话几个月能把磁盘吃满。在宿主机配置 logrotate 规则对日志目录每天切割、保留 14 天。第三是安全补丁及时打。GitLab 高危漏洞修复方案在社区里讨论过不少回基本都是通过升级版本解决。因为它是 Ruby 应用历史上出过多次 RCE 和存储型 XSS 漏洞官方公告都很及时。平时订阅一下 release 邮件看到高危版本就安排升级窗口别拖。第四是建议另外部署一台 gitlab-runner 容器配合使用。同一台机器上如果 GitLab 和 Runner 共用 Docker 网络Runner 里跑 job 调用 GitLab API 是很顺畅的。并且 Runner 的并发数要控制好我用concurrent 2避免 CI 任务爆掉服务器 CPU。我在部署 GitLab 过程中踩过的坑基本都是配置细节问题好在 Docker 容器的好处就是重新配置、重新创建的成本很低。你有空也建议在测试环境把整套流程跑通一遍再上生产尤其是备份恢复那一环演练过后才能真正放心。现在这套 GitLab 已经稳定跑了快一年团队 15 个人、10 多个项目、日常 CI 量一个月几百次8G 内存的机器跑起来毫无压力这就是我要的结果。