前几天一个朋友在群里问:想在公司的Ubuntu服务器上搭一套内部代码托管平台,该选什么方案?底下一堆人推荐各种付费平台,我就说了一句:Ubuntu加GitLab社区版,自己跑一台,完全够用。结果这位朋友去搜了一圈资料,回来说网上教程太杂,有的讲apt装、有的讲Docker装,参数五花八门,折腾了两天都没跑起来。
这其实是很多人的真实痛点。GitLab本身是个功能极全的DevOps平台,但恰恰因为功能多,初次部署时很容易被各种配置项绕晕。尤其是Ubuntu环境下,不同版本、不同安装方式的坑都不一样,网上资料又新老混杂,新手根本分不清哪个能用。我前前后后在Ubuntu服务器上部署、迁移、维护过好几次GitLab,踩过的坑足够写成一本书了。这篇就把我从零搭建、日常使用到CI/CD接入的完整经验一次性整理出来,照着做就行。
这篇内容适合谁?刚接手公司服务器想搭私有GitLab的运维同学、想在自己Ubuntu机器上搭代码仓库的个人开发者、以及正在被“gitlab使用教程”里那些零散资料折磨的新手。无论你是用虚拟机装的Ubuntu桌面版,还是云服务器上的Ubuntu Server,核心逻辑都一样。
1. 先想清楚:为什么是“Ubuntu + GitLab”这套组合
1.1 Ubuntu和GitLab搭配的典型使用场景
先说个容易被忽略的事实:GitLab官方对Ubuntu的支持是所有Linux发行版里最好的之一。无论是apt仓库安装还是Docker镜像,Ubuntu都是优先级最高的适配对象。所以当你看到一堆“ubuntu安装docker”“docker 安装gitlab 镜像”的教程时,背后其实有一个共同逻辑:在Ubuntu上跑GitLab,是社区验证最多、踩坑资料最全的路径。
什么样的场景适合这套组合?我总结下来有三类。
第一类是小型团队内网代码托管。GitLab社区版提供无限私有仓库、分支保护、代码评审、Issue追踪,这些功能对10人左右的技术团队完全够用,而且部署在公司内网,代码不出内网,合规性上让人放心。第二类是个人开发者的多设备同步需求。我自己就有一台Ubuntu服务器专门跑GitLab,用来托管一些不想放到公网平台上的个人项目,比如家庭自动化脚本、实验项目、简历模板等。第三类是学习CI/CD的场景。GitLab自带的CI/CD功能非常完整,你完全可以在自己的服务器上跑通一套“代码推送-自动测试-自动部署”的流水线,这个过程对理解现代DevOps工作流非常有帮助。
1.2 社区版与企业版怎么选
很多人最初搜索“gitlab 社区版下载”的时候会纠结:社区版、企业版到底有什么区别?我是不是必须用企业版?
社区版(CE)和企业版(EE)的核心代码是同一套,企业版只是在社区版基础上叠加了一些高级功能并受许可证约束。对绝大多数中小团队来说,社区版已经覆盖了日常所需:不限数量的私有仓库、分支保护、代码评审、Issue管理、Wiki、CI/CD基础功能、LDAP集成,这些都是免费的。企业版多出来的更多是大型组织才用得上的能力,比如多个审批级别、安全合规扫描、项目分析仪表盘等。
我的建议很简单:先从社区版开始,遇到明确的功能瓶颈再升级也不迟。版本选型上优先选最新的稳定版,因为GitLab的迭代速度很快,高频更新意味着老版本存在已知安全漏洞的可能性更高,这也是近几年“gitlab高危漏洞修复方案”频繁上热搜的原因。用新版本,很多漏洞天然就绕开了。
1.3 硬件配置和容量规划
在动手安装之前,必须先评估机器配置。GitLab是一个吃资源大户,这一点必须明确:最低2核4G能跑,4核8G才舒服,如果还要跑CI流水线,8核16G起步不嫌多。
我第一次部署时就是吃了配置的亏。在一台2核2G的云服务器上硬装GitLab,结果启动之后CPU直接拉满,页面打开要等十几秒,跑一次CI直接把服务干挂了。后来加了内存、限制了部分占用资源的组件,才算稳定下来。
磁盘方面也有讲究。GitLab默认会存储仓库数据、数据库、日志、备份文件,一定要预留足够的空间。我一般建议至少准备50GB给系统和数据,如果团队代码仓库多、历史久,直接上200GB也不过分。加上日常备份会占用额外的磁盘,这个余量务必要留出。
提示:如果是虚拟机安装Ubuntu再跑GitLab,建议给虚拟机分配至少4GB内存,并配置动态磁盘,否则后面扩容会很痛苦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与GitLab安装:三种路线怎么选
2.1 安装方式对比:apt、Omnibus还是Docker
GitLab在Ubuntu上的安装方式主要有三种:基于apt仓库安装、直接下载Omnibus安装包、用Docker跑容器。
apt方式适合喜欢用系统包管理器管理一切的人,升级、卸载都方便,但GitLab官方apt仓库在国外,国内服务器拉取时速度不稳定,而且apt安装时依赖冲突的问题也偶尔出现。Omnibus方式就是把所有组件打成一个安装包,一键安装,适合内网环境手动下载安装包再部署,因为可以事先下好包、离线安装,不依赖外部网络。Docker方式是我个人最推荐的,也是这几年“docker安装gitlab”热度一直很高的原因。它把GitLab所有组件封装进了一个容器,宿主机只要装了Docker就能跑,升级时换镜像即可,出问题删除容器重建,完全不影响宿主机其他服务。
我之前一直是Omnibus方式的重度用户,后来有一次升级失败导致GitLab服务起不来,处理过程极其痛苦。换到Docker之后,升级和回滚都变成了几分钟的事,整体可靠性提升了一个量级。如果你是新部署,直接从Docker方式开始是最省心的选择。
2.2 Ubuntu上安装Docker引擎
Docker安装本身不难,但网上教程经常把简单事情复杂化。这里给一套简洁可靠的流程,适用于Ubuntu 20.04及22.04版本。
先更新软件源并安装依赖:
bash复制sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
然后添加Docker官方GPG密钥和仓库:
bash复制curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
接着安装并启动Docker:
bash复制sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker
装完之后可以用 sudo docker run hello-world 验证一下。整个过程大概5分钟。
这里有一个经常遇到的问题:执行docker命令时总提示权限不足,需要加 sudo。解决方案是把当前用户加入docker用户组:
bash复制sudo usermod -aG docker $USER
newgrp docker
2.3 用Docker部署GitLab的完整过程和参数解析
GitLab官方Docker镜像的名称为 gitlab/gitlab-ce,这是全网下载量最大的GitLab镜像之一。部署之前先规划好数据目录,我习惯把GitLab相关数据统一放在 /srv/gitlab 下,方便备份和迁移。
创建目录:
bash复制sudo mkdir -p /srv/gitlab
然后编写docker-compose配置。我个人强烈推荐用docker compose来管理,而不是直接跑docker run,原因后面会讲。新建 /srv/gitlab/docker-compose.yml:
yaml复制services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
restart: always
hostname: git.example.com
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://git.example.com'
gitlab_rails['gitlab_shell_ssh_port'] = 2222
puma['worker_processes'] = 2
sidekiq['max_concurrency'] = 5
ports:
- "80:80"
- "443:443"
- "2222:22"
volumes:
- /srv/gitlab/config:/etc/gitlab
- /srv/gitlab/logs:/var/log/gitlab
- /srv/gitlab/data:/var/opt/gitlab
shm_size: '256m'
每个关键点解释一下。
hostname 和 external_url 决定了GitLab对外访问的地址。如果暂时没有域名,可以直接填服务器的IP,例如 external_url 'http://192.168.1.100',这样通过浏览器访问 http://192.168.1.100 就能进入GitLab界面。
端口映射部分,"80:80" 和 "443:443" 是把容器内的HTTP和HTTPS端口映射到宿主机。这里有个常见的认知误区:很多人会搜“gitlab 默认端口是多少”,结果搜到一些乱七八糟的答案。GitLab Web默认端口就是80(HTTP)和443(HTTPS),不是79,GitLab默认的SSH端口是22,容器里以22端口监听SSH。因为宿主机22端口通常已被系统SSH占用,所以我把容器22端口映射成了宿主机的2222端口,也就是 "2222:22"。这样配置后,GitLab仓库的SSH克隆地址会显示为 ssh://git@git.example.com:2222/group/project.git,也就是说端口不要搞错,否则克隆时会提示连接被拒绝。
GITLAB_OMNIBUS_CONFIG 中的参数按需添加。 puma['worker_processes'] 和 sidekiq['max_concurrency'] 是控制Web服务并发和后台任务并发数。机器配置不高的话建议限制一下,否则GitLab会按照CPU核心数自动分配过多worker,导致内存迅速耗尽。
数据卷挂载也很关键。把config、logs、data三个目录挂载出来,意味着容器可以被随意删除、重建,但您的所有代码仓库、用户数据、配置都会保留在宿主机上。这一点正是容器化部署最大的优势之一。
配置完成后启动:
bash复制cd /srv/gitlab
docker compose up -d
首次启动时容器内部会进行初始化,耗时比较长,大约3到10分钟不等,取决于机器性能。可以通过以下命令监控初始化进度:
bash复制docker logs -f gitlab
看到 gitlab Reconfigured! 字样说明初始化完成。此时访问 http://服务器IP,第一次会要求设置root密码,设置完成后即可用root账号登录。
注意:千万别在初始化过程中强制重启容器,否则可能造成数据目录文件不完整。我见过有人等了5分钟没反应,直接
docker restart,结果初始化进度丢失,前前后后折腾了一个多小时。
3. 日常用得最多的GitLab操作:从配置SSH到拉取代码
3.1 SSH密钥配置全流程
GitLab部署好之后,日常用得最多的就是代码的克隆、推送和拉取。这部分的核心是搞定SSH密钥。
为什么要配置SSH密钥?简单理解,SSH密钥就像一把“永不过期的门禁卡”,配置一次之后,以后所有Git操作都不再需要反复输入用户名密码。原理是本地生成一对密钥:私钥留在自己的电脑上,公钥上传到GitLab服务器。每次连接时服务器会验证你的私钥是否匹配公钥,匹配就放行。
配置过程分三步。
第一步,在本地生成密钥对:
bash复制ssh-keygen -t ed25519 -C "your_email@example.com"
这里我推荐使用 ed25519 算法而不是传统的 rsa,前者密钥更短、安全性更高、生成速度更快。一路回车即可,默认会保存到 ~/.ssh/id_ed25519。
第二步,查看公钥内容并复制:
bash复制cat ~/.ssh/id_ed25519.pub
第三步,登录GitLab网页,点击右上角头像,选择 Preferences,左侧菜单找到 SSH Keys,把公钥粘贴到输入框中,设置一个有效期,保存即可。
验证是否配置成功:
bash复制ssh -T git@你的GitLab服务器地址 -p 2222
注意这里的 -p 2222 一定要加上,因为前面部署时把SSH端口映射到了2222。如果看到 Welcome to GitLab, @username!,说明配置成功。
3.2 获取Access Token:IDE集成的关键
另一个高频操作是获取Access Token。不管你是用VS Code的GitLab插件,还是用IDEA自带的版本控制工具,都会遇到API Token的问题。
先回答最常被搜的那个问题:“gitlab token在哪里”。路径是:点击头像进入 Preferences,左侧选择 Access Tokens,填写Token名称、选择权限范围(通常勾选 api、read_repository、write_repository),设置过期时间,点击创建。创建完成后GitLab只会显示一次Token明文,必须立刻复制保存,关掉页面就再也看不到了。
设置Token之后,VS Code安装GitLab插件,在设置中填入GitLab实例地址和Token,就能实现仓库浏览、创建Merge Request等操作。这里有一个特别常见的问题,报错信息是“login failed. check api token or gitlab version. log in via git if the version is older than the supported one”。
这个问题我排查过很多次,核心原因通常是三个:Token权限范围不足、Token已过期、GitLab版本过旧导致API不兼容。解决方法是:到 Access Tokens 页面重新生成一个勾选了完整 api 权限的Token,然后检查一下GitLab版本是否过于老旧,如果是,建议升级到最新稳定版。
3.3 克隆、推送与分支管理实战
SSH密钥和Token配置完成之后,日常Git操作就比较顺畅了。
克隆仓库:
bash复制git clone ssh://git@git.example.com:2222/group/project.git
推送代码流程:
bash复制git add .
git commit -m "feat: 初始提交"
git push origin main
分支管理这块,经常被问的一个问题是“gitlab 如何查看某个分支是从哪个分支拉取的”。这个功能GitLab网页上没有直接展示,但通过Git命令可以准确查到。
先查看所有远程分支:
bash复制git branch -r
然后找到目标分支与各候选分支的共同祖先,用 git merge-base 来判断亲缘关系:
bash复制git merge-base 目标分支 候选分支
输出结果是一串提交哈希值,哈希值离哪个分支的HEAD越近,说明目标分支越可能来自该分支。更直观的做法是在GitLab网页上打开目标分支,查看提交记录中是否存在创建分支时的“merge commit”或分支起点。如果是团队协作项目,最简单粗暴的方法是去问创建这个分支的同学,省时省力。
4. 数据安全加固:备份恢复、升级避坑与防护基线
4.1 GitLab备份与恢复的规范操作
数据无价,这个谁都懂,但真正坚持做备份的人很少。GitLab容器化部署之后,备份其实很简单,核心是两条线:代码数据备份和配置文件备份。
代码数据备份使用GitLab自带的备份命令,在容器内执行:
bash复制docker exec gitlab gitlab-backup create
默认备份文件会生成在 /var/opt/gitlab/backups 目录下,由于我们挂载了数据卷,实际文件会出现在宿主机的 /srv/gitlab/data/backups 目录中。
配置文件备份的方式更简单,直接把整个config目录复制一份出来:
bash复制sudo cp -r /srv/gitlab/config /srv/gitlab/config.bak.$(date +%F)
这里有个容易忽略的细节:GitLab的关键信息不仅存在于代码仓库数据里,还存在于配置文件中。比如数据库密钥文件 /etc/gitlab/gitlab-secrets.json,一旦丢失,即使你有备份数据,恢复时也会因为无法解密数据库而失败。所以备份时,data和config必须分开备份,而且要放在一起管理。
恢复操作同样不复杂。先把备份文件放到容器的 /var/opt/gitlab/backups 目录下,然后执行:
bash复制docker exec gitlab gitlab-backup restore
恢复完成后重启容器:
bash复制docker restart gitlab
提示:如果是异地备份,建议把备份文件定期同步到另一台机器或对象存储。GitLab备份文件是明文打包的,里面包含全部私有代码,传输过程一定要走加密通道。
4.2 升级不踩坑:先备份再升级
GitLab的版本升级是运维中的“高危操作”。社区版迭代频繁,有时候官方会直接跳过中间版本,你从14升级到16的时候,可能要求必须经过15才能跳,不能一次跨太多。
我在实际升级中总结的一套安全流程:先完整备份(包括data和config),然后拉取新镜像,修改docker-compose中的镜像标签,执行 docker compose up -d 重启容器。容器启动后会自动执行迁移,这个阶段不要中断,耐心等待。
打开日志观察进度:
bash复制docker logs -f gitlab
等待迁移完成,看到服务正常监听后,用浏览器登录验证关键功能:仓库列表、代码浏览、CI流水线状态。确认无异常后,清理旧镜像:
bash复制docker image prune
升级过程中最常见的崩溃场景是数据库迁移时间过长,尤其是仓库数量多、历史久的实例。处理办法是耐心等待,不要中途重启。如果超过30分钟还没有响应,再考虑查看日志定位问题。
4.3 安全防护:从漏洞修复到开放注册风险
GitLab出现在热搜里,除了安装和使用教程之外,还有一类频率很高的话题:“gitlab高危漏洞修复方案”以及“gitlab未授权访问风险”。这背后反映的是一个现实:GitLab功能庞杂、攻击面大,如果配置不当,很容易被外部扫描到并利用。
先明确一个误区:很多人一看到“未授权访问”就以为要按某个固定路径去修补漏洞,其实绝大多数风险来自配置疏漏,而不是代码漏洞。
最基本的防护动作是关闭注册功能。GitLab默认开启注册,任何拿到地址的人都能注册账号。对内部系统来说这很危险,一定要关闭。路径是:点击 管理员区域 -> 设置 -> 通用 -> 注册限制,取消勾选“开启注册”。
然后是限制访问来源。如果是内网系统,建议在防火墙上做限制,只允许公司内网IP访问GitLab的80和443端口。这一步能在源头拦截绝大多数外部扫描。
最后是定期更新版本。GitLab几乎每个月都有安全更新,很多高危漏洞修复方案其实就是“升级到最新修复版本”。建议订阅GitLab官网的安全公告列表,每周花两分钟看看有没有涉及自己版本的安全通告。
配置SSL证书也是必须做的一步。用Let's Encrypt免费证书或企业内部CA证书,把 external_url 改成HTTPS协议,确保代码传输过程中加密,防止中间人窃听。
5. CI/CD实战:GitLab自动构建流水线搭建
5.1 注册Runner:让GitLab有活儿可干
GitLab CI/CD的前提是有一台执行任务的Runner。Runner是独立于GitLab服务之外的执行器,可以在同一台机器上,也可以单独跑在一台专门的构建机上。
安装Runner的流程,Ubuntu环境下用官方安装包快速处理:
bash复制curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
安装完成后注册Runner:
bash复制sudo gitlab-runner register
注册过程会交互式询问几个问题:GitLab实例地址、注册Token、Runner描述等。注册Token从哪里拿?在GitLab项目中进入 设置 -> CI/CD -> Runner,可以看到项目专属的注册Token。
注册时有一个细节值得注意。Runner执行方式建议选择 docker,这样每次构建任务都会在一个全新的容器中运行,环境干净、互不干扰。执行器选择docker后,需要指定默认镜像,比如 python:3.11,后面构建任务如果不特别指定镜像,就会用这个默认值。
5.2 .gitlab-ci.yml配置示例:一个Python项目的CI
Runner注册完成后,需要在项目根目录编写 .gitlab-ci.yml 文件。这是CI/CD的配置文件,定义了流水线每个阶段要做什么。
一个最简单的Python项目CI配置如下:
yaml复制stages:
- test
- build
- deploy
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
before_script:
- python --version
- pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
test:
stage: test
script:
- pytest --junitxml=report.xml
artifacts:
when: always
reports:
junit: report.xml
build:
stage: build
script:
- python -m build
artifacts:
paths:
- dist/
deploy:
stage: deploy
script:
- echo "部署到服务器"
only:
- main
这里解释几个关键点。
stages 定义了流水线阶段,按顺序执行。before_script 是每个任务执行前的准备工作,我在里面指定了pip使用清华镜像源,解决国内服务器拉取Python依赖慢的问题。这和热搜词里“gitlab cicd python 依赖 仓库地址”其实是一类需求,很多人在内网环境跑CI,依赖源不通,才会去搜索怎么配置。
artifacts 表示把测试报告、构建产物保存到GitLab服务器,可以在网页上直接下载。 only: - main 表示只有推送到main分支时才执行部署。
配置好之后,推送代码到仓库,GitLab会自动触发流水线,在项目页面的 CI/CD -> 流水线 中可以看到执行进度。如果Runner工作正常,这里会显示绿色的成功状态。
6. 高频故障排查与日常维护速查
6.1 启动失败与页面无法访问
GitLab用Docker部署后,最容易出现的问题就是容器启动失败或者页面打不开。
先说端口占用。宿主机80端口被Nginx或其他Web服务占用时,GitLab容器会启动报错,提示端口冲突。解决方法是修改docker-compose中的端口映射,比如把宿主机8080端口映射到容器80端口:
yaml复制ports:
- "8080:80"
同时要把 external_url 改成 http://服务器IP:8080。
再一个常见场景是502 Bad Gateway。GitLab页面显示502,通常说明Web组件还没有完全启动,或者Puma进程崩溃。先等几分钟刷新一下,如果仍然502,用 docker logs gitlab 查看日志,重点看有没有数据库连接异常、磁盘空间不足之类的关键信息。
排查顺序我建议固定下来:先看容器状态 docker ps,再看日志 docker logs,最后检查磁盘 df -h。大部分GitLab问题都能在这三步里找到答案。
6.2 SSH连接失败和认证报错
SSH连不上GitLab是另一个高频问题。从前面的部署配置可以看到,我把GitLab的SSH端口映射成了2222,所以连接时候必须指定端口:
bash复制ssh -T git@git.example.com -p 2222
如果提示 Permission denied (publickey),说明密钥认证失败。排查顺序:确认公钥已经添加到GitLab的SSH Keys页面;确认本机使用的是正确的私钥文件,必要时通过 ssh -vT 查看详细调试信息。
配好VS Code插件后如果遇到“login failed. check api token or gitlab version”,我前面已经提过,核心还是Token权限、过期或版本过旧这三个原因。按部就班地检查一遍,问题基本就能解决。
6.3 资源占用优化与日常维护
GitLab是吞内存大户,尤其是在小配置机器上跑,内存吃紧是常态。如果发现GitLab响应变慢,先看内存占用:
bash复制docker stats
优化方向有三个。第一个是限制Puma worker数量,在 GITLAB_OMNIBUS_CONFIG 里把 puma['worker_processes'] 调低,比如2。第二个是给系统加swap,缓解物理内存不足的情况。第三个是关闭不用的组件,例如内置的Prometheus监控和Grafana,在配置里用 prometheus['enable'] = false 关闭,能省出一大块内存。
定期清理构建产物和日志也很有必要。CI流水线每次构建都会留下archives和日志文件,时间长了会占不少磁盘。可以在 docker-compose.yml 中设置自动清理策略,或者定期手动清理 /srv/gitlab/data/backups 目录下的旧备份文件。
我在实际运维中最常用的维护命令整理成了一张速查表:
| 操作 | 命令 |
|---|---|
| 查看服务状态 | docker ps | grep gitlab |
| 查看实时日志 | docker logs -f gitlab |
| 手动备份 | docker exec gitlab gitlab-backup create |
| 恢复备份 | docker exec gitlab gitlab-backup restore |
| 重启服务 | docker restart gitlab |
| 进入容器 | docker exec -it gitlab bash |
| 查看磁盘占用 | du -sh /srv/gitlab/* |
| 更新镜像 | docker compose pull && docker compose up -d |
最后分享一个我踩过的坑。早期我给一台配置很低的服务器装GitLab,图省事把Puma worker数设成自动,结果机器上的其他服务全被挤爆了。后来又试过盲目清缓存,把 /tmp 下的缓存文件当成垃圾清理掉,结果直接影响了构建进程。后来才明白,GitLab在资源紧张时的核心优化原则是“贪多嚼不烂”,宁可牺牲一些并发性能,也要保证服务的稳定可用。先按2个worker跑起来,后续根据真实负载再逐步调整。
这套Ubuntu加GitLab的方案,我前后维护了三四年,从个人项目到团队协作场景都用过。把数据目录和配置文件梳理清楚、数据安全防线建立起来之后,这个系统基本是“十年不坏”的状态。希望这篇能够帮你少走一些弯路。
