一个多月前帮朋友在一台CentOS 7服务器上部署GitLab,原以为就是下载RPM、rpm -ivh一把梭,结果从系统选型到启动排查整整折腾了大半天。这台机器是台2C2G的“老爷机”,装完GitLab CE之后页面直接502,后来一步步查日志、调内存、配swap才跑起来。今天把这次完整过程整理出来,从硬件准备、安装路线选择、初始配置、启动失败排查到高危漏洞修复,一次性讲透。文章适用于两类人:一是准备在自己手头的CentOS服务器上搭GitLab的运维同学,二是想在虚拟机里练手、但不知道从哪儿下手的新手。
1. 先把需求理清楚:这台CentOS服务器要准备到什么程度
很多人拿到安装教程就急着敲命令,结果装到一半发现磁盘不够、内存不足、yum源超时,回头再折腾系统,反而更慢。我建议动手前先花十分钟确认三件事:硬件配置、系统版本、网络和时间同步。
1.1 硬件门槛:内存、CPU、磁盘的真实建议
GitLab官方写的硬件要求不高,但实际跑起来你会发现它是个“吃内存大户”。它默认会拉起PostgreSQL、Redis、Puma、Sidekiq、Nginx、Prometheus这些组件,一整套下来,2G内存根本不够舒服地跑。
我按团队规模给一个参考表,这是我反复装过的经验值:
| 场景 | 配置建议 | 说明 |
|---|---|---|
| 个人练手/几人的小团队 | 2核4G内存、40G以上磁盘 | 需要关闭Prometheus并做内存优化,否则容易502 |
| 20人左右团队 | 4核8G内存、100G磁盘 | 比较舒服,基本不用折腾 |
| 50人以上团队 | 8核16G内存、200G以上SSD | 建议单独挂数据盘给GitLab storage |
磁盘方面,GitLab安装包解压到/opt/gitlab后大概占4~5G,仓库数据、日志都放在/var/opt/gitlab。如果你有独立数据盘,建议先把数据盘挂到/var/opt/gitlab或者至少给/opt和/var留足空间。别等到gitlab-ctl reconfigure一直卡住,一查df -h发现/满了,那就很被动了。
提示:2G内存的机器不是不能装,但装完后一定要做两件事:加swap、减小Puma并发。这个我在第4章会给出具体做法。
1.2 系统版本与GitLab版本匹配:为什么我还在用CentOS 7
说实话,CentOS 7已经停止官方维护了,新项目我不太推荐继续用。但现实是很多公司里的老服务器、虚拟机上跑的就是CentOS 7,一时半会儿换不了。这篇内容就是围绕CentOS 7展开的,所以我默认你的环境是CentOS 7.x minimal。
如果你跟我一样用的是minimal版,装GitLab前第一件事不是装GitLab,而是先确认yum源能不能用。CentOS 7停维护后,默认的mirror.centos.org源已经失效,会出现类似http://mirrors.aliyun.com/centos/7/os/x86_64/repodata/repomd.xml: [Errno -1]的报错。解决办法是把yum源切换到vault镜像,比如清华的centos-vault/7.9.2009/os/x86_64。大致操作是编辑/etc/yum.repos.d/CentOS-Base.repo,把baseurl指到vault路径,问题就解决了。
GitLab官方对系统的支持也有个时间线。我印象里GitLab CE还提供el7的RPM包到16.x这个阶段,再往后的新版本官方就不再为CentOS 7发布安装包了。所以在CentOS 7上装GitLab,没必要追最新版,选一个16.x的补丁版本反而更稳。这个版本选择很重要,直接决定后续漏洞修复的升级路径。
1.3 网络、域名与时间同步的预先准备
安装之前想好GitLab用什么地址访问。如果是内网使用,可以直接用IP加端口,比如http://192.168.1.10:8090;如果买了域名,提前把域名DNS解析到这台服务器。external_url这个配置后面第3章会详细说,现在只需要记住:事先规划好端口。
还有一个很多人忽略的点:时间同步。GitLab对服务器时间很敏感,时间偏差太大会导致登录抛出异常、Git操作报证书或JWT验签失败。刚装的CentOS 7多半没有开启时间同步,可以先用timedatectl看一下状态:
timedatectl status如果NTP synchronized是no,就开启NTP同步或者装chrony:
yum install -y chrony systemctl enable chronyd --now chronyc sources -v看到^*开头的行就说明已同步到上游时间服务器。这一步虽然简单,但能让后面少掉很多奇怪的坑,尤其是后面要配合个人访问令牌、SSL证书的场景。
2. 原生RPM和Docker两条安装路线,我最终选了哪条
装GitLab社区版主要有两条路线:一条是在CentOS上直接用官方/镜像源提供的RPM包装;另一条是跑Docker容器。热词里也有人在搜docker安装gitlab,我把两条都讲一下,并给出我的选择逻辑。
2.1 两条路线的资源占用和维护成本对比
原生RPM方式是把GitLab作为普通systemd服务安装到系统里,由gitlab-ctl统一管理各组件。Docker方式是拉取gitlab/gitlab-ce镜像,用容器跑一套完整的GitLab进程。
| 对比项 | 原生RPM安装 | Docker安装 |
|---|---|---|
| 内存占用 | 相对可控,高一点 | 容器本身还要占系统资源,略高 |
| 升级方式 | rpm -Uvh后reconfigure | 拉新镜像、重建容器 |
| 备份恢复 | 用gitlab-backup命令 | 稍微繁琐,还要处理volume |
| 与系统集成 | 直接监听端口,Nginx、SSH都原生 | 需要做端口映射,SSH端口冲突更明显 |
| 适合人群 | 服务器上不想再引入容器层,追求稳定 | 想隔离环境、换机器方便 |
我最终选了原生RPM。原因很简单:这台CentOS 7内存本来就不富裕,再套一层Docker会增加开销;而且GitLab升级时RPM方式只要换包再reconfigure,流程上更成熟。如果你以后打算上K8s或者希望环境完全隔离,选Docker也不是不行,但新手我还是建议用原生RPM,遇到问题好查日志,资料也多。
2.2 用清华镜像源安装GitLab CE的完整步骤
官方推荐的安装方式是把packages.gitlab.com仓库加入yum源。但国内网络访问这个源很慢,动不动超时。我的做法是直接用清华的GitLab CE镜像源,速度快且稳定。
在/etc/yum.repos.d/下新建gitlab-ce.repo:
cat > /etc/yum.repos.d/gitlab-ce.repo <<'EOF' [gitlab-ce] name=GitLab CE Repository baseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ enabled=1 gpgcheck=0 EOF然后执行:
yum clean all && yum makecache yum install -y gitlab-ce安装过程会自动下载所需的依赖包(比如policycoreutils、openssh-server等),在minimal系统上额外依赖比较多,耐心等几分钟。装完以后,GitLab相关的文件分布在:
- 主程序目录:
/opt/gitlab - 配置目录:
/etc/gitlab - 数据目录:
/var/opt/gitlab - 日志目录:
/var/log/gitlab
注意:
/etc/gitlab/gitlab.rb是核心配置文件,后续external_url、端口、内存参数都在这里改。改完必须执行gitlab-ctl reconfigure才会生效。
如果你不想用yum源,也可以直接下载RPM包离线安装。去清华镜像的gitlab-ce/yum/el7/目录挑一个16.x的版本,比如:
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-16.10.8-ce.0.el7.x86_64.rpm rpm -ivh gitlab-ce-16.10.8-ce.0.el7.x86_64.rpm离线包的好处是可以用u盘或内网传输,适合不出网的环境。
2.3 通过Docker安装的参考命令与注意事项
如果你仍想用Docker,CentOS 7上先确保Docker装好并且存储驱动正常。GitLab官方Docker镜像的参考启动命令如下:
docker run --detach \ --hostname gitlab.example.com \ --publish 8929:80 \ --publish 2289: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 \ gitlab/gitlab-ce:16.10.8-ce.0这里有三个细节容易踩坑:
--publish 8929:80表示把宿主机的8929端口映射到容器内的80端口,访问就用http://IP:8929。- SSH端口冲突在容器里更普遍,因为容器内22端口已经被gitlab-shell占用了。你要把容器内的22映射成宿主机的其他端口,比如2289,否则宿主机的SSH功能会被干扰。
- CentOS 7上Docker的存储驱动建议用overlay2,文件系统最好支持d_type,否则可能导致容器内文件操作异常。
Docker方式最大的优点是环境干净,升级时换镜像版本就行,卷目录保持不变数据不会丢。但如果你对容器原理不熟,出了问题会感觉“隔着一层”,日志不好定位,所以我个人在CentOS 7上更倾向原生RPM。
3. 第一次启动前必须改的配置:external_url、防火墙和初始密码
安装包装完后,还没到“直接访问”的地步。GitLab默认用localhost地址启动,你不改配置是没法通过IP访问的。这一步我把它拆成三块:改URL、放防火墙、拿初始密码并换token。
3.1 修改external_url与SSH端口冲突的解法
编辑/etc/gitlab/gitlab.rb,找到external_url这一行,改成你的实际访问地址:
external_url 'http://192.168.1.10:8090'如果你有域名,就写成'http://gitlab.example.com'。注意URL结尾不要带斜杠,否则reconfigure时Nginx配置会出问题。
改完执行:
gitlab-ctl reconfigure gitlab-ctl restart等一两分钟,访问http://192.168.1.10:8090/users/sign_in看是否能出来登录页。
这里必须单独提醒一个SSH端口的大坑。GitLab安装完后会自动接管22端口作为Git SSH克隆通道。如果你的服务器本身也是用22端口SSH远程登录的,装完GitLab之后你会发现服务器“SSH连不上了”——不是你密码错了,是端口被GitLab的openssh占用了。
解决办法有两个:
- 把系统sshd端口改到其他端口,比如2222,然后防火墙放行2222,远程连接改用
ssh -p 2222。 - 保留系统sshd的22端口,把GitLab的ssh端口改成别的,比如在
gitlab.rb里加一行:
gitlab_rails['gitlab_shell_ssh_port'] = 2289改完重新reconfigure,推代码时SSH URL里就会带:2289。我的习惯是用方案二,系统SSH维持22不变,GitLab用2289,互不干扰。
3.2 防火墙放行与SELinux处理
CentOS 7默认开了firewalld,如果你不开端口,外部访问大概率超时。假设你的external_url用的8090端口:
firewall-cmd --permanent --add-port=8090/tcp firewall-cmd --reload firewall-cmd --list-ports如果给GitLab配置了SSH端口2289,也一并放行:
firewall-cmd --permanent --add-port=2289/tcp firewall-cmd --reload再一个就是SELinux。CentOS 7默认状态是enforcing,虽然GitLab的安装包理论上带SELinux策略,但实战中Nginx绑定非标准端口或者反向代理时,偶尔会触发AVC拒绝。遇到Nginx起不来的情况,又确认端口没被占用,不妨先看SELinux:
getenforce如果是enforcing,临时放行可以执行setenforce 0。这个方法只是临时,重启失效。要彻底关闭就改/etc/selinux/config,把SELINUX=enforcing改成SELINUX=permissive。更规范的做法是用semanage把自定义端口加进http_port_t:
yum install -y policycoreutils-python semanage port -a -t http_port_t -p tcp 8090但说实话,内部服务器如果对SELinux没硬性要求,很多团队都是直接permissive,省心。
3.3 root初始密码获取、修改和个人访问令牌
GitLab从较新版本开始不再使用“默认密码”,而是安装时生成一个随机密码保存在/etc/gitlab/initial_root_password文件里。这个文件有效期是24小时,24小时后会自动删除。所以拿到登录页后,第一件事是去读这个文件:
cat /etc/gitlab/initial_root_password复制Password:后面的值,用root账号登录。登录进去后马上在User Settings -> Password里改成自己的密码。
改完密码,我强烈建议马上创建一个个人访问令牌(PAT),因为你后面用IDEA、PyCharm或者命令行HTTPS方式推送代码时,GitLab会拒绝单纯用密码登录。热词里有“login failed. check api token or gitlab version”这类报错,多半就是认证方式不对。
创建令牌的位置在:User Settings -> Access Tokens,名称随便填,scope勾选api和read_repository,过期时间自己设,生成后立刻复制保存,页面刷新后就不会再显示了。使用方式:
- HTTPS克隆地址的用户名填
root(或你的用户名) - 密码不是登录密码,而是这个访问令牌
很多人在IDEA里反复输入登录密码死活连不上,就是因为没理解“HTTP克隆用PAT而不是密码”这一点。这个细节我每次都要跟同事强调。
4. 启动失败是常态:从502到converge卡住的完整排查链路
如果你照上面步骤操作,大部分能正常跑起来。但GitLab组件多,启动失败的概率不低,尤其是低配服务器。我把自己踩过的几个典型场景完整还原一遍,你按这条链路排查会很快。
4.1 内存不足导致502或Sidekiq退出
我在2C2G机器上装完GitLab CE后,访问首页直接502。先看服务状态:
gitlab-ctl status输出大概是:
run: alertmanager: (pid 1234) ... run: gitaly: (pid ...) ... run: postgresql: (pid ...) ... down: sidekiq: ...内存不足时,最常见的表现就是sidekiq起不来,或者Puma进程反复重启。再看日志:
tail -n 50 /var/log/gitlab/puma/current日志里全是内存分配失败或者进程被杀掉的记录。
解决方案分两步:第一步调低并发,编辑/etc/gitlab/gitlab.rb:
puma['worker_processes'] = 2 puma['min_threads'] = 1 puma['max_threads'] = 8 sidekiq['max_concurrency'] = 5 prometheus_monitoring['enable'] = falseprometheus_monitoring关闭后能省下不少内存,对小机器非常有效。改完重新reconfigure并重启:
gitlab-ctl reconfigure gitlab-ctl restart第二步是加swap。2G内存裸跑GitLab实在太勉强,给系统补一个2G的swap文件:
dd if=/dev/zero of=/swapfile bs=1M count=2048 chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile swap swap defaults 0 0' >> /etc/fstab这里不要用fallocate去创建swapfile,某些文件系统上fallocate生成的文件作为swap会报“swapfile has holes”,dd虽然慢一点但更稳。加完swap后再看free -m,可用内存会宽裕很多。
4.2 reconfigure收敛失败与PostgreSQL起不来的原因
运行gitlab-ctl reconfigure时卡在Running handlers或者PostgreSQL相关步骤上,是另一类高频问题。
先看是不是磁盘满了:
df -h如果/使用率达到100%,GitLab写入数据失败就会导致converge失败。解决办法是清理日志和旧包,或者给相关目录扩容。/var/log/gitlab下的日志如果长期不轮转,体积会涨得很快,可以用journalctl --vacuum-time=3d清理systemd日志;GitLab自己的日志可以先删掉旧的.log.1这类归档文件。
另一个常见原因是PostgreSQL目录权限错误。如果报错里出现Permission denied,多半是/var/opt/gitlab/postgresql或/var/opt/gitlab/git-data的属主不对,可以重置:
chown -R git:git /var/opt/gitlab/postgresql chown -R git:git /var/opt/gitlab/git-data然后重新reconfigure。如果PostgreSQL数据目录损坏,最粗暴但有效的方案是彻底重新初始化。先确认没有重要数据,然后:
rm -rf /var/opt/gitlab/postgresql/data gitlab-ctl reconfigure它会重新生成一个空的PostgreSQL数据库。这个操作会把所有GitLab内置数据库清空,仓库数据如果是以文件形式存在的并不会丢,但用户、项目记录都会没,所以我只建议在“本来就没数据”的练手环境里做。
排错时记得看日志,关键日志路径:
- PostgreSQL:
/var/log/gitlab/postgresql/current - Redis:
/var/log/gitlab/redis/current - GitLab整体服务管理日志:
gitlab-ctl命令本身会输出不少信息
4.3 时间不同步引发的登录与push异常
GitLab的很多操作跟时间戳绑定,比如session、JWT,以及和Gitaly之间的通信验证。服务器时间错误太离谱时,会出现登录页提交后一直转圈,或者Git推送时报证书/验签类错误,非常容易误判成代码或网络问题。
排查方法很简单:
date -R对比一下是不是跟实际时间差了几分钟以上。如果是,就按第1章的做法启用chrony时间同步:
yum install -y chrony systemctl enable chronyd --now chronyc sources -v如果你的服务器在一个完全隔离的内网,chrony连不上外部时间服务器,那至少要在内网指定一台可信的时间服务器,写入/etc/chrony.conf:
server 192.168.1.1 iburst然后systemctl restart chronyd。时间问题看起来小,实际引发的故障现象很迷惑,建议装完GitLab就先确认这一点。
4.4 兜底手段:备份命令和卸载重装的正确顺序
很多人在排查过程中会把GitLab越弄越乱,最后干脆卸载重装。卸载不是rm -rf /opt/gitlab就完了,顺序很讲究:
gitlab-ctl stop rpm -e gitlab-ce这样会保留/etc/gitlab和/var/opt/gitlab下的数据。如果确认不需要保留数据再手动删除目录。盲目删目录很容易把后端数据库彻底毁掉,后面想恢复都没得恢复。
正确的习惯是重装之前先备份:
gitlab-backup create执行后会在/var/opt/gitlab/backups下生成一个*_gitlab_backup.tar文件。GitLab配置单独备份一份:
cp /etc/gitlab/gitlab.rb /etc/gitlab/gitlab-secrets.json /root/gitlab-config-backup/gitlab-secrets.json保存了GitLab的加密密钥,以后升级迁移、恢复备份时都必须和数据库备份一起使用,丢了它即使有备份也恢复不了。这一点我见过不少人栽过。
5. 高危漏洞修复与版本升级:别让GitLab裸奔
装好GitLab不是终点,GitLab历史上出过好几个高危远程命令执行和账号接管类漏洞,热词里也有人在搜“gitlab高危漏洞修复方案”。这里我必须明确一个态度:高危漏洞的修复,核心是升级到官方修复版本,而不是靠web防火墙或者“改配置”硬扛。
5.1 为什么“不升级只改配置”救不了高危漏洞
GitLab两次比较著名的高危漏洞:
- CVE-2021-22205:影响特定版本的GitLab CE/EE,攻击者无需登录就能通过特定上传接口触发远程命令执行,属于极其严重的问题。官方在13.10.3等版本中修复。
- CVE-2023-7028:账号接管类漏洞,攻击者可以构造密码重置请求,把重置链接发给任意未验证邮箱,从而实现账号接管。官方在16.x系列中修复。
这类漏洞的共同点是“藏在代码逻辑里”,不像弱口令那种可以靠修改密码策略缓解。你看再多的访问控制,攻击入口还是存在。所以方案只有一条:升级到官方声明包含修复的版本。
对CentOS 7上的GitLab来说,这就回到了第1章的版本选择问题:如果你装的是16.x,就升到16.x最新的补丁版;如果你在生产环境用的是15.x甚至更老,则要先规划好升级路径,别直接跨大版本。
5.2 小版本升级的正确步骤(含备份)
升级前先备份,这个习惯必须养成。执行备份:
gitlab-backup create确认备份完成后,下载目标版本的RPM包。比如要升级到16.10.8:
wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-16.10.8-ce.0.el7.x86_64.rpm然后用rpm -Uvh更新,不是-ivh:
rpm -Uvh gitlab-ce-16.10.8-ce.0.el7.x86_64.rpm-U会在安装前先处理已存在的旧版本,避免版本冲突。升级包安装完成后GitLab会自动触发reconfigure,如果没有自动触发就手动执行:
gitlab-ctl reconfigure gitlab-ctl restart gitlab-ctl status最后验证:
cat /etc/gitlab-release确认版本号已经是你想要的版本。这时候用浏览器登录,简单跑一下“新建项目、提交代码”的流程,确认业务正常。
5.3 升级和降级都不能跳版本:注意跨大版本的边界
GitLab有一个很麻烦的约束:大版本之间不能随便跳。比如从14.x直接升到17.x,中间大概率会因为数据库结构不兼容而失败。正确做法是分段升级:
- 先升到14.x最新的补丁版
- 再升到15.x最新的补丁版
- 再升到16.x最新的补丁版
- 需要的话再升到17.x
每次升级前都做一次备份。生产环境一定要选在低峰期升级,并且通过巡检确认没报错再离开。
我自己的习惯是升级前把当前版本、目标版本、路径写成一个简单的检查清单,贴在终端旁边,一步一步打勾。比如:
- 当前版本是多少?
- 备份文件是否生成?
- 磁盘空间是否足够?
- reconfigure是否正常结束?
- 登录、推送是否恢复?
这套流程看着繁琐,但能避免“升级到一半发现数据库迁移失败、又退不回旧版本”的尴尬局面。
如果让我给你这条安装链路排优先级,我会说:先保证内存和磁盘,再谈安装速度;先解决时间同步,再谈登录体验;先学会备份,再谈升级。把这些基本功练熟之后再去折腾GitLab的各类集成和插件,你会发现顺手很多。