需求
公司需要自己搭建gitlab服务器,决定使用免费的社区版,最简单的方式是通过docker部署,在服务器找一个文件夹,新建docker-compose.yml
#version: "3.9"
services:
gitlab:
image: gitlab/gitlab-ce
container_name: gitlab
user: root
restart: always
ports:
- "33333:80" # 将容器内部的80端口映射到宿主机的33333端口,同时容器内改用80端口
volumes:
- "./config:/etc/gitlab"
- "./logs:/var/log/gitlab"
- "./data:/var/opt/gitlab"
logging:
driver: journald
shm_size: 256m
我这里是需要将33333端口进行映射,这是个大坑
坑1
首先需要联系运维,看这个33333端口开放有没有限制,我就是因为这个没给开放,导致本地localhost:33333能访问,外网访问ip:33333报502
坑2
gitlab在服务器上下载不下来,这个可能和服务器的网络有关,不能访问国外网络,可以在一台能部署docker的电脑上打包好,把文件传到服务器上,我就是在一台windows电脑上,通过dockerDesktop打包的
docker pull gitlab/gitlab-ce:latest
docker save -o gitlab_gitlab-ce.tar gitlab/gitlab-ce:latest
将 gitlab_gitlab-ce.tar 文件通过 U 盘、SCP 等方式复制到您的 CentOS 服务器上
在您的 CentOS 服务器上:
sudo docker load -i gitlab_gitlab-ce.tar
加载成功后,再次运行 sudo docker compose up。
坑3如果启动后遇到502错误
如果容器启动但访问时出现502错误,通常是资源不足或初始化未完成:
# 查看容器资源使用情况
sudo docker stats gitlab
# 查看详细日志
sudo docker compose logs gitlab
# 进入容器检查状态
sudo docker exec -it gitlab gitlab-ctl status
GitLab 官方建议至少 4GB 内存。
GitLab 首次启动确实需要较长时间(可能几分钟到十几分钟,取决于硬件)进行初始化数据库和配置。如果日志在滚动输出但没有明显的错误信息,并且 gitlab-ctl status 显示服务在陆续启动,建议你耐心等待一段时间再观察。
坑4 Puma 一直重启,导致502
如果打印出的输出是这样的
[ChipletRing_web@centos7_100 gitlab]$ sudo docker exec -it gitlab /bin/bash
root@221:/# gitlab-ctl status | grep -E "(puma|sidekiq|unicorn|nginx)"
run: nginx: (pid 660) 605s; run: log: (pid 712) 602s
run: puma: (pid 1914) 19s; run: log: (pid 572) 622s
run: sidekiq: (pid 577) 617s; run: log: (pid 598) 614s
root@221:/#
Puma 进程 (pid 1914) 的运行时间只有 19 秒,而 Nginx 和 Sidekiq 都已经运行了超过 10 分钟。这表明 Puma(GitLab 的核心应用服务器)在不断崩溃和重启,这就是导致 502 错误的根本原因!
Puma 频繁崩溃通常由以下几个原因导致,请按顺序排查:
- 内存不足(最常见!)
GitLab 对内存要求很高,最少需要 4GB 的可用内存。如果内存不足,Puma 进程会被系统终止。
检查内存情况:
# 在宿主机上执行
free -h
# 在容器内查看最近是否有进程被OOM Killer杀死
grep -i 'killed process' /var/log/syslog | tail -5
解决方案:
如果内存不足,请增加服务器内存。
或者为系统创建 Swap 交换分区(临时解决方案):
# 在宿主机上操作
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
- 端口冲突
Puma 可能在使用默认端口并与其它服务冲突。
检查并修改 Puma 端口:
# 编辑 GitLab 配置文件
vi /etc/gitlab/gitlab.rb
# 添加或修改以下行,选择一个未占用的端口
puma['port'] = 8083
# 保存后重新配置 GitLab
gitlab-ctl reconfigure
gitlab-ctl restart puma
- 数据库连接或初始化问题
GitLab 启动时需要连接 PostgreSQL 数据库,如果数据库尚未完成初始化或连接失败,Puma 会启动失败。
检查数据库状态和日志:
# 检查数据库状态
gitlab-ctl status postgresql
# 查看数据库日志
tail -f /var/log/gitlab/postgresql/current
# 尝试初始化数据库(如果尚未完成)
gitlab-ctl reconfigure
- 文件权限问题
确保 GitLab 相关目录的权限正确。
修复权限:
gitlab-ctl reconfigure
gitlab-ctl restart
我这边是端口冲突了,刚开始设置的是8080端口,与nginx冲突,如果日志打出来是这样的
[ChipletRing_web@centos7_100 gitlab]$ sudo docker exec gitlab gitlab-ctl status
run: alertmanager: (pid 1676) 148s; run: log: (pid 1465) 178s
run: gitaly: (pid 298) 241s; run: log: (pid 356) 240s
run: gitlab-exporter: (pid 1607) 150s; run: log: (pid 731) 198s
run: gitlab-kas: (pid 516) 229s; run: log: (pid 564) 228s
run: gitlab-workhorse: (pid 1583) 151s; run: log: (pid 626) 210s
run: logrotate: (pid 267) 254s; run: log: (pid 276) 250s
run: nginx: (pid 664) 205s; run: log: (pid 711) 204s
run: postgres-exporter: (pid 1700) 148s; run: log: (pid 1485) 174s
run: postgresql: (pid 363) 235s; run: log: (pid 373) 234s
run: prometheus: (pid 1617) 149s; run: log: (pid 1251) 186s
run: puma: (pid 568) 223s; run: log: (pid 575) 222s
run: redis: (pid 280) 247s; run: log: (pid 290) 246s
run: redis-exporter: (pid 1609) 150s; run: log: (pid 751) 190s
run: sidekiq: (pid 580) 217s; run: log: (pid 591) 216s
run: sshd: (pid 43) 264s; run: log: (pid 42) 264s
[ChipletRing_web@centos7_100 gitlab]$
就说明启动成功了
常用命令
部署gitlab的时候,常用命令如下
在能连外网的电脑上运行
# 1. 拉取镜像
docker pull gitlab/gitlab-ce:latest
# 2. 查看镜像ID(确认拉取成功)
docker images
# 3. 将镜像保存为tar文件
docker save -o gitlab_gitlab-ce.tar gitlab/gitlab-ce:latest
# 4. 检查文件大小(GitLab镜像很大,约1.5-2GB)
ls -lh gitlab_gitlab-ce.tar
在服务器运行:
# 进入您的gitlab目录
cd /path/to/gitlab
# 加载镜像(这个过程需要一些时间)
sudo docker load -i gitlab_gitlab-ce.tar
# 验证镜像是否加载成功
sudo docker images | grep gitlab-ce
# 2. 启动GitLab(现在应该可以成功了)
sudo docker compose up -d
# 1. 实时跟踪Nginx的错误日志(重点关注错误信息)
sudo docker exec gitlab tail -f /var/log/gitlab/nginx/gitlab_error.log
# 2. 实时跟踪Puma(应用服务器)的日志
sudo docker exec gitlab tail -f /var/log/gitlab/puma/puma_stdout.log
sudo docker exec gitlab tail -f /var/log/gitlab/puma/puma_stderr.log
# 3. 实时跟踪GitLab Rails应用的日志
sudo docker exec gitlab tail -f /var/log/gitlab/gitlab-rails/production.log
# 4. 也可以使用gitlab-ctl tail命令综合查看:cite[3]:cite[6]
sudo docker exec gitlab gitlab-ctl tail
sudo docker exec -it gitlab vi /etc/gitlab/gitlab.rb
# 为 Puma 指定一个不同的端口(例如 8082)
puma['port'] = 8082
# 确保 Nginx 配置正确(保持你之前的设置)
nginx['listen_port'] = 8081
external_url 'http://xxxxxxxx:33333'
# 重新配置 GitLab
sudo docker exec gitlab gitlab-ctl reconfigure
# 重启 GitLab 服务
sudo docker exec gitlab gitlab-ctl restart
# 查看 GitLab 服务状态
sudo docker exec gitlab gitlab-ctl status
这个是我用到的编辑过的部分
external_url 'http://221.226.159.58:33333'
nginx['listen_addresses'] = ['0.0.0.0'] # 确保监听所有端口
nginx['listen_port'] = 80 # 明确指定容器内监听接口,通常80
puma['listen'] = '127.0.0.1' # Puma 默认监听 127.0.0.1
puma['port'] = 8081 # puma默认监听接口,防止端口冲突
#明确告知Gitlab nginx如何连接到puma
gitlab_rails['internal_api_url'] = "http://127.0.0.1:8081"
gitlab_workhorse['auth_backend'] = "http://127.0.0.1:8081"
# gitlab_backup_cli['additional_groups'] = %w[git gitlab-psql registry]
docker端口映射
version: '3'
services:
web-app-1:
image: nginx
ports:
- "8080:80" # 服务1使用宿主机8080端口
web-app-2:
image: nginx
ports:
- "8081:80" # 服务2使用宿主机8081端口
web-app-3:
image: nginx
ports:
- "8082:80" # 服务3使用宿主机8082端口
对于这段代码映射的解释:
核心概念:两个不同的“世界”
有两个独立的网络环境:
宿主机 (Host) 世界:你的 Ubuntu 物理机或虚拟机。它有自己的 IP 地址(如 192.168.1.100)和一套端口(80, 8080, 22, 443 等)。
容器 (Container) 世界:每个 Docker 容器都是一个隔离的、迷你版的 Linux 系统。它也有自己独立的内部 IP 地址(由 Docker 分配,如 172.18.0.2)和一套完全独立的端口。
为什么不会冲突?
关键在于:冲突只发生在“宿主机世界”的端口上。
宿主机端口是唯一的:
8080, 8081, 8082 是宿主机上三个完全不同的端口。
Docker 会让宿主机同时监听这三个端口,它们之间不会冲突。
这就好比一家公司有三个不同的总机电话号码。
容器端口是独立的:
每个容器内部的 80 端口都只属于它自己所在的“迷你系统”。
web-app-1 在自己的小世界里监听 80 端口。
web-app-2 也在自己的小世界里监听 80 端口。
它们互相看不见对方,也完全不知道对方的存在,所以根本不会冲突。
这就好比公司里的每个部门都有自己的内部分机号 80,但因为他们处于不同的分机系统,所以号码可以重复。
访问流程
根据上面的配置,访问流程是这样的:
当你在浏览器访问 http://你的宿主机IP:8080时:
流量到达宿主机的 8080 端口。
Docker 接收到流量,说:“哦,8080 端口映射给了 web-app-1”。
Docker 将流量转发到 web-app-1 容器的 80 端口。
Nginx 在容器内接收到流量并处理。
当访问 http://你的宿主机IP:8081时:
同样流程,但 Docker 会将流量转发到 web-app-2 容器的 80 端口。
用一个比喻来理解
想象一栋大楼(宿主机)里有三个独立的套房(容器):
套房A (web-app-1):大楼地址是 大厦8080号,套房内的房间号是 80。
套房B (web-app-2):大楼地址是 大厦8081号,套房内的房间号是 80。
套房C (web-app-3):大楼地址是 大厦8082号,套房内的房间号是 80。
快递员(网络请求)需要先找到正确的大楼地址(宿主机IP:宿主机端口),比如找到“大厦8080号”,然后把包裹送给这个地址下的“80号房间”(容器端口)。
每个套房都有自己的“80号房间”,但因为大楼地址不同,所以快递员永远不会送错。