1. 为什么还要在 CentOS 7 上折腾 GitLab 13.1.2
先把话说在前头:CentOS 7 已经进入维护尾声,GitLab 13.1.2 也是好几年前的版本了。但现实情况是,不少公司内网、实验室环境、老旧的虚拟机集群里,跑的还是 CentOS 7,业务代码、CI 流程、权限体系全都绑在 GitLab 上,升级一次牵一发动全身。所以“在 CentOS 7 上把 GitLab 13.1.2 装起来、跑稳”这件事,依然有它真实的需求场景。
我自己就遇到过好几次:一台内网机器,系统是 CentOS 7.9,要求部署一套代码托管平台,团队规模不大,二三十人,日常就是 Git 仓库管理、Merge Request 审核、简单的 CI 跑测试。这种场景下,GitLab 13.1.2 的社区版(CE)完全够用,而且它对硬件的要求比新版本温和不少,4 核 8G 的虚拟机就能跑得比较舒服。
这篇文章面向的是有一定 Linux 基础的运维或后端同学,最好你之前手动装过 Nginx、MySQL 这类服务,知道 systemd 怎么管服务、防火墙怎么放行端口。如果你是完全的新手,也能跟着做,但遇到报错时需要你愿意去看日志、查原因。我会把整个安装过程拆成几个阶段:环境准备、依赖安装、GitLab 本体部署、配置调优、常见问题排查。每一步我都会说清楚“为什么这么做”,而不只是丢一堆命令让你复制。
需要特别说明的是,GitLab 的安装方式有好几种:源码编译、Docker 容器、Omnibus 包(也就是官方提供的 rpm/deb 一体化安装包)。在 CentOS 7 这个环境下,我强烈推荐用 Omnibus 包,原因很简单——它把 Ruby、PostgreSQL、Redis、Nginx 这些依赖全部打包在一起,版本都是官方调好的,你不需要自己去解决各种依赖冲突。源码编译那条路我走过一次,光是 Ruby 版本和 gem 依赖就能耗掉一整天,实在不划算。
提示:本文所有操作均基于内网测试环境,涉及的主机名、IP、密码等均为示例,请根据你自己的环境替换。安装前务必确认你拥有该服务器的 root 权限或 sudo 权限。
2. 安装前的环境准备与依赖梳理
2.1 系统版本与硬件资源的确认
动手之前,先确认几件事。第一,系统版本。执行cat /etc/redhat-release,正常应该看到类似CentOS Linux release 7.9.2009 (Core)的输出。GitLab 13.1.2 官方支持的 CentOS 7 版本是 7.4 及以上,7.9 是最稳妥的。如果你还在 7.2、7.3,建议先做一次系统小版本升级,否则可能会遇到 glibc 版本不匹配的问题。
第二,硬件资源。GitLab 是个“吃内存大户”,这一点必须提前说清楚。官方推荐的最低配置是 2 核 4G,但那是“能跑起来”的底线,实际使用中你会非常痛苦。我的经验是:
| 团队规模 | CPU | 内存 | 磁盘 | 说明 |
|---|---|---|---|---|
| 1-5 人 | 2 核 | 4G | 50G | 勉强可用,需加 Swap |
| 5-20 人 | 4 核 | 8G | 100G | 推荐配置,体验流畅 |
| 20-50 人 | 8 核 | 16G | 200G | 需考虑分离部署 |
| 50 人以上 | 16 核+ | 32G+ | 500G+ | 建议拆分成多节点 |
磁盘方面,GitLab 的仓库数据、CI 产物、日志都会持续增长,所以别卡着 50G 装,留足余量。另外,磁盘类型最好是 SSD,机械硬盘在跑 CI 或者做仓库检索时会明显卡顿。
第三,内存不够怎么办?加 Swap。这是 CentOS 7 上跑 GitLab 的一个关键技巧。4G 内存的机器,建议加 4G 到 8G 的 Swap。具体操作后面会讲。
2.2 网络、主机名与时间同步的配置
GitLab 对主机名比较敏感,因为它生成的仓库地址、克隆链接都会用到主机名。所以第一步是把主机名设置好。执行hostnamectl set-hostname gitlab,然后编辑/etc/hosts,加上一行127.0.0.1 gitlab。这一步不做的话,后面 GitLab 启动时可能会因为无法解析自己的主机名而报错。
时间同步也很重要。GitLab 的 token、证书、日志时间戳都依赖系统时间。CentOS 7 默认可能没开 NTP,执行timedatectl status看一下,如果显示NTP synchronized: no,就装个 chrony:yum install -y chrony,然后systemctl enable chronyd && systemctl start chronyd。同步完成后用timedatectl确认一下。
网络方面,确认服务器能访问外网,因为安装过程需要下载 GitLab 的 rpm 包和依赖。如果你的环境是纯内网,那就需要提前把 rpm 包和依赖包下载好,用离线方式安装。离线安装的坑比较多,我后面会单独说。
防火墙这块,CentOS 7 默认用的是 firewalld。GitLab 需要用到 80(HTTP)、443(HTTPS)、22(SSH)这几个端口。如果你打算用非标准端口,比如 8080 或者 2222,那也要一并放行。放行命令:
firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --permanent --add-service=ssh firewall-cmd --reload如果你用的是 iptables,那就用iptables -I INPUT -p tcp --dport 80 -j ACCEPT这种方式。另外,SELinux 也是个绕不开的话题。GitLab 官方建议把 SELinux 设为 permissive 或者 disabled,否则可能会遇到权限问题。我个人的做法是设为 permissive,这样既不影响安全审计,又能避免大部分权限报错。修改/etc/selinux/config,把SELINUX=enforcing改成SELINUX=permissive,然后重启生效。
2.3 依赖包与 Swap 空间的准备
GitLab Omnibus 包虽然把大部分依赖都打包了,但系统层面还是需要一些基础工具。执行下面这条命令安装:
yum install -y curl policycoreutils-python openssh-server openssh-clients \ postfix cronie perl wget vim net-tools这里面有几个包值得说明一下。policycoreutils-python是给 SELinux 用的,如果你关了 SELinux 其实可以不装,但装上没坏处。postfix是邮件服务,GitLab 发通知邮件需要它,即使你暂时不用邮件功能,也建议装上,否则安装脚本可能会报错。cronie是定时任务服务,GitLab 的一些后台清理任务依赖它。
Swap 的配置,如果你的内存小于 8G,强烈建议加。操作步骤:
# 创建 4G 的 swap 文件 dd if=/dev/zero of=/swapfile bs=1M count=4096 chmod 600 /swapfile mkswap /swapfile swapon /swapfile # 写入 fstab 实现开机自动挂载 echo '/swapfile swap swap defaults 0 0' >> /etc/fstab # 验证 free -h这里有个细节:dd命令创建文件会比较慢,如果你追求速度,可以用fallocate -l 4G /swapfile,但某些文件系统上 fallocate 创建的 swap 文件可能有问题,所以我还是习惯用 dd。另外,swappiness参数建议调低一点,比如设为 10,这样系统不会太激进地使用 Swap,避免影响性能。执行sysctl vm.swappiness=10,并写入/etc/sysctl.conf持久化。
3. GitLab 13.1.2 的安装与核心配置
3.1 添加官方源与安装 Omnibus 包
GitLab 官方提供了一个脚本,可以自动添加仓库并安装。但我不推荐直接用那个脚本,因为它会默认安装最新版,而我们要的是 13.1.2 这个特定版本。所以手动添加仓库更可控。
首先,创建一个仓库配置文件/etc/yum.repos.d/gitlab-ce.repo,内容如下:
[gitlab-ce] name=Gitlab CE Repository baseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/ gpgcheck=0 enabled=1这里我用的是国内某高校的镜像源,速度比官方源快很多。gpgcheck=0是跳过 GPG 校验,如果你对安全性要求高,可以改成 1 并导入对应的 GPG key,但那样会麻烦一些。对于内网环境,跳过校验是可以接受的。
然后执行yum makecache刷新缓存。接下来就是安装指定版本:
yum install -y gitlab-ce-13.1.2-ce.0.el7.x86_64注意版本号的写法,13.1.2-ce.0.el7是完整的版本标识。如果你不确定有哪些版本可用,可以用yum list gitlab-ce --showduplicates | sort -r查看。安装过程会下载一个几百兆的 rpm 包,耐心等待。
安装完成后,你会看到一行提示,让你运行gitlab-ctl reconfigure。先别急,我们还需要改配置。
3.2 核心配置文件 gitlab.rb 的调优
GitLab 的主配置文件是/etc/gitlab/gitlab.rb,这是一个 Ruby 语法的文件。每次修改后都需要执行gitlab-ctl reconfigure让配置生效。这个文件内容非常多,但真正需要改的没几项。
第一项,外部访问地址。找到external_url这一行,默认是http://gitlab.example.com,改成你自己的地址,比如http://gitlab或者http://192.168.1.100。如果你打算用域名,就写域名。这个地址会影响到仓库的克隆链接,所以一定要设对。
第二项,时区。找到gitlab_rails['time_zone'],设为'Asia/Shanghai'。不设的话,界面上的时间会差 8 小时,看日志和提交记录时会很别扭。
第三项,内存相关的调优。GitLab 默认会启动很多 worker 进程,在内存有限的机器上容易 OOM。可以调整以下几个参数:
unicorn['worker_processes'] = 2 unicorn['worker_timeout'] = 60 sidekiq['concurrency'] = 10 postgresql['shared_buffers'] = "256MB" postgresql['max_worker_processes'] = 8unicorn是 GitLab 的 Web 服务,worker_processes默认是按 CPU 核数算的,4 核机器会开 4 个 worker,每个 worker 占几百兆内存。如果内存紧张,就手动设成 2。sidekiq是后台任务队列,concurrency控制并发数,设成 10 比较稳妥。postgresql的shared_buffers设成内存的 1/4 左右比较合适,8G 内存的机器可以设 1GB 到 2GB。
第四项,邮件配置。如果你需要 GitLab 发通知邮件,就要配置 SMTP。以常见的企业邮箱为例:
gitlab_rails['smtp_enable'] = true gitlab_rails['smtp_address'] = "smtp.example.com" gitlab_rails['smtp_port'] = 465 gitlab_rails['smtp_user_name'] = "gitlab@example.com" gitlab_rails['smtp_password'] = "your_password" gitlab_rails['smtp_domain'] = "example.com" gitlab_rails['smtp_authentication'] = "login" gitlab_rails['smtp_enable_starttls_auto'] = true gitlab_rails['smtp_tls'] = true gitlab_rails['gitlab_email_from'] = "gitlab@example.com"这里要注意,465 端口用的是 SSL,如果服务商要求用 STARTTLS,端口通常是 587,smtp_tls要设为 false,smtp_enable_starttls_auto设为 true。配置错了邮件发不出去,但不会影响 GitLab 主服务运行。
第五项,备份相关。GitLab 自带备份命令,但默认备份文件会存在/var/opt/gitlab/backups,这个路径可能空间不够。可以改到其他盘:
gitlab_rails['backup_path'] = "/data/gitlab-backups" gitlab_rails['backup_keep_time'] = 604800backup_keep_time是备份保留时间,单位秒,604800 就是 7 天。这个参数只对 GitLab 自带的清理逻辑有效,实际生产中我建议还是用脚本配合 cron 做更精细的管理。
3.3 执行 reconfigure 与首次访问
配置改完后,执行gitlab-ctl reconfigure。这个过程会持续几分钟,它会根据你的配置重新生成所有服务的配置文件,并启动服务。第一次执行时,它会初始化 PostgreSQL 数据库、创建必要的目录、生成证书等。屏幕上会滚动大量输出,只要最后没有红色的 error,基本就是成功了。
reconfigure 完成后,执行gitlab-ctl status查看各服务状态。正常应该看到run:开头的行,表示服务在运行。如果有down:或者fail:,就要去看对应的日志,日志在/var/log/gitlab/下面,每个服务一个目录。
接下来在浏览器里访问你设置的external_url。第一次访问会要求你设置 root 用户的密码。密码要求至少 8 位,不能太简单。设置完成后用 root 和你刚设的密码登录,就能看到 GitLab 的主界面了。
登录后第一件事,我建议去“管理区域”里把一些默认设置改掉。比如关闭用户注册(Sign-up restrictions),因为内网环境通常不需要开放注册,账号由管理员创建更可控。还有默认的项目可见性,建议设为“私有”,避免误操作把内部代码暴露出去。
注意:GitLab 13.1.2 的默认 root 密码是随机生成的,存在
/etc/gitlab/initial_root_password文件里,但这个文件在 24 小时后会被自动删除。如果你在 24 小时内没有设置密码,就要用gitlab-rails console手动重置了。
4. 安装后的验证与日常运维要点
4.1 功能验证:仓库、SSH 与 CI 的连通性
装完不代表能用,得实际验证一遍。我通常会做三个测试。
第一个测试,创建一个测试项目,然后尝试用 HTTP 方式克隆。在 GitLab 界面上新建一个项目,然后在本机执行git clone http://gitlab/root/test-project.git。如果提示输入用户名密码,输入 root 和密码,能克隆下来就说明 HTTP 访问正常。
第二个测试,SSH 方式。这个更容易出问题。首先确认你本机有 SSH key,没有的话用ssh-keygen -t rsa -b 4096生成。然后把公钥内容复制到 GitLab 的“设置 - SSH Keys”里。接着测试ssh -T git@gitlab,如果返回Welcome to GitLab, @root!就说明 SSH 通了。如果卡住或者报错,常见原因是 22 端口被占用或者防火墙没放行。GitLab 默认会用系统的 SSH 服务,如果你系统 SSH 端口不是 22,或者你想让 GitLab 用单独的端口,就需要改gitlab.rb里的gitlab_rails['gitlab_shell_ssh_port']和gitlab_shell['sshd_port']。
第三个测试,CI 功能。GitLab 13.1.2 自带 Runner 注册功能,但 Runner 需要单独安装。你可以在项目里创建一个.gitlab-ci.yml文件,内容写个最简单的:
test: script: - echo "hello gitlab ci"然后去“设置 - CI/CD - Runner”里看看有没有可用的 Runner。如果没有,就需要在另一台机器上装 gitlab-runner 并注册。CI 这块展开讲能写一整篇,这里先不深入,你只需要知道装完 GitLab 后 CI 不是自动就能用的。
4.2 备份、恢复与升级的实操建议
备份是运维的生命线,GitLab 的备份命令是gitlab-backup create。注意,13.1.2 这个版本用的是gitlab-backup,而不是老版本的gitlab-rake gitlab:backup:create。执行后会生成一个 tar 包,里面包含数据库、仓库、上传文件等。但有两个东西不在备份包里:/etc/gitlab/gitlab.rb和/etc/gitlab/gitlab-secrets.json。这两个文件必须手动备份,否则恢复后用户密码、CI token 这些都会失效。
恢复的命令是gitlab-backup restore BACKUP=备份文件名。恢复前要先停掉相关服务:gitlab-ctl stop unicorn和gitlab-ctl stop sidekiq。恢复完成后重新 reconfigure 并启动。这里有个坑:备份文件和 GitLab 版本必须严格对应,13.1.2 的备份不能直接恢复到 13.2 上,必须先恢复到同版本,再逐步升级。
说到升级,GitLab 的升级路径是有讲究的。不能跨大版本直接升,比如从 13.1 直接升到 14.x 是不行的。官方推荐的是按照升级路径逐步来:13.1 -> 13.12 -> 14.0 -> 14.3 这样。每次升级前都要备份,升级后要验证。升级命令就是yum install gitlab-ce-新版本号,然后gitlab-ctl reconfigure。但升级过程中数据库迁移可能耗时较长,要做好心理准备。
4.3 性能监控与日志排查的常用手段
GitLab 跑起来后,日常监控主要看几个东西。第一,内存和 CPU,用free -h和top就能看。如果发现内存持续吃紧,就要考虑调低 worker 数量或者加内存。第二,磁盘空间,df -h看/var/opt/gitlab这个分区,GitLab 的仓库和日志都在这下面。第三,服务状态,gitlab-ctl status和gitlab-ctl tail是最常用的。gitlab-ctl tail可以实时滚动所有服务的日志,排查问题时非常方便。
日志文件的具体位置:GitLab 主日志在/var/log/gitlab/gitlab-rails/production.log,Nginx 日志在/var/log/gitlab/nginx/,PostgreSQL 日志在/var/log/gitlab/postgresql/。如果你遇到 502 错误,通常是 unicorn 没起来或者超时,去看production.log和unicorn/current日志。如果是仓库推送失败,去看gitlab-shell/gitlab-shell.log。
还有一个实用的命令是gitlab-ctl tail nginx,可以只看 Nginx 的日志。另外,gitlab-rails console可以进入 Rails 控制台,用来查用户、改配置、重置密码等。比如重置 root 密码:
user = User.where(id: 1).first user.password = 'new_password' user.password_confirmation = 'new_password' user.save!这个控制台加载比较慢,要等十几秒,但功能很强大,建议运维同学掌握。
5. 常见问题与排查技巧实录
5.1 安装与启动阶段的典型报错
问题一:gitlab-ctl reconfigure卡在ruby_block[wait for logrotate service socket]或者类似的地方。这个通常是因为系统资源不足,或者某个服务启动超时。先检查内存,如果内存不足 4G,基本都会卡。解决办法是加 Swap,或者调低 unicorn worker 数量。另外,/etc/hosts里没有配主机名解析也会导致卡住,确认一下127.0.0.1 gitlab这行有没有。
问题二:访问页面显示 502。这是最常见的报错。502 意味着 Nginx 能通,但后端的 unicorn 没响应。排查步骤:先gitlab-ctl status看 unicorn 是不是 down。如果是 down,去看/var/log/gitlab/unicorn/current日志。常见原因是端口冲突(比如 8080 被占用)或者内存不足导致 worker 启动失败。还有一个可能是external_url配错了,比如配了个无法解析的域名。
问题三:SSH 克隆提示Permission denied (publickey)。先确认公钥有没有正确添加到 GitLab。然后确认 SSH 命令用的端口对不对,GitLab 默认用 22,如果你系统 SSH 改了端口,就要用ssh -T git@gitlab -p 你的端口。还有一个隐蔽的原因:/etc/ssh/sshd_config里的AllowUsers或者DenyUsers限制了 git 用户登录。GitLab 会创建一个git系统用户,如果 SSH 配置里限制了这个用户,就会连不上。
问题四:邮件发不出去。先看production.log里有没有Net::SMTPAuthenticationError之类的报错。常见原因是密码错、端口错、或者 TLS 配置不对。有些邮件服务商要求发件人地址必须和认证用户一致,所以gitlab_email_from要和smtp_user_name保持一致。另外,如果服务器在内网,可能无法访问外部的 SMTP 服务器,需要确认网络策略。
5.2 运行阶段的性能与稳定性问题
问题一:GitLab 用一段时间后越来越慢。这通常是磁盘 I/O 或者内存问题。先看df -h确认磁盘没满,然后看free -h确认内存没被耗尽。如果内存不足,系统会频繁使用 Swap,导致响应变慢。解决办法是加内存或者调低unicorn['worker_processes']和sidekiq['concurrency']。另外,PostgreSQL 的shared_buffers如果设得太小,查询会变慢,可以适当调大。
问题二:仓库推送大文件时失败。GitLab 默认对单个文件大小有限制,Nginx 的client_max_body_size默认是 250M,GitLab 应用层也有max_attachment_size等限制。如果要推大文件,需要同时改 Nginx 和 GitLab 的配置。在gitlab.rb里加:
nginx['client_max_body_size'] = '1024m' gitlab_rails['max_attachment_size'] = 1024然后 reconfigure。但要注意,大文件推送对内存和磁盘压力都很大,如果不是必须,建议用 Git LFS。
问题三:备份失败或者备份文件损坏。备份失败常见原因是磁盘空间不足,备份文件会先写到临时目录再移动到目标目录,如果临时目录空间不够就会失败。另外,备份过程中如果有大量写入操作,可能导致备份不一致。建议在低峰期做备份,并且备份前先停掉 sidekiq。恢复时如果报tar: Unexpected EOF,说明备份文件不完整,只能重新备份。
5.3 独家避坑清单与快速排查表
下面这张表是我自己踩坑后整理的,遇到问题可以先按表排查:
| 现象 | 可能原因 | 排查命令 | 解决方向 |
|---|---|---|---|
| 502 错误 | unicorn 未启动 | gitlab-ctl status unicorn | 查 unicorn 日志,调内存 |
| 页面加载慢 | 内存不足/Swap 频繁 | free -h、vmstat 1 | 加内存或调低 worker |
| SSH 克隆失败 | 端口/公钥/用户限制 | ssh -T git@host -p 端口 | 检查 sshd_config 和公钥 |
| 邮件不发送 | SMTP 配置错误 | gitlab-ctl tail | 核对端口、TLS、发件人 |
| reconfigure 卡住 | 资源不足/主机名解析 | free -h、cat /etc/hosts | 加 Swap、配 hosts |
| 备份失败 | 磁盘空间不足 | df -h | 清理空间或改备份路径 |
| 仓库推送超限 | Nginx/应用层限制 | 看 Nginx error log | 调大 body size 限制 |
几个额外的避坑点。第一,别在 GitLab 服务器上跑其他吃内存的服务,比如 MySQL、Redis 独立实例,GitLab 自带的已经够用了。第二,/var/opt/gitlab这个目录会越来越大,定期清理旧的 CI 产物和日志,可以在gitlab.rb里设置gitlab_rails['ci_artifacts_expire_in']之类的参数。第三,如果你改了external_url的协议从 http 到 https,一定要重新 reconfigure,并且确认证书路径正确,否则 Nginx 起不来。
还有一个很隐蔽的坑:CentOS 7 的默认文件句柄数限制比较低,GitLab 在高并发时可能报Too many open files。解决办法是修改/etc/security/limits.conf,加上:
* soft nofile 65535 * hard nofile 65535然后重启服务器,或者用ulimit -n 65535临时生效。这个改动对 GitLab 的稳定性提升很明显,尤其是团队人数多、仓库多的时候。
最后说一个我自己的体会:GitLab 的 Omnibus 包虽然方便,但它把很多东西都封装起来了,出问题时排查起来需要你对它的内部结构有一定了解。建议花点时间看看/opt/gitlab目录下的结构,了解各个组件的位置。另外,gitlab-ctl这个命令非常强大,gitlab-ctl --help值得仔细看一遍,里面有很多实用的子命令,比如gitlab-ctl restart、gitlab-ctl stop、gitlab-ctl tail、gitlab-ctl reconfigure,掌握这些基本就能应对大部分日常运维场景了。