这段时间一直在折腾用Docker部署GitLab从最初的一键脚本到后来手动跑容器、升级备份、排查各种坑也算是把这套流程彻底摸熟了。GitLab这个工具本身不必多介绍代码托管、CI/CD、代码审查、里程碑管理一家公司的研发流程基本都能在它上面跑起来。但真正上手部署的时候不少人都卡在了环境准备和版本规划上要么是内存不够跑不动要么是SSH端口冲突折腾半天要么是升级到一半实例起不来。这篇就以Docker方式为主把GitLab的安装部署、参数规划、升级备份和常见坑完整过一遍。适合刚接触GitLab、准备在公司内网或团队里搭一套代码托管平台的开发者也适合已经用了一段时间、想换到Docker方式管理的运维同学。自己搭一套自托管GitLab好处很直接代码不出内网、仓库数量不限制、CI分钟数不花钱、版本节奏自己掌握而且整个部署下来也就半小时左右。1. 为什么选择Docker方式部署GitLab1.1 对比裸机安装Docker解决了什么GitLab官方提供了多种安装方式Omnibus包直接装在物理机或虚拟机上是最传统的路子但也是坑最多的一条路。Omnibus安装会把PostgreSQL、Redis、Nginx、Gitaly等十几二十个组件全部装进系统依赖关系复杂。我之前在一台CentOS机器上装过装到一半Ruby版本的依赖冲突后面排查花了大半天最后还是抹掉重来。Docker部署的核心优势在于环境隔离和可重复性。GitLab官方维护的Docker镜像已经把Omnibus包、运行时依赖、启动脚本全部封装好了宿主机上只需要有一个Docker环境。同一套docker run命令不管是装在开发笔记本上还是生产服务器上跑起来的结果是一致的。这对我来说意味着什么意味着换机器、迁移、扩容的时候不需要重新走一遍安装踩坑流程直接把容器拉起来就行。数据持久化也是Docker方案的另一大好处。GitLab的数据目录、配置目录、日志目录分别挂载到宿主机三个不同的volume路径容器本身可以随时删除重建数据完全不受影响。这个特性在出问题的时候特别救命——容器起不来、配置改崩了删掉容器重新run数据一点不丢。1.2 Docker方案适合什么场景这就要分情况说。如果是超大规模生产环境上千人同时使用ecommerce级的仓库数量和并发CI任务量那通常建议直接上Kubernetes生态或官方推荐的helm部署充分发挥多节点弹性。但对于绝大多数场景——50人以下的团队、企业内部代码托管、个人开发环境、教育用途——单机Docker部署完全够用性价比最高。我见过不少公司用一台16G内存的中配服务器Docker里跑GitLab加上几个业务容器稳稳定定跑了两年没出过事。GitLab本身的内存占用其实没有传说中那么恐怖默认配置下8G内存的机器跑起来很舒服4G也能跑只是需要做一些精简调整后面会详细说。选Docker还有一个现实原因GitLab的升级和回滚太方便了。裸机安装升级往往是apt/yum拉包、跑upgrade脚本一旦中途报错排查起来非常痛苦。而Docker方式升级本质上就是换一个镜像tag再重新起容器启动前打个快照备份出了任何问题都能秒级回滚到旧镜像。这个体验差异实际操作过的人都能感受到。2. 部署前的准备工作2.1 三件必须提前定好的事域名、端口、存储不少人部署GitLab习惯直接拿服务器IP访问比如http://192.168.1.100短时间用可以长期用会有一堆麻烦。GitLab的很多功能依赖于一个完整的外部URL比如推送代码时生成的仓库地址、CI/CD中构建产物的链接、Webhook回调地址。如果直接用IP后续配置HTTPS、接入LDAP、对接外部CI服务的时候URL改起来非常痛。建议在部署之前就绑定一个域名比如git.company.com通过内网DNS解析到服务器IP。环境变量里配置EXTERNAL_URLhttp://git.company.com即可GitLab会自动根据这个URL生成所有内部链接。这一步提前做好后面会省掉大量重复配置。端口冲突是我在实际部署中碰到最多的问题。GitLab的SSH默认走22端口Web默认走80和443。但很多公司的服务器上22端口已经被系统的OpenSSH占用了80端口可能是Nginx或者其他Web服务在跑。如果直接裸装GitLab端口冲突基本是必然的。Docker部署的解法是端口映射。宿主机SSH端口保留给系统连接用另一个端口比如2222映射给GitLab容器内的22端口Web端口同理宿主机8080映射到容器80。具体做法加上-p 2222:22 -p 8080:80 -p 8443:443这段映射参数。存储方面GitLab容器内把数据放在/srv/gitlab目录下部署时把宿主机目录挂载进去。建议单独给GitLab划一个数据盘至少预留50G起步仓库量大的团队按需扩。我习惯先把数据盘挂载到宿主机比如/data/gitlab目录然后在docker run时映射进去。这样容器删了重建数据还稳稳留在宿主机上。有人图省事直接把数据卷放在系统盘等仓库多起来发现磁盘爆了再迁移那就折腾了。2.2 内存规划从2G到16G要怎么调GitLab的内存占用是很多人部署后第一个吐槽的点。默认配置下它启动后会占用大约2.5G到4G内存8G内存的机器跑起来任务管理器看起来有点吓人但实际并不会崩。关键在于理解GitLab内部的内存结构PostgreSQL、Redis、Gitaly、Puma处理HTTP请求、Sidekiq处理后台任务、Nginx每个服务都在吃内存。4G以下内存能跑吗能但需要调整。编辑gitlab.rb配置文件可以把Puma的worker数量从默认的4降到2把Sidekiq的并发线程数降一档关闭监控相关的Prometheus和Grafana这样能把整体占用压到2G左右。我用一台2G内存的云主机跑过测试环境能启动代码托管和最基本的CI能用但跑大型CI任务会很吃力。内存规划建议纯代码托管场景4G起步要跑CI/CD8G比较舒服200人以上团队16G或更高。部署前先跟公司IT确认资源别等部署完了才发现内存不够再换机器那个成本更高。2.3 系统环境和Docker安装宿主机建议用Ubuntu 20.04及以上或CentOS 7.9/8内核版本不要太老。Docker Engine的安装很简单但有两个关键配置我用了很久才发现重要性一个是设置Docker开机自启另一个是日志滚动策略。GitLab的日志量不小尤其是运行CI任务频繁的时候容器日志会快速增长占满磁盘。建议在/etc/docker/daemon.json里加上日志限制{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }重启Docker守护进程后生效。这个配置不仅能控制GitLab的日志你后面跑其他容器也都受益不会一觉醒来发现磁盘因为容器日志爆掉了。3. GitLab Docker部署实操全流程3.1 部署核心命令逐段拆解docker run命令看着长但每一条参数都有它存在的意义。先把完整命令放出来再逐段解释sudo docker run --detach \ --hostname git.example.com \ --publish 443:443 --publish 80:80 --publish 2222:22 \ --name gitlab \ --restart always \ --volume /srv/gitlab/config:/etc/gitlab \ --volume /srv/gitlab/logs:/var/log/gitlab \ --volume /srv/gitlab/data:/var/opt/gitlab \ --shm-size 2g \ gitlab/gitlab-ce:latest第一段是基础参数--detach表示后台运行--hostname设置容器内部的主机名这个值会参与生成仓库的SSH克隆地址和HTTP克隆地址。如果不设默认会拿容器的随机ID当主机名克隆地址就会变成一串乱码。--publish做了三层端口映射。443和80是HTTP/HTTPS入口如果把这两个映射到宿主机不冲突的端口直接用域名访问没问题。第三层2222:22是SSH的映射宿主机2222端口映射到容器的22端口这样系统SSH不会被GitLab占用。如果公司服务器只有你一个在用直接把22映射进去也行但强烈不建议——一旦GitLab出问题SSH也连不上了你就只能去机房物理解决了。--name gitlab给容器起个固定名字后面所有docker exec、docker logs操作都通过这个名字来引用不用去记容器ID。--restart always是生产环境必备的。服务器重启后Docker会自动把GitLab容器拉起来不用人工干预。我见过有人漏了这一步机房断电恢复后GitLab一直是停止状态直到用户反映代码推不上去才发现。三个--volume是数据持久化的核心。config目录放gitlab.rb配置文件和密钥logs目录放日志data目录放仓库数据、数据库文件。这三个目录必须挂载出来容器删了重建GitLab还是原来的GitLab。最后那个--shm-size 2g很多人会忽略这是个隐藏的坑。GitLab内部组件之间通过共享内存通信Docker默认只给容器分64M的共享内存。仓库一大Gitaly处理Git操作时就容易报错或者直接卡死。实测下来给到2G基本不会再碰到这类问题。3.2 版本选择的历史教训gitlab/gitlab-ce的latest标签是个陷阱。因为GitLab每年的重大版本升级路径是固定的有时候跨大版本升级必须先升到某个中间版本不能直接跳。如果部署时用了latest过几个月官方发布新版本你pull下来重启容器跨了好几个大版本启动大概率会失败报各种PG迁移错误。我的建议是部署时明确指定一个具体的稳定版本号。比如gitlab/gitlab-ce:16.11.2-ce.0。选择版本的策略先看GitLab官方升级文档中当前支持的大版本再选这个大版本的最近一个小版本。过几个月要升级时再去查官方Upgrade Path文档看当前版本到目标版本之间需要经过哪些中间版本。比如你现在用的是15.x想升到16.x升级文档通常会告诉你15.11是必经之路。那就先把镜像tag换到15.11启动成功后再换16.x一步步来不要跨大版本硬跳。3.3 第一次启动等待、初始密码、和初步配置容器启动后输入docker ps看状态STATUS列会显示healthy或者starting。GitLab第一次启动需要初始化数据库和配置所有内部服务这个过程慢的机器上可能要3到5分钟不要急着去访问页面。查看启动进度sudo docker logs -f gitlab看到类似GitLab is ready或者gitlab Reconfigured!的日志说明可以访问了。这时候可以用浏览器打开配置的URL。GitLab的初始管理员密码是自动生成的存在一个临时文件里。版本低一点的在/etc/gitlab/initial_root_password新版本在容器的/var/opt/gitlab/initial_password。获取方式sudo docker exec gitlab cat /etc/gitlab/initial_root_password sudo docker exec gitlab cat /var/opt/gitlab/initial_password登录用户是root密码取文件里Password字段的值。首次登录后建议立刻改成自己的密码并且开启双因子认证。GitLab上的权限设置很丰富生产环境别嫌麻烦该配的权限都配上代码安全出问题往往是从弱口令开始的。3.4 修改外部URL和SSH端口上一节提到EXTERNAL_URL决定GitLab对外所有链接的生成方式。如果在docker run时漏了或者端口映射用的不是默认值就需要手动调整gitlab.rb配置。用编辑器打开挂载出来的/srv/gitlab/config/gitlab.rb找到这两行并修改external_url http://git.example.com gitlab_rails[gitlab_shell_ssh_port] 2222第一行是Web访问地址第二行是SSH端口。特别提醒如果SSH做了非22的端口映射必须在gitlab_rails配置里写上端口号否则页面上显示的SSH克隆地址不会带端口用户复制下来推送代码会连不上。改完后执行重配置sudo docker exec gitlab gitlab-ctl reconfigure sudo docker exec gitlab gitlab-ctl restart重配置过程会更新Nginx配置、生成新的克隆URL整个过程大约一两分钟。这也是我为什么强调要用volume挂载config目录——配置改崩了直接编辑宿主机上的文件改回来再重启容器就恢复了不用进容器折腾。4. GitLab日常管理与升级实战4.1 备份的正确姿势不只是数据目录GitLab的数据分两块一块是git仓库数据存在/var/opt/gitlab/git-data里面另一块是数据库、用户信息、权限配置、CI/CD配置存在PostgreSQL里面。很多人做备份只打包了前者恢复的时候发现仓库文件都在但项目列表、用户权限全没了那种感觉非常难受。官方提供的备份命令会把两块数据一并打包sudo docker exec -t gitlab gitlab-backup create备份文件生成在容器内的/var/opt/gitlab/backups目录对应宿主机挂载目录的/srv/gitlab/data/backups。文件名类似1698123456789_gitlab_backup.tar前面的数字是时间戳。生产环境建议备份策略做到三层每隔一段时间做一次gitlab-backup全量备份备份文件定期异地拷贝重要节点升级前、迁移前手动额外打一次快照。升级前的备份尤其重要升级脚本可能会重写配置或数据库结构一旦失败没有备份就只能从零开始建用户、配权限那种工作量想想都头皮发麻。恢复备份也有讲究。先恢复备份再起容器这是许多新手容易做反的顺序。正确做法先停掉容器确认数据目录下有备份包再启动一个同版本的新容器然后进入容器执行恢复命令。4.2 升级GitLab的完整步骤很多人直接拉新镜像重启完事这在大跨度版本升级时几乎必翻车。安全升级流程我给一个标准版本第一步备份。执行gitlab-backup create并把备份文件复制到宿主机其他目录留存。第二步查看当前版本。执行docker exec gitlab gitlab-rake gitlab:env:info能看到当前版本号和最新可用版本。第三步根据当前版本和目标版本的差距查GitLab官方Upgrade Path文档。跨大版本时必须先经过指定的中间版本不能跳。第四步替换镜像版本并重启容器sudo docker stop gitlab sudo docker rm gitlab sudo docker run ... # 同样的参数镜像tag换成新版本注意数据显示第三步做的映射要完全一致特别是三个volume位置不能变否则新容器找不到旧数据GitLab会当作全新安装初始化。第五步容器启动后gitlab-ctl reconfigure和数据库迁移会自动执行。这个过程可能比平时启动慢很多大版本升级可能要等10分钟以上。期间不要手动重启容器或者频繁查看日志操作让迁移跑完。看到GitLab is ready后登录管理后台进Admin Area确认版本号正确、项目列表和用户数据完好。4.3 GitLab Runner注册部署GitLab后的下一件事代码托管只是GitLab的一半价值另一半在CI/CD。跑CI/CD需要单独的Runner组件官方提供了各种安装方式我用的是Docker方式——在一台单独的机器上装一个runner容器注册到GitLab实例上让任务跑在runner所在的主机而不是GitLab服务器上。这样CI任务随便玩就算任务把Runner机器搞崩了GitLab本身不受影响。Runner注册命令sudo docker run --rm -t -i \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ gitlab/gitlab-runner:latest \ register \ --url http://git.example.com \ --token glrt-xxxxxxxxxxxx--url是GitLab的地址--token是注册令牌。在GitLab管理后台的Runner页面可以看到这个token注意新版本中token是glrt开头的老版本是纯数字的注册token两种都能用。Runner注册成功后验证方式是在管理后台的Runner页面看到该Runner显示为在线状态。然后随便建一个项目加个.gitlab-ci.yml文件提交代码触发一次流水线确认任务能正常跑起来整个部署流程才算闭环。5. 常见问题排查与避坑指南5.1 502页面频发多半是内存不足容器起来了页面也打开了但点几个页面就开始刷502。这个现象十有八九是内存不够。GitLab的Puma服务在内存不足时会被系统强制杀掉请求进来没有服务能处理Nginx只能吐502。查看方式是执行docker stats看容器内存使用率接近上限的时候基本可以确诊。解法是两条路一是加大内存干脆把机器规格升上去二是给GitLab减负编辑gitlab.rb把Puma的worker数从默认4降到2或1把Sidekiq的并发数也调低同时关闭Prometheus监控相关组件。性能会打一点折扣但起码系统稳定可用。5.2 SSH克隆连接不上先检查端口生效没这是一个非常典型的新手问题HTTP克隆没问题SSH方式的git clone一直卡住超时。排查路径并不复杂。先确认宿主机端口映射没被防火墙挡住在GitLab所在机器上执行netstat -tlnp看2222端口有没有在监听。再用telnet从客户端机器连过去telnet git.example.com 2222能通说明网络层没问题。然后进容器确认SSH服务在运行执行docker exec gitlab gitlab-ctl status看sshd服务是否active。如果全部正常但SSH还是不通就回到本文3.4提到的那个配置检查gitlab.rb里有没有正确设置gitlab_shell_ssh_port。这是个不被注意但非常关键的点端口映射做了、防火墙开了、容器SSH也活着但GitLab生成的SSH克隆地址不带新端口客户端连的还是22端口当然会失败。5.3 升级后数据库迁移失败最值钱的一课我把这个坑放在最后说是因为它最值得引起重视。见过不止一次有人直接从12.x跳到15.x跳了三个大版本容器起来后日志界面全是数据库迁移报错。GitLab的数据库结构是逐版本累积演进的一下子跳太多迁移脚本之间的依赖关系会断掉数据库结构迁移就会跑不过去。出现这种情况首先要保持冷静提醒自己不能慌乱操作备份一定要先确认存在且能读出来。然后老老实实按Upgrade Path去找当前版本到目标版本需要经过的中间版本的镜像逐个步骤升级每次重启容器都要确认数据库迁移成功、页面能正常打开再往下一个版本走。整个过程中最核心的经验启动新版本容器前一定要看一眼GitLab官方文档里这一版本的迁移要求很多版本都写明了必须先升级到XX版本才能再升级到本版本。这些信息平时看着没用真到升级的关键时刻就是活命的指南。5.4 配置修改后不生效执行顺序是玄学还有一个容易被忽略的小问题改完gitlab.rb执行了reconfigure页面打开发现配置没变。大概率是忘记restart了。reconfigure只负责把配置下发和相关服务重启但有些配置项需要整个GitLab服务栈重启才生效。稳妥的顺序是改gitlab.rb执行gitlab-ctl reconfigure再执行gitlab-ctl restart两个命令串行执行缺一个都可能出现配置改了但没啥变化的情况。如果改了external_url或者SSH端口之后发现克隆地址没变化别忘了清一下浏览器缓存或者用无痕窗口访问。这种问题最容易让人误判其实服务端配置已经生效是浏览器端有旧缓存换了浏览器或者清了缓存立刻就好了。6. 小结与经验沉淀把Docker部署GitLab的整套流程实际操作过一遍最大的体会是这个问题本身不难难的是那些偏门细节和环境适配。端口冲突、内存紧张、升级路径、备份恢复每个环节都有几个容易被忽略的坑坑踩过了后面就顺了。如果就是给团队搭一个代码托管平台建议直接按照文中的步骤操作命令基本可以抄作业配置调整根据自己的服务器资源来决定。如果之前已经用过一段时间的GitLab想切换到Docker方式管理重点看第3节的volume挂载和第4节的备份升级这两块是数据迁移和日常运维的核心。Docker部署GitLab后续可以扩展的方向还有不少。可以给GitLab配置LDAP对接公司统一账号体系省掉每来一个新人就手动建账号的麻烦可以给GitLab配上对象存储把构建产物、依赖缓存放到远端减轻本地磁盘压力还可以把Runner集群化按项目或按团队分配不同的执行环境。每一步都是在前面的基础上叠加的。我在实际操作中的一个习惯是每次部署完GitLab都会顺手把这次用的镜像版本号、端口映射情况、内存配置记在一个文件里。版本升级或者要重新部署的时候直接看这个文件比去翻历史命令记录找效率高得多。GitLab本身已经是个很成熟的工具把部署和运维细节管好剩下的时间就可以专注在真正有趣的事情上了。
阅读完成 · 觉得有帮助?