说到 GitLab很多人的第一反应是“这不就是个代码仓库管理工具吗”。确实它最广为人知的身份是代码托管平台但真正用起来之后你会发现项目权限、分支保护、合并请求评审、CI/CD 流水线、容器镜像库这些能力全都集成在一个系统里面。换句话说它不是一个只能放代码的“网盘”而是一整套开发协作的基础设施。这篇手册我按自己从零搭建 GitLab、把团队日常开发流程迁移上去、再逐步铺开流水线和 Code Review 规范的完整链路来写。覆盖范围包括部署方式怎么选、项目权限怎么配、MR 流程怎么定、.gitlab-ci.yml 怎么写、日常排障和备份恢复怎么做。如果你是刚接手 GitLab 维护的新手建议从头往下读如果已经有使用经验可以直接跳到第 4、6 章看 CI/CD 配置和常见坑。因为 GitLab 版本迭代很快界面和具体配置入口偶尔会变但核心概念和工作原理是稳定的。读到任何一步和你的版本不一致时先去找“同名设置项”而不是“同名菜单位置”。1. 先搞明白 GitLab 到底是个什么东西1.1 一个平台把代码托管、协作和自动化揉在一起GitLab 最初解决的问题很简单让团队可以在自己的服务器上托管 Git 仓库不依赖外部公共平台。但发展到现在它的定位已经变成了一条完整的 DevOps 工具链代码托管、分支权限管理、Issue 跟踪、Wiki 文档、代码审查、CI/CD、依赖扫描、容器镜像管理全部放在同一个产品里。这个设计对团队来说有一个很实际的好处不需要再去拼装“Git 服务器 CI 工具 缺陷跟踪系统 制品仓库”这样的组合方案也就少了很多账号打通和数据同步的麻烦。你提交代码之后从触发构建到跑测试再到部署上线所有状态都能在同一个 MR 页面里看到。协作变透明的代价是前期需要花一点时间理解它的概念分类和配置逻辑但一旦跑起来整个开发流程会顺很多。刚开始接触 GitLab 时最容易混淆的是几个概念之间的关系。可以这样理解用户是登录和使用的人组是容纳项目和做权限继承的容器项目是真正的仓库本体承载代码、MR、Issue 和流水线Runner则是执行 CI 任务的“工人”。组套项目项目套 Runner用户在这些层级上获得不同权限这就是 GitLab 最基本的组织模型。1.2 社区版与企业版怎么选别被“免费”迷惑GitLab 分成社区版CE和企业版EE两套发行版本。社区版免费开源包含绝大多数核心功能无限项目、私有仓库、基础 CI/CD、Merge Request、容器镜像库这些对中小团队来说已经相当够用。企业版是付费订阅附加值集中在审计日志、细粒度权限、安全扫描、多环境部署策略等更高层的治理能力上。我见过不少团队一开始就纠结要不要上企业版结果买回来发现大部分高级功能根本没用到反而因为许可证和激活流程增加了维护成本。我个人的建议是除非团队明确有合规审计、多集群部署或安全扫描这类硬需求否则先无脑选社区版。后面业务复杂度上来了再考虑补一张订阅也完全来得及。GitLab 官方升级路径支持 CE 到 EE 的转换只是过程要在预发环境先走一遍。还有一个认知上的误区是“我有现成的 K8s 集群是不是必须用 Helm 部署 GitLab 才算先进”。其实不然部署方式应该由维护能力和故障恢复速度决定。对大多数团队来说一台稳定虚拟机上的容器化部署反而是更平滑的起点。2. 部署方案与服务器规划一步到位不返工2.1 三种主流部署方式怎么选GitLab 官方提供了多种部署途径实际用到最多的就三种Omnibus 安装包、Docker 容器部署、Helm Chart 部署到 Kubernetes。它们的差异我直接用一张表列清楚部署方式适用场景明显优点需要注意的坑Omnibus 安装包有一台稳定的 Linux 服务器自带全部组件和监控配置集中升级体验最顺系统环境变更要谨慎迁移到其他机器稍重Docker 部署已有容器环境或想快速验证环境隔离起停方便迁移只需带走数据卷数据卷管理要仔细版本升级要注意兼容性Helm/K8s 部署团队已深度使用 K8s弹性伸缩、高可用组件可拆分运维门槛最高排查链路长不建议新手直上如果让我给一个“不会错”的推荐中小团队、单机运维、预算有限优先考虑 Docker 部署。如果手头是云上虚拟机和独立的系统盘Omnibus 也很稳。真正需要 K8s 方案的时候团队往往已经具备对应的运维能力了否则碰到一个 Pod 反复重启排查起来会比传统部署更费时间。2.2 硬件配置与磁盘规划建议GitLab 特别吃内存这是很多人容易忽略的。可以看官方给出的参考配置4 核 4GB 内存大约支撑 100 个左右用户的小团队8 核 8GB 可以覆盖 500 人规模的日常使用16 核 16GB 则能从容应对几千人的组织。请注意这里说的是“日常使用”而不是“同一时间全部触发流水线”如果 CI 任务也跑在同一台机器上内存压力要按倍数预估。我最初踩过一个实实在在的坑用一台 2 核 4GB 的小机器跑 GitLab刚装完还能打开页面团队 5 个人同时推送代码之后页面开始频繁报 502free -h一看内存几乎被 Puma、Sidekiq、PostgreSQL 瓜分殆尽。后来把内存升到 8GB才算是真正稳定下来。所以硬件配置上我的原则是CPU 4 核起步内存 8GB 起步低于这个数只能当体验环境用。磁盘规划同样容易踩雷。GitLab 的仓库数据、数据库、构建产物和容器镜像都会持续占空间。如果 CI 需要在平台上保存构建产物磁盘增长会比你预想的快很多。建议把数据盘独立挂载并预留至少 50% 的余量有条件的话给/var/opt/gitlab所在分区设置磁盘告警线这样就不会直到磁盘写满才从一堆诡异报错里发现问题。2.3 Docker 方式实战从拉镜像到改配置我平时最常用的是 Docker 部署这里给一套可以直接照抄的命令。首先设置一个数据目录建议放到独立的数据盘上不要放在系统盘export GITLAB_HOME/srv/gitlab sudo docker run --detach \ --hostname gitlab.example.local \ --publish 80:80 \ --publish 22:22 \ --name gitlab \ --restart always \ --volume $GITLAB_HOME/config:/etc/gitlab \ --volume $GITLAB_HOME/logs:/var/log/gitlab \ --volume $GITLAB_HOME/data:/var/opt/gitlab \ --shm-size 256m \ gitlab/gitlab-ce:latest每条参数都有讲究。--hostname影响所有生成的仓库克隆地址一旦团队开始用起来再改会很麻烦所以要先规划好域名或内网地址再启动容器。--shm-size是给 Puma 等进程用的共享内存设得太小启动时可能直接报错。三个 volume 分别挂载配置、日志和数据这是容器重建之后数据不丢的保证。22 端口用于 SSH 克隆如果宿主机已经占用了 22可以映射到 2222但克隆地址要写成ssh://githost:2222这种形式团队成员要额外适应一下。容器启动之后需要先等一两分钟让数据库初始化完成。这时候访问服务器 IP 会看到 GitLab 的欢迎页提示你设置 root 用户密码。如果一直打不开先检查防火墙放行没放行对应端口再执行docker logs gitlab看看初始化进度。设置完密码后建议立刻把gitlab.example.local这个地址和实际域名对齐在管理后台的“设置-通用”里确认。有一个容易被忽略的细节如果--publish 80:80和服务器上已有的 Web 服务冲突可以改成--publish 8080:80但之后所有访问链接都会带端口号。团队规模一大这种“带端口的地址”会变得非常不优雅。所以服务器选型阶段就要保证 80 和 22 端口是空闲的。2.4 部署后的初始化检查清单部署完成不等于能用好。我每次搭完新环境都会按下面这个清单过一遍命令行执行sudo docker exec gitlab gitlab-rake gitlab:check确认核心组件健康状态。用 root 登录后台修改 root 邮箱和密码开启两步验证。创建第一个组确定组名规范后续项目都放进组里。建立前几个用户分配权限时遵循最小化原则。配置 SMTP 邮箱保证收到告警和 MR 通知。默认情况下如果不配邮箱GitLab 只能站内信很多成员会漏看。至少建一个空项目试一下 push 和 clone 流程确认 SSH 协议已经走通。这套清单做完一台 GitLab 才算真正具备了让团队开始使用的条件。别急着铺流水线和复杂分支策略先把代码能顺畅地存进去、拉出来再谈自动化。3. 项目管理、权限体系与分支保护3.1 从创建项目到 SSH Key 配置项目创建本身很简单首页点“新建项目”选择“创建空白项目”填上项目名和可见性级别即可。实际工作中真正麻烦的是命名规范和 SSH Key 配置。项目命名建议提前定好规则。大团队项目多了之后一个清晰的命名格式能省很多搜索时间。我习惯用“项目名-环境”的方式比如某个业务系统的前端项目就是web-frontend如果是后台管理端就是admin-backend。组名则按业务线或产品线划分比如mobile、platform。这样组织和查找项目时能明显感觉到权限和路径都很顺畅。SSH Key 是绝大多数新手的第一道坎。本地生成密钥的命令是ssh-keygen -t ed25519 -C youexample.com然后打开~/.ssh/id_ed25519.pub文件把内容复制到 GitLab 用户设置的“SSH 密钥”页签里。配置完成后可以用ssh -T git你的域名测试连通性。如果收到欢迎信息说明公钥已经生效。这时候再去克隆仓库建议优先使用 SSH 地址而不是 HTTPS 地址能省掉每次输用户名密码的麻烦。很多人的问题出在协议混淆上明明配置了 SSH Key克隆地址却选了http://开头的链接或者是换电脑后没有重新生成密钥。记住一个原则SSH 协议用密钥认证HTTPS 协议用账号密码或访问令牌认证。如果你配了密钥但克隆时还在问密码先看看是不是 URL 用错了协议。3.2 五种角色与可见性权限分配怎么落地GitLab 的角色体系从低到高依次是 Guest、Reporter、Developer、Maintainer、Owner。你可以把它们理解成“访客、观察者、干活的人、管家、房东”。角色越往上能做的事情越多。角色核心能力典型分配对象Guest查看 Issue、留言不能看代码非技术相关的外部协作人员Reporter查看代码、下载包、提 Issue需要确认代码状态的产品或测试Developer推送代码、创建分支、处理 MR干活的主力默认给这个Maintainer修改项目设置、管理保护分支、配置 CI技术负责人、核心维护成员Owner所有权限包括删除项目最终责任人和管理员团队协作中我坚持的最小权限原则是普通开发给 Developer组长和核心维护者给 MaintainerOwner 只留给极少数负责人。不要把所有人一律拉成 Maintainer否则一旦分支保护设置不严任何一个人都可能误改项目配置甚至删掉生产分支。外部协作者给了 Reporter 就足够能看代码、能提意见但改不了任何东西。可见性级别三种私有、内部、公开。默认私有是最稳妥的仓库只有在被明确授权的人那里可见。内部指的是所有登录用户可见多团队共用一个实例时这个选项要慎用它可能让你的代码仓库意外暴露给不相关的部门。公开就更是需要写权限审批流程才能使用的选项我一般直接建议团队全员使用私有。3.3 保护分支与 MR 约束防止代码被“直接改歪”分支保护是团队协作里最容易被忽视却也是最能防止事故的功能。默认创建的 main 分支虽然是保护状态但它仍然允许 Maintainer 直接推送代码。如果不做进一步约束很容易演变成“谁觉得没问题就直接 push 上线”Code Review 变成走过场。推荐的做法是到“设置-仓库-保护分支”里做三件事第一把 main 分支设置为不允许任何人直接推送只允许通过合并请求变更代码第二把“允许维护者推送”也关掉让维护者同样走 MR 流程第三开启 MR 的强制流水线检查让 CI 不通过的合并请求根本无法合并。这样设置之后main 分支的每一次变更都有迹可循是谁合并的、CI 是否通过、有没有人批准。团队成员自然就养成了“先建分支、开发完提 MR、合并前必须看检查结果”的习惯。再配合“合并前必须解决所有待讨论的评论”选项Code Review 的意见不会被轻易忽略。4. CI/CD 流水线从 Runner 到 .gitlab-ci.yml4.1 Runner 部署与注册常见踩坑CI 流水线不能凭空执行任务必须有一台或多台 Runner 接受任务。Runner 有三种作用域实例级共享 Runner、组级 Runner、项目级 Runner。新手不要一上来就部署一个共享 Runner 让全公司共用建议先在项目里注册一个项目级 Runner把流程跑通再按需提升到组级或实例级。安装 GitLab Runner 后最核心的是执行注册命令。在项目“设置-CI/CD”页面可以找到注册令牌然后执行sudo gitlab-runner register \ --url https://gitlab.example.local \ --registration-token 你的token \ --executor docker \ --docker-image alpine:latest \ --description local-docker-runner注册时选择dockerexecutor 后每个 CI 任务都会在一个独立的容器里执行相互隔离不会污染宿主环境。--docker-image是默认的构建镜像实际每个 job 里还可以单独指定image字段覆盖它。比如 Java 项目常用maven:3.9-eclipse-temurin-17Node 项目用node:18。Runner 注册成功后在项目 CI/CD 设置页能看到它上线。最常见的 Runner 问题是注册时一直报x509证书错误。这通常是因为 GitLab 用了自签证书Runner 机器不信任它。解决方式有两种要么在 Runner 的配置里加上tls-skip-verify true让 Runner 跳过证书校验要么把自签证书安装到 Runner 所在机器的系统证书目录。正式环境我强烈建议直接用正规证书省下后续一整套信任链维护的麻烦。Runner 并发数量的调优也很容易被忽略。默认的concurrent值是 1也就是说同一时间只能执行一个任务其它 job 只能排队。按机器核数把它调成 4 或 8会让流水线明显快起来。调的位置在 Runner 的config.toml文件里修改后重启 Runner 服务即可。4.2 一个能直接上手的 .gitlab-ci.yml 示例流水线的核心是项目根目录下的.gitlab-ci.yml文件。第一次写的人很容易被 YAML 的缩进坑到记住一个原则不要使用 Tab 缩进全部用空格而且缩进层级必须一致。下面这份配置覆盖了大部分小团队最基础的需求stages: - build - test - deploy variables: APP_NAME: demo-app MAVEN_OPTS: -Dmaven.repo.local$CI_PROJECT_DIR/.m2/repository build-job: stage: build image: maven:3.9-eclipse-temurin-17 script: - mvn clean package artifacts: paths: - target/*.jar expire_in: 1 week tags: - java-build test-job: stage: test image: maven:3.9-eclipse-temurin-17 script: - mvn test needs: - build-job artifacts: paths: - target/surefire-reports/ expire_in: 1 week deploy-job: stage: deploy image: alpine:latest before_script: - apk add --no-cache openssh-client script: - scp target/*.jar deployexample-server:/opt/app/ environment: name: production rules: - if: $CI_COMMIT_BRANCH main几个关键点说明一下。stages声明了阶段顺序执行时会按 build、test、deploy 依次进行。script是真正要执行的命令它是在容器里跑的所以环境是干净的不要妄想里面的依赖会保留到下一个 job。artifacts把构建产物传递到后续任务它和cache是两码事后面细讲。tags可以帮你在多个不同环境的 Runner 之间做出选择比如给带 Maven 缓存的 Runner 打上java-build标签。rules完美替代了旧的only/except写法上面这个配置的效果是只有 main 分支的提交才触发部署。当流水线跑起来以后你会看到每个 job 都有独立的日志和执行时长。这比本地跑脚本有用得多因为每次提交都会留下可追溯的构建记录。哪个 job 失败了点开日志就能定位到具体命令和报错。4.3 缓存、制品与多环境部署要点缓存和制品是新手最容易混淆的两个机制。cache的主要作用是加速依赖安装比如把node_modules、Maven 的本地仓库目录缓存起来下次流水线跑同一份代码时就不需要重新下载依赖它相当于给构建过程开了个“好记性”。artifacts则是把 job 的产物传递给后续阶段比如编译出来的 jar 包、测试报告它们是有明确用途的交付物并且可以设置过期时间。缓存有个很容易踩的坑默认的缓存 key 如果在分支之间变化命中率会很低。我的实践是用环境相关的 key 来提升复用率cache: key: $CI_COMMIT_REF_SLUG paths: - node_modules/$CI_COMMIT_REF_SLUG是分支名经过清洗后的变量同一个分支的流水线之间就能共享这个缓存。如果你的依赖下载成了流水线的主要耗时来源再引入MAVEN_OPTS这类环境变量把本地仓库路径指向项目目录也能显著加速。多环境部署方面GitLab 的environment关键字可以在界面上形成一条“部署历史时间轴”每次部署到生产环境都会留一个记录点。如果你想做预发和生产两套环境可以拆两个 deploy job分别用name: staging和name: production再通过rules或手动触发的when: manual来控制执行时机。推送到主分支自动部署预发生产环境则让有权限的人在流水线里点按钮确认这样既灵活又安全。5. 代码审查与 MR 协作工作流5.1 三种分支工作流到底选哪种MR 不只是一个人点个合并按钮它背后代表的是团队对代码流转节奏的约定。常见的有三种工作流GitHub Flow 的核心是 main 分支永远保持可部署状态开发者从 main 拉出功能分支开发完成提 MR经过 Code Review 和 CI 后合并回 main。它的优点是简单直白非常适合快速迭代的中小团队。Git Flow 则是把分支拆得很细master 放稳定代码、develop 做集成分支、feature 分支做功能开发、release 分支准备发布、hotfix 处理紧急修复。这种模型适合发布周期长、版本规划严格的团队但管理成本确实高如果团队没有专职的发布负责人很容易在分支切换上消耗大量精力。GitLab Flow 是官方推荐的折中方案强调所有变更必须走 MR必须过 CI同时可以引入环境分支。比如 main 对生产环境pre-production 对预发布环境。功能开发从环境分支拉出合并回环境分支再由环境分支合并到 main。大多数团队我建议从 GitHub Flow 起步。它让团队成员把精力花在“编写好的 MR 描述”和“认真看代码”上而不是花在与复杂的分支规则搏斗上。等业务进入多版本并行阶段再考虑在 GitLab Flow 里加入环境分支。5.2 MR 模板、批准规则与 Code Review 技巧MR 模板能显著提升审查效率。在项目根目录创建.gitlab/merge_request_templates/Default.md写上固定的区块变更背景、变更内容、测试情况、影响范围、检查清单。这样每个人创建的 MR 描述都会保持统一格式审查者一眼就能抓住重点不用反复追问“这个改动是解决什么问题的”。模板文件示例## 变更背景 填写这个 MR 要解决什么问题 ## 变更内容 - 改动模块 - 涉及接口 - 数据库变更 ## 测试情况 - [ ] 本地自测通过 - [ ] 流水线通过 - [ ] 联调环境已验证 ## 影响范围 哪些服务、哪些页面会受影响批准规则方面我建议至少开一个并且把“流水线必须通过”“合并且前必须解决所有待讨论评论”强制打开。这些设置全部完成后MR 的合并按钮只有在所有条件满足时才会亮起来。Code Review 时最实用的经验是控制 MR 的规模。单个 MR 改动量在 200 到 400 行以内时审查质量最高超过 1000 行的 MR即使认真看了也很容易漏掉问题。再一个技巧是合并前把源分支 rebase 到目标分支能减少大量不必要的冲突。GitLab 页面上的 merge 按钮通常支持 squash 选项如果你的团队不希望历史里都是零碎的提交可以在项目设置里把 squash 合并设为默认。审查过程本身也有几个值得坚持的原则评论尽量给出具体修改建议而不是只说“这里不对”对非阻断的小问题用“可以后续优化”来标注避免阻塞 MR 合并对大改动建议本地把分支拉下来实际跑一遍不要只凭 diff 判断。6. 日常运维、备份恢复与问题排查6.1 常见报错速查表GitLab 用久了总会遇到各种五花八门的报错。下面这几个是我和团队成员实际踩过、频率最高的列成速查表方便排查。现象常见原因处理建议Permission denied (publickey)SSH Key 没生效或协议不对执行ssh -T git域名测试确认克隆地址是 SSH 而非 HTTPS页面 502/500后端进程异常或磁盘满查看 Puma/Sidekiq 服务状态执行df -h看磁盘Job 一直 PendingRunner 离线或并发不够检查 Runner 在线状态调大concurrentclone 大仓库失败内存或网络超时用git clone --depth1浅克隆再逐步拉取历史推送代码超时大文件过多检查是否误提交了大体积二进制文件考虑 Git LFS数据库连接失败PostgreSQL 资源耗尽或磁盘满立即清理备份和日志空间再重启容器排查 GitLab 问题时我最常用的三个命令是sudo gitlab-ctl status、sudo gitlab-ctl tail和sudo gitlab-ctl reconfigure。前两个是看服务状态和日志第三个是让配置变更生效。几乎所有“改完配置没反应”的情况都能用 reconfigure 解决。Docker 环境下对容器执行命令不太一样需要写成sudo docker exec gitlab gitlab-ctl reconfigure。有一个隐蔽的坑是磁盘满导致的诡异故障。GitLab 的很多组件在磁盘写满后会表现成随机错误一会儿报数据库连不上一会儿报仓库写入失败。遇到无法解释的故障第一件事永远是df -h和free -h把资源和容量问题排除掉再谈别的。6.2 备份、恢复与升级的正确姿势备份应该在 GitLab 投入使用之前就配置好而不是等数据出问题后追悔莫及。在 Docker 环境下备份命令是sudo docker exec gitlab gitlab-backup create备份默认生成在/var/opt/gitlab/backups目录下对应宿主机的数据卷里。恢复时需要把备份文件放回这个目录然后执行sudo docker exec gitlab gitlab-backup restore BACKUP时间戳这里必须强调一个很多文档不会明说的点备份文件不包括配置文件和环境变量尤其重要的是gitlab-secrets.json。如果这个文件丢失即使数据库备份完整也恢复不出一套能正常解密数据库的实例。所以备份策略应该是“数据库备份 配置文件 gitlab-secrets.json”三件套然后把这些文件同步到异地存储。升级方面GitLab 的版本节奏比较快大版本之间不能随意跳级官方每个大版本都给出了明确的升级路径。Docker 布局下升级比较简单拉取新版本镜像停止旧容器重新运行同一套 volume 的启动命令即可。但升级前一定要检查官方升级路径文档确认自己当前版本能否直接跳转到目标版本。如果你从 CE 升级到 EE还要提前准备许可证并且先在预发环境验证。我建议把升级动作固定成流程做备份、读升级路径、升级到中间版本、验证核心功能、再继续往上升。不要在 CI 正在大量跑流水线的时候做版本变更尽量选在团队活动少的时段操作。6.3 团队落地 GitLab 过程中最值得留意的几件事写到最后聊聊我在几个团队里推广 GitLab 的一些真实体会。部署其实是最简单的难的是让团队真正把流程跑起来。一开始如果强推复杂的权限和分支规则阻力会相当大。我的做法是先选一个节奏正常的小项目做试点把保护分支、MR、CI 全部开起来让团队在真实迭代中体会“流水线红了就不该合并”这件事的价值。跑通两三周之后大家自然会认可这套流程再逐渐推广到更多项目。权限分配上要坚持最小化。很多事故不是因为有人恶意操作而是因为权限过大造成误操作。默认给 Developer不要为了省事全员 Maintainer。Owner 和 Maintainer 只有少数人该有。还有一个小技巧是善用 GitLab 的全局搜索。项目多了之后找代码、找 MR、找 Issue 都靠它。我见过有人每次都从菜单一层层点进去翻项目效率很低。直接在顶部搜索框输入功能名或文件名几秒钟就能定位到目标。这个习惯值得刻意培养。最后想说的是GitLab 本身只是一个工具团队真正收获的是把流程透明化之后所有人面对代码库时那种自觉严谨的态度。从最初只把它当仓库用到后来形成一整套“MR CI Code Review”的协作规范你会发现最有价值的不是某个具体功能而是这套流程逼着大家在提交代码前多想一步。别忘了定期做一次备份恢复演练真正动手恢复过你才会对这套系统有底气。