ARTICLE DETAIL

资讯详情

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

GitLab资源耗尽?实测迁移Gitea:从10GB到600MB的轻量替代方案

GitLab资源耗尽?实测迁移Gitea:从10GB到600MB的轻量替代方案 先说结果3月底我们把公司内部跑了大半年的GitLab摘了下来。起因是某天下午监控群突然抛出一条告警那台4核8G的服务器内存占用到了97%。登上去一看前50个进程里三十多个都是gitlab开头的SSH操作都开始卡顿同事在群里问是不是被挖矿了。实际排查了一圈没有什么奇怪的进程纯粹就是GitLab全家桶把机器吃干净了。那台服务器跑着GitLab社区版同时还有两个小项目的CI Runner。按说规模不算大仓库总数也就四十几个团队十几个人。但GitLab社区版默认带了一整套Ruby on Rails、PostgreSQL、Redis、Sidekiq、Prometheus光基础服务就好几个进程组日常内存稳定在5GB以上磁盘更是夸张——镜像、日志、CI缓存、备份文件叠在一起随便一查就十多个GB。我们当时的第一个念头不是换而是调优。给Sidekiq限并发关掉Prometheus把数据库从容器里迁出来跑折腾了两周效果有一点但离省心两个字还是差得远。后来讨论了几轮干脆做了一个决定找一个更轻的自建Git服务把数据搬过去。如果你也正在GitLab上纠结要不要换、或者被小服务器的资源告警搞得心力交瘁这篇内容会比较实用。我会把我们从选型、迁移到踩坑的全过程写清楚包括每一步怎么操作、哪些地方文档里根本找不到。1. 一台8G服务器被GitLab拖垮的复盘1.1 GitLab的资源消耗到底花在哪了很多人对GitLab的资源占用没有概念觉得不就是个代码托管平台吗。实际上GitLab和GitHub/Gitea这一类工具在架构上完全不同。GitLab是一个大而全的DevOps平台代码托管只是它的一小块它还内置了CI/CD、容器镜像仓库、制品库、依赖扫描、安全报表、Wiki、里程碑管理等等。为了让这些模块协同工作社区版会同时拉起PostgreSQL、Redis、Sidekiq异步任务、GitalyGit存储、PumaRuby Web服务器、Prometheus监控等多套服务。我当时的实测数据是这样的刚部署完、一个仓库还没有的情况下GitLab容器加依赖进程的内存占用就已经到了2.8GB。跑起来之后随着Sidekiq处理Webhook、刷CI状态、生成图表内存会一路涨到5GB以上。磁盘方面容器镜像本身3GB左右加上PostgreSQL数据、仓库存储、日志文件、每次升级前的备份包长期稳定在10-15GB。如果团队再开Artifact缓存、Registry功能再翻一倍也不奇怪。这还不是最要命的。最要命的是升级。GitLab社区版每个季度有安全更新每次跨大版本升级都得沿着版本号一级一级往上跳比如从16.3升到16.4中间要先后升16.4、 16.5不能直接跳。每次升级备份、拉镜像、迁移数据库、起服务、看日志一套下来大半天就没了。而且升级过程中万一数据库migration卡住排查起来非常头疼。我们有一次升级后Sidekiq一直报错查了四五个小时才发现是老版本遗留的队列数据不兼容。1.2 真正让人想换掉的不是性能是运维心态性能问题是显性的更磨人的是隐性成本。团队十几个人真正高频使用的功能就几个仓库托管、分支管理、Merge Request、Issue、Webhook推送、权限控制。GitLab那一大堆治理类、安全类、DevOps类功能九成我们根本没碰过。但这些功能不会因为不用就不占资源它们一直在后台跑着、占着内存、产生日志、等着升级。另外一个很实际的问题是升级本身有安全压力。GitLab历史上出过好几次比较严重的高危漏洞其中有未授权的接口访问类问题、也有默认配置暴露敏感信息的问题。每次漏洞公告一出来我们就要停下来评估当前版本是否受影响然后安排升级窗口。对于一个小团队来说这个心理负担比技术负担更让人疲惫。当时我们算了一笔账如果继续用GitLab大概率要给服务器加内存或者直接换机器同时每个季度都要预留升级时间。如果换一个资源占用只有几十分之一的方案也许就一劳永逸了。这笔账算完之后弃用GitLab就从讨论变成了立项。2. 选型Gitea600MB背后是一套完全不同的架构思路2.1 轻量级赛道的候选者自建Git服务的轻量方案绕不开三个名字Gogs、Gitea、Forgejo。Gogs是最早的Go语言实现单二进制文件就能跑但开发节奏后来放缓了。Gitea是从Gogs fork出来的社区驱动项目界面清爽功能迭代积极Docker镜像很小。Forgejo又是从Gitea fork出来的更强调社区治理兼容性上基本沿袭Gitea。我们在Gitea和Forgejo之间犹豫了一下最后选了Gitea。理由很实际文档最全社区用户多周边工具链比如Drone、Jenkins插件、IDE插件的兼容性验证最充分。Forgejo虽然理念上更社区化但团队没人有精力去验证镜像仓库和Webhook的兼容性就不折腾了。Gitea整体有多省资源它的主程序是一个Go编译出来的单个二进制文件静态编译不依赖任何运行时。数据库可以用SQLite也可以外接MySQL/PostgreSQL。因为没有Ruby、没有Node、没有一堆语言运行时整个服务的内存占用通常在100-300MB量级。我们当前的部署包含Gitea主进程、SQLite、act_runnerCI执行器常驻内存加起来不到600MB磁盘占用也在1GB以内。这个数字和GitLab动辄10GB的体量完全不是一个物种。2.2 架构差异决定了运维方式的差异再往深看一步两者的运维差异不只是省多少资源的问题而是遇到问题要修什么的问题。GitLab出问题时你经常要面对的是Ruby进程僵死、数据库连接池耗尽、Sidekiq队列堆积这类复杂的分布式系统问题。Gitea出问题时绝大多数情况就是看日志、检查配置文件、重启服务三步因为它本身就是一个单体进程没有那么多需要维护的子服务。Gitea的配置是一个app.ini文件集中管理端口、数据库、SSH、邮件、Webhook、OAuth全在这一个文件里改。改完重启一下进程就生效。GitLab呢几十个环境变量加一堆配置文件改了哪项、要不要跑reconfigure都得先查文档。我也不是说GitLab一无是处。如果你的团队需要一套开箱即用的完整DevOps平台比如平台工程团队要提供制品库、依赖代理、安全合规报表那GitLab全套仍然是最省心的选择。但对我们这种只有代码托管和评审诉求的小团队来说Gitea覆盖的功能点已经绰绰有余Pull Request、Issue、里程碑、看板、Wiki、标签、里程碑、Webhook、组织/团队权限一个不少。2.3 功能清单对照哪些被砍掉的项目其实无所谓我做了一张功能对照表当时同步给团队看用来让大家确认换过去到底会不会缺功能。功能GitLabGitea我们的结论Git仓库托管完整完整无差异Pull/Merge Request完整支持多级审批完整支持必填Review够用Issue跟踪完整支持迭代基础Issue里程碑看板够用内置CI/CD完整但重Gitea Actions兼容GitHub Actions我们用Jenkins影响不大容器镜像仓库内置Registry有外部包/容器支持本来就用的私有Registry代码搜索支持但依赖Elasticsearch内置基础搜索小仓库无感安全扫描内置无用外部工具替代资源配置镜像数十GB内存数GB镜像约百MB内存百MB级本次迁移核心动机如果你正在做类似决策我建议你也在团队里做一次这样的功能清单把每个功能标上正在用/偶尔用/从没用过。绝大多数团队做完这个清单之后会发现自己真正依赖的GitLab功能不超过五项。3. 迁移实操仓库、用户、权限钩子的一次性搬家3.1 先用Gitea自带的迁移器把主数据搬过去我们最初也考虑过用git clone --mirror逐个仓库迁移但实际操作之前发现Gitea本身内置了一个很实用的功能——仓库迁移器Create Migration。它可以直接从GitLab、GitHub、Gogs等服务导入仓库并且能连带拉取Issue、Pull Request、里程碑、标签和Wiki内容。具体操作路径是Gitea首页点右上角的号选择迁移外部仓库填上GitLab地址、Access Token选择仓库或分组。Gitea底层会调用GitLab的API来拉数据。这里最关键的准备工作就是Access Token在GitLab里生成一个Personal Access Token勾选read_repository、read_api等读权限然后在Gitea迁移表单里填好即可。如果你一时找不到Token在哪生成路径是GitLab右上角个人头像 → Edit Profile → Access Tokens。但这里有个问题一次迁移一个仓库还算方便四十多个仓库逐个操作就很烦了。解决办法是让有权限的账号先在Gitea库里创建好对应的仓库再用脚本批量处理。我们的脚本逻辑很简单读一个仓库清单文件逐个执行git clone --mirror然后git push --mirror到Gitea库。这样能把仓库历史和全部分支、标签完整搬过去脚本如下# authors.txt 里每行是 源仓库 目标仓库 while read line; do set -- $line git clone --mirror https://gitlab.corp.local/team/$1.git cd $1.git git remote add gitea http://gitea.corp.local/team/$2.git git push --mirror gitea cd .. done authors.txt--mirror模式会把本地仓库的所有refs包括远端跟踪分支一起推过去能最大程度保证仓库的完整性。执行完之后用git fsck或者随机挑几个历史分支对比commit hash确认数据一致。我们那时候就是拿主仓库的master分支和某个release标签做核对hash完全一致心里才踏实。3.2 用户、组织和权限重建的逻辑跨平台的用户体系没法直接平移。GitLab的密码哈希算法和Gitea不一样不能导入数据库行记录来复制用户否则只能重置密码。我们没有选择重置密码这种体验比较差的做法而是直接给Gitea对接了公司已有的LDAP服务。这样成员的账号、密码、组织归属都从LDAP同步大家不用额外记一套密码管理员也省得手工建账号。组织团队的权限设置则需要手动重建。GitLab的权限模型是Group Subgroup Projects权限级别有Guest/Reporter/Developer/Master/Owner五档。Gitea的模型是Organization Team RepositoryTeam权限分Read/Write/Admin三种。映射关系不完全是1:1但对我们这种扁平化小团队来说改成某Team对某仓库有Write权限比GitLab更直观。我们最后的做法是每个业务组建一个Organization底下按项目建Team再把对应成员拖进去。迁移完成后我专门做了一个校验动作用一个没有权限的测试账号登录Gitea确认私有仓库确实不可见再用一个写权限账号尝试直接push到受保护分支确认被拒绝。这个步骤很重要权限模型重构后一定要做正反两面的验证不能只测能访问的能访问。3.3 保护分支与提交规范的二次落地GitLab里有比较丰富的Push Rules能力比如限制提交信息格式、禁止把代码直接推到主干分支、强制关联Issue单等等。Gitea的保护分支能力相对简单它只能限制谁可以push/merge不能做提交信息格式校验这类规则。这个缺口我们要在迁移前想清楚。我们团队当时的规范很简单主干分支禁止直接push必须走Pull Request且至少一个人Review。这个在Gitea保护分支设置里就能实现分支设置里把合并请求前禁止推送开启指定允许push/merge的角色再把需要Review设置为比管理员低一级的成员。对于更复杂的提交规范我们是通过Jenkins流水线里加一段shell脚本检查commit message来兜底的。4. 换网关后的阵痛登录、SSH、Webhook与CI的五个深坑4.1 422登录错误和隐身模式之惑迁移完成后第一批同事反映的问题非常一致登录的时候偶尔会跳422页面错误然后怎么刷新都登不上但用隐身模式打开页面又能正常登录。这个问题在GitLab上也遇到过当时很多人用切换浏览器隐身模式来绕过以为是自己浏览器的问题其实本质是Session和Cookie的问题。Gitea的Session存储和Cookie域名绑定如果配置不对会出现部分请求在验证身份时拿到非法凭证的情况。我们当时在Nginx反代上做了HTTPS终止但没有显式传递正确的协议头Gitea误以为当前请求是HTTP导致Secure Cookie的判定出现偏差。正确的做法是在Nginx加两行配置proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host;同时在app.ini的[server]段里设置ROOT_URL https://git.corp.local/ROOT_URL必须和用户实际访问的地址完全一致这是很多人忽略的。改完配置重启Gitea422问题就消失了。4.2 SSH端口冲突最容易被忽略的搬家坑我们原先的GitLab部署在宿主机上直接占用了22端口。Gitea虽然也支持内置SSH服务但默认建议映射到其它端口比如2222。如果直接把Gitea容器映射到宿主机的22端口会发现和宿主机自身的sshd冲突容器根本起不来。这里有两种处理方式一是宿主机sshd改用2222把22让给Gitea这样用户clone地址不用带端口号二是保留宿主机sshd的22端口Gitea内置SSH监听在2222用户clone地址要写成ssh://gitgit.corp.local:2222/team/repo.git。我们选了第二种因为宿主机上还跑着其他脚本依赖ssh改默认端口的影响面太大。需要注意改成2222之后Git-LFS和部分IDE的Gitea插件可能默认还是走22端口需要在客户端配置里手动指定。如果团队对clone地址不带端口有执念建议提前和运维确认宿主机端口占用情况从长远看还是把22端口分配给Gitea更顺滑。4.3 GitLab Webhook改到Gitea之后事件格式变了Gitea的Webhook支持多种格式Gitea原生的、GitHub格式、以及通用JSON。很多和GitLab深度集成的工具比如企业微信群机器人、自研部署平台原本解析的是GitLab的事件结构。切到Gitea之后事件JSON里的字段名、嵌套结构都不一样了不能无缝兼容。我们当时的系统架构是Jenkins负责CI/CD另外一个自己写的部署平台负责环境发布。原先是GitLab推事件给这两个系统。迁移后Gitea的Webhook里勾选了GitHub兼容格式然后在Jenkins侧把原来的GitLab Plugin触发方式改成Generic Webhook Trigger插件用JSONPath去匹配仓库名、分支名。这个改动不算大但要做字段映射测试。我们的做法是先推一个空提交到测试仓库观察Webhook请求日志和Jenkins里的触发记录确认映射关系无误后再放开全量。如果你也正好用Jenkins我的建议是尽量选择GitHub兼容格式而不是Gitea原生格式因为Jenkins生态对GitHub格式的支持最成熟。4.4 大文件LFS的迁移仓库里有几个美术资源库用Git LFS管理。迁移的时候只做了常规的git clone --mirror结果LFS指针都拉下来了实际大文件内容没有过来。表现在Gitea界面里就是能正常下载代码但LFS文件在clone时直接404。解决方法是在Gitea里手动启用LFS支持然后对每个仓库执行一次全量LFS拉取和推送git lfs fetch --all git lfs push --all gitea执行之前要确认Gitea的LFS服务已经开启。Gitea的LFS功能支持S3兼容存储也支持纯本地存储小团队用本地存储就好S3反而多一层依赖。迁移完LFS后务必找一个之前包含大文件的提交在空白目录里重新clone一次验证LFS拉取正常再通知美术组停止推送。4.5 CI/CD的重新接驳之前用GitLab CI/CD的时候.gitlab-ci.yml里定义了build、test、deploy三个阶段跑在GitLab Runner上。迁移后这段CI配置彻底失效因为我们不再跑GitLab Runner了。我们的替代方案是第一优先把构建和部署切到Jenkins流水线上Gitea仓库里的Webhook负责触发Jenkins。如果是新项目想省事可以直接用Gitea内置的Gitea Actions兼容GitHub Actions语法需要在服务器上额外部署一个act_runner作为执行器。两种方案我们都试过Jenkins适合已有大量流水线资产的老团队Gitea Actions适合从零开始、不想维护Jenkins服务的新团队。对于已经搭了Jenkins的团队我不建议为了统一工具链再去折腾Gitea Actions收益不大反而要多维护一套Runner。5. 10GB到600MB的真实账本迁移后一个月的运行数据5.1 资源占用前后对照迁移完成首日我在同一台服务器上观察了24小时的资源曲线。下面是稳定运行后第30天的实测数据不是刚启动时的瞬时值指标GitLab时期Gitea时期容器/进程内存占用5.2GB - 6.8GB280MB - 400MB磁盘总占用含仓库约23GB约1.6GBDocker镜像总大小8.5GB403MB服务启动时间3-5分钟2-4秒日常CPU占用1%-15%波动接近0最直观的变化是内存从一直在警戒线上变成了一条几乎水平的低水位线。以前那台服务器我们已经准备加内存了现在不仅不用加还能在同一个宿主机上继续跑其他服务。5.2 团队体感操作习惯切换成本代码托管工具换了之后团队成员最关心的其实只有三件事原来怎么拉代码现在还怎么拉代码原来怎么提MR现在还怎么提MR原来的权限还在不在。Gitea的Pull Request流程和GitLab Merge Request非常像从GitLab迁过去的人基本不需要重新学习。我们在切换后的第一天做了一次半小时的在线培训之后就再没收到过操作类的问题。有几个同事反馈过这几点差异Gitea的代码搜索响应明显更快小仓库里秒出结果UI页面轻量办公室网络差的时候也能秒开但Issue统计和代码审查界面的信息密度相比GitLab略显简单。这里说的小痛点主要是全仓库代码搜索在Gitea里是基于内置索引的仓库大了之后搜索结果可能不如GitLab搭配Elasticsearch那么精准。5.3 什么情况建议回到大平台Gitea也不是万能的。如果你所在团队有下列需求中的任意两条我建议还是要慎重第一必须有开箱即用的制品库和容器镜像库不想额外维护Nexus或Harbor第二需要精细到字段级的安全合规报表比如依赖漏洞扫描CI/CD流水线的审计日志第三代码库规模很大比如单体仓库超过几十GB或者需要跨多个机房的复制能力第四团队有专职的DevOps工程师负责平台维护完全有余力去管理GitLab全家桶。我们走了这条路不代表所有人都该走这条路。最终的决定依据就是团队规模、技术栈和运维人力之间的平衡点。6. 如果你也想弃用GitLab我的几个实在建议最后说点干活过程中的体会吧。第一迁移前一定要和团队同步清楚哪些功能会变、哪些功能没有了尤其是那些依赖GitLab企业级能力的人。先别急着动手把功能清单发出去让大家提意见提前把预期拉齐后面阻力会小很多。第二SSH端口和Webhook这两件事一定要在第一天就规划好它们在迁移完成后是会立即炸响的雷提前处理能省掉后面几乎所有火急火燎的排查。第三无论如何都要做一次全量备份验证不是我们导出过了而是真的找一个干净环境把备份文件完整还原一次。我们把赌注压在一个600MB级别的服务上图的就是省心而省心的前提是数据随时都能恢复。迁移之后最明显的变化是我不用再天天盯那台服务器的内存曲线了。配置完的那天下午GitLab时代遗留下来的几十个告警规则被我一次性清空看着监控群里安安静静的样子还是很有成就感的。如果你也在小服务器上被GitLab的体量压得难受不妨给自己一个周末按上面的步骤试一把。搬完家那种长舒一口气的感觉值得体验一下。
返回列表