ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

GitLab迁移实战:从CentOS到Docker Compose的数据零丢失指南

GitLab迁移实战:从CentOS到Docker Compose的数据零丢失指南 安全团队又发来漏洞通告GitLab 又爆高危。换以前直接yum update一条命令解决但这次卡住了——那台跑了两三年的 GitLab 还活在 CentOS 原生环境里系统生命周期已经结束软件源里根本没有新版 GitLab 的包。硬扛还是迁移我选了后者把 GitLab 从 CentOS 原生安装迁到了 Ubuntu 上的 Docker Compose全程数据零丢失备份恢复、切换校验、故障排查都完整走了一遍。这篇文章就是那次迁移的复盘把关键命令、版本对齐原则、数据校验清单以及用户反馈最多的几个报错一次说清楚。如果你正准备做 GitLab 迁移或者刚把 GitLab 装进 Docker 正被各种报错折腾这篇可以直接拿来当操作手册。1. 迁移前的清醒账本版本、数据、风险一起摸清1.1 先说清楚这趟迁移到底图什么很多人看到“迁移”两个字就先慌了其实第一步不是动手而是把“为什么迁”想明白。我当时的情况很典型CentOS 7 的生命周期在 2024 年 6 月 30 日正式终止之后整个系统都没有官方安全更新。GitLab 隔三差五就有高危漏洞通告而修复方案基本都得靠升级包但系统源里已经拿不到了。继续留在原地等于让整个代码仓库暴露在已知漏洞面前安全审计这一关就过不去。选择 Ubuntu 的理由很直接Ubuntu LTS 版本维护周期长、社区活跃、硬件兼容性好。选择 Docker Compose 的理由更实际——部署方式统一环境和宿主机隔离升级就是改个镜像 tag 再重启回滚也快而且数据目录固定成三个 volume备份、迁移、灾难恢复都好打理。但这里我得说句实在话Docker 化不等于数据安全容器里的数据一样会丢备份该做还是得做后面我会给一套能直接用的备份脚本。1.2 旧环境信息清单不知道这些别动刀迁移之前一定先把旧环境的信息完整记下来。我自己列过一张清单照着抄就行GitLab 版本查看/opt/gitlab/version-manifest.txt或者执行gitlab-rake gitlab:env:info输出的 GitLab 版本号要记准这是后面版本对齐的依据。数据目录/var/opt/gitlab是主数据目录里面有 repositories仓库、postgresql数据库数据、uploads附件、backups备份产物。配置与密钥/etc/gitlab/gitlab.rb是配置文件/etc/gitlab/gitlab-secrets.json是密钥文件。这两个必须单独备份很多迁移失败都是栽在 secrets 文件上。定制配置external_url、SSH 端口、SMTP 发信、LDAP 对接这些全部在gitlab.rb里用grep -v ^# /etc/gitlab/gitlab.rb过滤出有效配置项逐条记录。业务规模管理员后台里看项目数、用户数、组数、Runner 数、CI/CD 变量数量。这些数字迁移后要逐项核对是“数据零丢失”最直接的证据。我当时把项目数、用户数、最重要的几个仓库的最新 commit 哈希都截图存档了后面校验时对得上心里才踏实。1.3 风险评估最怕的不是丢数据是版本对不上很多人以为迁移最大的风险是数据损坏其实更常见的坑是版本不匹配。GitLab 的备份恢复机制对版本有严格要求备份文件里写死了生成时的 GitLab 版本恢复时目标实例版本太新或太旧都会报错甚至跨大版本强行恢复会导致数据库 schema 错乱。我定的预案是新环境先用 Docker 部署一个和旧环境完全相同的版本恢复备份验证没问题之后再按官方升级路径一步步往上升级。这个过程后面会细说但你可以先把这条原则刻在脑子里——永远不要在全新版本上直接恢复旧备份。另外迁移时间窗一定要选业务低谷。我选的是周五晚上预估停机时间 2 小时实际用了 1 小时 20 分钟回滚方案也提前写好了新环境恢复失败、确认无法短时间内修复时旧机器还保留着原样直接把 DNS 指回旧 IP 就能切回旧环境。2. 新环境搭建Ubuntu Server Docker Compose 一次到位2.1 Ubuntu 系统初始化的几个动作我新装的是 Ubuntu Server 24.04 LTS安装过程不多说重点讲几个容易忽略的初始化动作系统更新apt update apt upgrade -y装完重启一次确保内核也是最新的。主机名和 hosts趁着一开始就把hostname和/etc/hosts配好避免 GitLab 内部依赖主机名的地方出诡异问题。如果你用了域名访问把域名也写进 hosts 指到本机 IP后面测试方便。防火墙如果启用了 UFW放行 80、443HTTP/HTTPS和 2222SSH 映射端口。注意 Ubuntu 默认没开 UFW但安全要求严格的环境通常会开。磁盘规划GitLab 的 data 目录建议独立分区挂载我当时是把一块 500G 的云硬盘挂到/srv/gitlab下面避免系统盘满导致整个实例不可用。2.2 安装 Docker Engine 与 Compose 插件新版 Docker 已经自带 Compose 插件不用再单独装老式的 Python 版docker-compose。直接加 Docker 官方 apt 仓库然后安装sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker docker compose version这里有个经验安装完成后docker compose version能正常输出版本号才算装好。如果你在别的教程里看到docker-compose带横杠的用法多半是老版本语法有差异注意区分。另外把当前用户加进 docker 组可以免 sudo 执行 docker 命令但基于安全考虑生产环境我不太建议这么做老老实实用 sudo 更稳妥。2.3 docker-compose.yml 的关键设计我用的 compose 文件长这样注释写的是我踩过坑之后总结的原因services: gitlab: image: gitlab/gitlab-ce:15.11.13-ce.0 container_name: gitlab restart: always hostname: gitlab.example.com environment: GITLAB_OMNIBUS_CONFIG: | external_url http://gitlab.example.com gitlab_rails[gitlab_shell_ssh_port] 2222 ports: - 80:80 - 2222:22 volumes: - /srv/gitlab/config:/etc/gitlab - /srv/gitlab/logs:/var/log/gitlab - /srv/gitlab/data:/var/opt/gitlab shm_size: 256m几个关键点拆开讲镜像 tag 为什么要写死版本我特意用了和旧环境一致的15.11.13-ce.0这是为了保证备份恢复时的版本兼容。如果你图省事直接写latest后面恢复备份大概率会撞上版本 mismatch 的报错。external_url 要和旧环境保持一致如果域名不变就继续用旧域名。这个值影响所有 webhook 回调、克隆地址、OAuth 回调地址一旦对不上表面上能登录但各种联动功能全乱。SSH 端口映射到 2222容器内部 GitLab SSH 监听的是 22 端口但宿主机的 22 被系统 SSH 占了所以我映射成了2222:22。同时必须在gitlab_shell_ssh_port里告诉 GitLab“对外是 2222”这样 UI 显示的克隆地址才会自动带上端口。三个 volume 的职责config存配置和密钥、logs存日志、data存仓库和数据库。备份、迁移时主要针对data而密钥在config里。shm_size: 256mGitLab 内部组件尤其是 Prometheus 和 PostgreSQL对共享内存有要求默认 64M 在流量上来后容易出奇怪问题比如数据库无响应。这个参数不加后期运维会非常头疼。文件写好后直接启动docker compose up -d docker compose logs -f第一次启动要拉镜像、初始化数据库日志会一直刷等到看到Congratulations! GitLab is running或者gitlab is ready之类的输出再用浏览器访问。3. 数据零丢失的核心链路备份、校验、传输、恢复3.1 版本对齐是第一原则GitLab 的备份文件里记录了生成它的版本号。恢复时目标实例的版本需要与备份版本相同或相近patch 版本差异通常可以接受但我不建议赌。跨大版本直接恢复时报错的典型信息是GitLab version mismatch: You are trying to restore a backup of GitLab 15.11.13 to a GitLab 17.x.x。我当时在旧环境先查了版本cat /opt/gitlab/version-manifest.txt | grep gitlab-ce拿到15.11.13新环境的镜像 tag 就直接写15.11.13-ce.0。等恢复验证通过后再从 15 升 16、16 升 17每一步升级前都做备份。这条路径虽然慢但最安全。3.2 旧环境全量备份一个 tar 包不代表全部备份前先确认磁盘空间充足备份产物通常是仓库、数据库 dump 的集合体几个 GB 很常见df -h /var/opt/gitlab sudo gitlab-rake gitlab:backup:create执行完备份文件出现在/var/opt/gitlab/backups/名字类似1700000000_2024_11_17_15.11.13_gitlab_backup.tar。这个 tar 包里包含数据库、仓库 bundle、上传附件等核心数据。但这里有个绝大多数教程不会提醒你的点备份 tar 包不包含gitlab-secrets.json。这个密钥文件掌管着用户 2FA、webhook 加密、CI/CD 变量加密、Runner 通信密钥。恢复后如果没带过来用户全部要重新绑定 2FAwebhook 和 CI 变量基本全废。所以一定要单独备份配置和密钥sudo tar czf gitlab-config-backup.tar.gz /etc/gitlab/gitlab.rb /etc/gitlab/gitlab-secrets.json把这两个文件打包带走迁移才谈得上完整。3.3 传输与哈希校验备份文件弄好后我用 rsync 传到新服务器的备份目录rsync -avzP gitlab-config-backup.tar.gz 1700000000_2024_11_17_15.11.13_gitlab_backup.tar usernew-server:/srv/gitlab/data/backups/传输完成不是万事大吉一定要做哈希校验。tar 包动辄几个 GB网络传输抖动、磁盘坏道都可能让文件损坏等到 restore 时报错再排查就晚了。我在旧机器和新机器上分别算sha256sum 1700000000_2024_11_17_15.11.13_gitlab_backup.tar两边哈希一致才开始动恢复的脑筋。这一步别省真的是血的教训。3.4 在 Docker Compose 里执行恢复恢复的核心思路是让备份文件出现在容器内的/var/opt/gitlab/backups/目录。因为我们把宿主机/srv/gitlab/data映射成了容器的/var/opt/gitlab所以刚才传到/srv/gitlab/data/backups/的文件容器内已经能看到。先修正文件属主再进入容器sudo chown -R git:git /srv/gitlab/data/backups/ sudo docker compose exec gitlab bash进入容器后停掉可能写数据库的服务避免恢复过程中发生数据竞争gitlab-ctl stop puma gitlab-ctl stop sidekiq然后执行恢复。注意BACKUP后面的参数不带_gitlab_backup.tar后缀gitlab-backup restore BACKUP1700000000_2024_11_17_15.11.13如果你的 GitLab 版本比较老命令可能还是gitlab-rake gitlab:backup:restore BACKUP...实际以官方文档为准。执行过程中会提示确认输入yes继续。恢复完成后gitlab-ctl reconfigure gitlab-ctl restart到这里数据库和仓库已经回来了但还差最后一步把前面备份的gitlab-secrets.json复制到新环境的/etc/gitlab/目录也就是宿主机/srv/gitlab/config/gitlab-secrets.json。这一步最好在容器停止状态下操作复制完再启动容器确保容器不会用新生成的密钥文件覆盖掉旧密钥。然后浏览器访问用管理员账号登录验证密码还是老的因为用户数据已经从备份里恢复了。4. 切换与数据校验旧机器先别急着删4.1 DNS 与访问入口切换如果域名没变external_url 也保持一致那么业务侧几乎无感用户不需要改任何地址。但服务器 IP 变了DNS 的 A 记录必须更新。我当时的做法是切换前 24 小时把 DNS TTL 从默认值调低到 300 秒这样真正切换时全球生效时间能控制在几分钟内。如果只有一部分需要马上验证的人可以先测就在自己电脑上改/etc/hosts把域名提前指到新服务器 IP完整走一遍浏览器登录、克隆、推送、触发 CI 的流程确认没问题再切 DNS。一个容易忽略的细节如果迁移后域名或端口有变化用户本地已有的 remote 地址全都要改得提前通知团队并给一份命令git remote set-url origin gitgitlab.example.com:group/project.git4.2 数据核对清单用数字说话“数据零丢失”不是嘴上说说要用数据验证。我整理了一张核对清单照着逐项打勾核对项方法预期结果项目仓库总数管理员后台统计页与迁移前记录一致用户总数管理员后台用户列表与迁移前记录一致组与子组结构管理员后台组列表层级结构完整重点仓库最新 commitgit ls-remote抽查哈希与迁移前一致用户 SSH Key抽查几个用户后台完整保留2FA 登录实测扫码登录可正常通过Webhook 回调触发一次测试事件回调正常到达CI/CD 变量检查变量值可读没有解密报错Runner 状态管理员后台重新注册后在线仓库层面的抽查我用的方式很直接git ls-remote gitgitlab.example.com:ops/backup-scripts.git HEAD输出的 commit 哈希和迁移前存档的截图一对比是不是一致一目了然。4.3 旧服务器降级与退役数据核对没问题不代表第二天就能把旧机器关机。我建议至少保留两周观察期这两周内旧机器保持只读状态——千万不要再往旧环境里推代码或跑 CI否则新旧两个环境的仓库会产生分叉后面的合并就是一场灾难。观察期内如果发现新环境有解决不了的问题还能把 DNS 切回旧 IP回滚成本极低。两周后确认稳定再做一次旧环境完整备份留档然后才把旧机器关机退役。5. 故障排查实录迁移后最常见的四个报错5.1 login failed. check api token or gitlab version这个报错我迁移后的第一周收到了三次全是用了 GitKraken、VS Code Git 插件这类 GUI 客户端的同事反馈的。报错信息原文是login failed. check api token or gitlab version. log in via git if the version...字面意思很容易让人去怀疑 token 或者版本填错排查链路按顺序来先确认客户端里填的 GitLab 地址是不是还指向旧 IP/旧域名。迁移后地址变了客户端里保存的还是旧地址居然不会主动报连接超时而是绕到 API 校验这一层才炸误导性很强。再重新生成一个 Personal Access Token。迁移后如果 external_url 变了旧 token 的绑定关系可能已经失效。让用户在浏览器登录后进入 User Settings → Access Tokens新建一个有api权限的 token重新填进客户端。最后检查客户端里的 GitLab 版本配置。部分 GUI 客户端允许手动指定 GitLab 版本号用于 API 兼容判断填得和实际版本跨度太大也会报这个错。改成和实际接近的版本或者选自动检测。这里也顺便回答很多人问的“gitlab token 在哪里”登录后左下角头像 → User Settings → Access Tokenstoken 只显示一次生成后必须立刻复制保存。5.2 GitLab 422 登录报错跨环境迁移后422 是另一个高频报错。典型症状是浏览器输入账号密码点登录直接跳 422但是开一个隐身模式窗口却可以正常登录。出现这种情况的第一反应应该是清理浏览器 cookie——老域名下的加密 cookie 还在本地Rails 做 CSRF 校验时发现来源不一致直接拒绝。第二个常见原因是external_url和实际访问地址不一致。比如 external_url 配的是https://gitlab.example.com但新环境还没挂证书有人用http://访问协议对不上就会 422。迁移后第一时间用浏览器地址栏的完整 URL 和 external_url 逐字符比对。如果你前面挂了一层反向代理Nginx、Caddy 之类还要注意在GITLAB_OMNIBUS_CONFIG里加nginx[trusted_proxies] [你的代理IP网段]不配这个GitLab 拿到的用户来源 IP 全是代理的地址在某些场景下也会触发安全校验问题表现就是各种诡异的 422 和登录态丢失。5.3 SSH 拉取代码失败Docker 端口映射的坑迁移到 Docker 版之后“克隆代码连不上”的反馈是最多的。症状要么是Permission denied (publickey)要么是Connection refused但实际上密钥和账号都没问题。真正的坑在于 Docker 端口映射。默认情况下GitLab 在 UI 里显示gitgitlab.example.com:group/project.git但容器内 SSH 监听 22对外映射的却是 2222。如果你没在 compose 里设置gitlab_rails[gitlab_shell_ssh_port] 2222UI 克隆地址不会带端口用户拿着这个地址去 clone自然连 22 端口而宿主机的 22 是系统 SSH 在监听连上去身份对不上就报Permission denied。验证方法很简单ssh -T gitgitlab.example.com -p 2222能出现Welcome to GitLab, username!就说明 SSH 通了。用户侧的长期解决办法是在~/.ssh/config里写一段Host gitlab.example.com HostName gitlab.example.com Port 2222 User git IdentityFile ~/.ssh/id_ed25519这样git clone gitgitlab.example.com:group/project.git就不用手动加-p 2222了。另外提醒一句~/.ssh目录权限必须是 700authorized_keys权限是 600权限过宽 SSH 也会拒绝。5.4 Runner 失联与 CI/CD 配置迁移迁完之后去管理员后台一看Runner 全灰着这是因为 Runner 注册时绑定的还是旧实例的 URL迁移后自然失联。解决方式就是重新注册。到项目或组设置里的 CI/CD → Runners 页面拿到新的注册 token然后在 Runner 机器上执行sudo gitlab-runner register按提示输入新实例地址、注册 token、执行器类型。如果是 Docker executor还要确认 runner 机器能访问到新 GitLab 地址网络策略别漏放。还有个隐蔽问题如果前面提到的gitlab-secrets.json没有正确恢复CI/CD 变量的加密密钥对不上界面上能看到变量名但读不出值流水线里用到这些变量的 job 会全部失败。遇到这种情况先检查 secrets 文件而不是急着重建变量——重建等于把密码类变量全部手动导一遍费时费力还容易漏。6. 迁移后的日常运维脚本、升级、监控6.1 一个够用的备份脚本迁移只是开始日常备份不能断。我在新环境里写了个简单脚本放在/usr/local/bin/gitlab-backup.sh#!/bin/bash BACKUP_BASE/srv/gitlab/data/backups /usr/bin/docker compose -f /srv/gitlab/docker-compose.yml exec -T gitlab gitlab-backup create find $BACKUP_BASE -name *_gitlab_backup.tar -mtime 14 -delete tar czf $BACKUP_BASE/gitlab-config-$(date %F).tar.gz /srv/gitlab/config/gitlab.rb /srv/gitlab/config/gitlab-secrets.json find $BACKUP_BASE -name gitlab-config-*.tar.gz -mtime 14 -delete配合 crontab 每周执行一次0 2 * * 0 /usr/local/bin/gitlab-backup.sh脚本里保留最近 14 天的备份配置和密钥每个星期单独打一个包。定期恢复演练比备份本身更重要建议每季度找一台空闲机器把备份恢复一遍并跑几个关键仓库的git fsck确认备份真的能救命。6.2 升级 GitLab 的正确姿势Docker Compose 部署的 GitLab升级流程其实很清爽先备份再改镜像 tag然后docker compose pull docker compose up -d。但有一条红线必须守住——跨大版本升级必须走官方升级路径。比如从 15.x 升到 17.x正确路径是 15 → 16 → 17每一步都是一个稳定大版本每一步之间都做一次备份。千万别图省事直接从 15 跳到 17GitLab 内部数据库结构在大版本之间变化很大跳级升级轻则报错重则数据损坏。升级完立刻去管理员后台确认版本号再跑一次gitlab-rake gitlab:check验证系统完整性。6.3 磁盘和日志Docker 部署的隐形杀手Docker 部署 GitLab 最容易被忽视的是容器日志无限增长。默认情况下容器的 JSON 日志会一直写配上 GitLab 本身的日志 volume硬盘很快会被吃掉。我给 compose 文件加了日志轮转限制logging: driver: json-file options: max-size: 50m max-file: 3另外/srv/gitlab/logs目录里的应用日志也需要关注特别是 PostgreSQL 和 Git 相关的日志。运维侧我每周固定看一眼df -h和du -sh /srv/gitlab/*确认数据目录增长在预期范围内。最后再分享一个实际体会迁移这种事真正考验人的不是技术命令而是流程是否克制。版本对齐、备份校验、切换观察、回滚预案这些步骤看着啰嗦但它们才是“数据零丢失”的真正保障。我这次迁移之所以顺利很大程度是因为提前把所有核对数字都存档了每一步都验证完再走下一步。如果你也准备做类似迁移别被“Docker 很轻松”这种说法带偏把备份和校验当成第一优先级稳一点慢一点反而是最快的路。
返回列表