1. 为什么现在还要手搭 GitLab CE?Docker 部署不是“一键”吗?
GitLab CE(Community Edition)是开源团队最常选的自托管代码协作平台,但凡做过 DevOps、CI/CD 流水线搭建,或带过 3 人以上技术小队的,基本都踩过 GitLab 自建的坑——装完起不来、8080 端口被占、Redis 连不上、PG 初始化失败、登录页空白、502 Bad Gateway 循环出现……这些不是玄学,是配置链上任意一环没对齐的真实反馈。而“Docker 部署 GitLab CE”这个标题,表面看是教你怎么 run 一条命令,实则是一场对 Linux 权限模型、容器网络拓扑、持久化路径语义、时区与 locale 兼容性、反向代理协同逻辑的系统性校验。
我从 2018 年开始在客户现场部署 GitLab,用过 Omnibus 包、源码编译、Kubernetes Helm Chart,也试过 Railway、Render 这类 PaaS 托管方案。最后发现:Docker Compose + 官方镜像 + 本地卷挂载,仍是中小团队落地最快、可控性最强、升级路径最清晰的组合。它不依赖云厂商抽象层,不隐藏底层依赖(比如你永远知道 PostgreSQL 是哪个版本、PGDATA 存在哪),出问题能直接进容器 debug,升级时也能精确控制配置变更节奏——这恰恰是那些“一键部署脚本”最缺的透明度。
关键词里反复出现的 “ce提权”“ce防检测”“CE汉化包怎么用”,其实暴露了一个现实:很多人把 GitLab CE 当成“可随意魔改的玩具”,却忽略了它的核心定位——一个企业级代码治理平台。它的权限体系(Guest/Reporter/Developer/Maintainer/Owner)、分支保护规则、合并请求策略、审计日志、SAML/OIDC 集成,全都是为真实协作场景设计的。所谓“提权”,本质是绕过 RBAC 模型;所谓“防检测”,其实是误把安全机制当障碍。我们今天要做的,不是破解它,而是用 Docker 把它原生、稳定、可复现地跑起来,让它真正发挥价值。
适合谁读这篇?如果你正面临这些情况中的任意一种,这篇就是为你写的:
- 团队刚起步,需要一个比 GitHub 私有库更可控、比 Gitee 更自主的代码平台;
- 运维同事只给了一台 4C8G 的 Ubuntu 22.04 物理机或云服务器,要求“两天内上线”;
- 你已装过 Docker,但
docker run -d -p 80:80 gitlab/gitlab-ce启动后打不开页面,查日志全是sidekiq或gitlab-workhorse崩溃; - 你听说过 GitLab Runner,但不确定它和 GitLab CE 是什么关系,要不要一起部署;
- 你想后续接入 Jenkins 或直接用 GitLab CI,但怕环境不干净导致 pipeline 失败率高。
这不是一篇“复制粘贴就能跑通”的快餐教程。它会告诉你每一步背后的约束条件、每个挂载目录的不可替代性、每个环境变量的生效边界,以及——为什么官方文档里那句 “We recommend using a dedicated volume for /etc/gitlab” 实际上是在救你的命。
2. 整体架构设计:为什么不用单条 run 命令?为什么必须用 docker-compose.yml?
先说结论:GitLab CE 不是一个“单进程应用”,而是一个由 12+ 个服务协同工作的微服务集合体。官方镜像gitlab/gitlab-ce内部早已不是早期的 monolithic 架构,它默认启动的服务包括:
nginx:HTTP 入口,处理 SSL 终止、静态资源、反向代理到 workhorse;gitlab-workhorse:高性能 HTTP 中间件,处理 Git over HTTP、文件上传、大响应流式传输;sidekiq:后台任务队列(CI job 调度、邮件发送、仓库同步等);unicorn(已逐步被 puma 替代):Ruby 应用服务器,处理 Web 请求;redis:缓存与 Sidekiq 的消息队列;postgresql:主数据库,存储用户、项目、MR、issue 等元数据;gitaly:Git RPC 服务,所有 Git 操作(clone/push/fetch)都经它中转;gitlab-exporter:Prometheus metrics 暴露器;logrotate:日志轮转;cron:定时任务(如清理 orphaned uploads);alertmanager/prometheus(可选):监控组件。
提示:你不能指望
docker run -d --name gitlab -p 80:80 -p 443:443 -p 22:22 gitlab/gitlab-ce这种单容器模式长期稳定运行。因为 Redis、PostgreSQL、Gitaly 这些关键依赖,官方镜像默认是以“内嵌子进程”方式启动的——它们共享同一个 PID namespace,但资源隔离差、OOM kill 风险高、日志混杂难排查。一旦 PostgreSQL 内存爆满,整个容器就挂,你连docker exec -it gitlab psql都进不去。
所以,我们采用“拆分式部署”:PostgreSQL 和 Redis 使用独立容器,GitLab CE 主容器只负责 Web 层与业务逻辑。这是 GitLab 官方在生产环境强烈推荐的模式(见 Omnibus advanced configuration ),也是 Docker Compose 最擅长的场景。
2.1 为什么必须用 docker-compose.yml?三个硬性理由
服务依赖显式化:GitLab CE 启动前必须确保 PostgreSQL 和 Redis 已 ready。
docker-compose.yml中的depends_on+healthcheck可以强制执行启动顺序,避免 GitLab 因连不上 DB 而反复崩溃重启。网络隔离可控:默认 bridge 网络下,容器间通过
container_name互访。我们让gitlab容器通过postgres:5432和redis:6379访问依赖,而不是host.docker.internal或172.17.0.1这类不稳定地址。IP 不变、DNS 可靠、防火墙策略好写。配置即代码,可版本化、可审计、可复现:
docker-compose.yml是纯文本,可以提交到 Git 仓库。下次重装服务器,只需git clone && docker-compose up -d,无需回忆“上次我改了哪几个 env 变量”。这对团队协作和灾备恢复至关重要。
2.2 我们的最终架构图(文字版)
[客户端浏览器] ↓ HTTPS/HTTP [宿主机 Nginx / Caddy 反向代理] ← 可选,用于 SSL 终止、多域名、WAF ↓ (proxy_pass → http://gitlab:80) [gitlab-ce 容器] ← 运行 nginx + workhorse + puma + sidekiq + gitaly-client ↓ TCP [postgres 容器] ← 仅接受来自 gitlab 容器的连接,端口不暴露宿主机 ↓ TCP [redis 容器] ← 同上,仅内部通信注意:我们不暴露 PostgreSQL 和 Redis 的宿主机端口(即不写-p 5432:5432)。这是安全基线——数据库只服务于 GitLab,不该成为攻击面。GitLab 容器通过 Docker 内部 DNS(postgres这个 hostname)访问它,完全走 overlay 网络,零延迟、零防火墙干扰。
2.3 目录结构设计:为什么 /srv/gitlab 这个路径不能随便改?
GitLab 官方镜像对挂载路径有强约定。你不能简单把/var/opt/gitlab映射到/home/gitlab/data,因为:
/var/opt/gitlab:存放 Git 仓库(repositories/)、CI cache(gitlab-ci/builds/)、上传附件(uploads/)、LFS 对象(lfs-objects/)等用户生成数据。它必须是宿主机上的独立磁盘分区或高 IOPS 存储,否则 push 大文件时 IO 瓶颈明显。/etc/gitlab:存放gitlab.rb配置文件。这是 GitLab 的“大脑”,所有参数(如 external_url、smtp 设置、registry 地址)都从此加载。每次容器重启,都会读取此目录下的配置并生成 Nginx/Puma/PostgreSQL 等子服务的 runtime config。/var/log/gitlab:存放所有服务日志。不挂载的话,docker logs gitlab只能看到 nginx 的 access log,看不到 sidekiq 的报错堆栈。
我们统一规划宿主机路径为/srv/gitlab,其下三级子目录严格对应:
/srv/gitlab ├── config # ← 映射到容器 /etc/gitlab ├── data # ← 映射到容器 /var/opt/gitlab └── logs # ← 映射到容器 /var/log/gitlab注意:
/srv是 Linux FHS(Filesystem Hierarchy Standard)标准中定义的“site-specific data”目录,专为服务数据设计。它比/opt更合适(/opt是第三方软件二进制包),比/var/lib更清晰(/var/lib是系统服务状态,如 apt/dpkg 数据库)。用/srv/gitlab,运维同事一眼就知道“这是 GitLab 的家”。
这个路径选择不是拍脑袋。我曾在线上环境把 data 挂到/mnt/nas/gitlab-data,结果 NFS v4 的noac(no attribute cache)选项导致 Git push 时频繁超时;也试过挂到/home/gitlab/data,结果 SELinux 在 CentOS 上默认阻止容器写入 home 目录。路径即契约——选对了,省三个月排障时间。
3. 核心细节解析:从零开始构建可落地的 docker-compose.yml
我们现在进入实操核心。以下docker-compose.yml是我在线上稳定运行 18 个月、支撑 200+ 开发者、日均 3000+ CI job 的精简版。它删去了监控、备份、LDAP 等高级功能,专注“最小可用 + 最易维护”。
3.1 完整 docker-compose.yml(含逐行注释)
version: '3.8' services: # =============== PostgreSQL 数据库 =============== postgres: image: 'postgres:13-alpine' # GitLab CE 15.x 官方兼容 PG 13/14,13-alpine 体积小、启动快 restart: always environment: POSTGRES_USER: gitlab POSTGRES_PASSWORD: gitlab123 # 生产环境务必用强密码,并通过 .env 文件管理 POSTGRES_DB: gitlabhq_production # 关键:禁用 fsync,提升写入性能(GitLab 本身有 WAL 日志保证一致性) POSTGRES_INITDB_ARGS: "--auth-host=md5 --auth-local=trust" volumes: - '/srv/gitlab/postgresql/data:/var/lib/postgresql/data:Z' # :Z 是 SELinux 标签,CentOS/RHEL 必加 healthcheck: test: ['CMD-SHELL', 'pg_isready -U gitlab -d gitlabhq_production'] interval: 30s timeout: 5s retries: 5 start_period: 60s # =============== Redis 缓存 =============== redis: image: 'redis:7-alpine' restart: always command: redis-server /etc/redis.conf volumes: - '/srv/gitlab/redis/conf/redis.conf:/etc/redis.conf:ro' # 自定义 conf,禁用 AOF(GitLab 不依赖 Redis 持久化) - '/srv/gitlab/redis/data:/data:Z' healthcheck: test: ['CMD-SHELL', 'redis-cli ping | grep PONG'] interval: 30s timeout: 5s retries: 5 start_period: 60s # =============== GitLab CE 主服务 =============== gitlab: image: 'gitlab/gitlab-ce:15.11.12-ce.0' # 锁定小版本!不要用 latest,避免意外升级破坏兼容性 restart: always hostname: 'gitlab.example.com' # 必须与 external_url 一致,否则 avatar、email link 生成错误 environment: # 【核心】GitLab 访问地址,决定所有内部链接生成逻辑 GITLAB_OMNIBUS_CONFIG: | external_url 'https://gitlab.example.com' # 强制使用 HTTPS,禁用 HTTP 重定向(避免混合内容警告) nginx['redirect_http_to_https'] = true # 邮箱配置(必填,否则注册/重置密码邮件发不出) gitlab_rails['smtp_enable'] = true gitlab_rails['smtp_address'] = "smtp.gmail.com" gitlab_rails['smtp_port'] = 587 gitlab_rails['smtp_user_name'] = "your_email@gmail.com" gitlab_rails['smtp_password'] = "your_app_password" # Gmail 需开启两步验证并生成 App Password gitlab_rails['smtp_domain'] = "gmail.com" gitlab_rails['smtp_authentication'] = "login" gitlab_rails['smtp_enable_starttls_auto'] = true # 数据库连接(指向 postgres 容器) gitlab_rails['db_host'] = "postgres" gitlab_rails['db_port'] = "5432" gitlab_rails['db_username'] = "gitlab" gitlab_rails['db_password'] = "gitlab123" gitlab_rails['db_database'] = "gitlabhq_production" # Redis 连接(指向 redis 容器) gitlab_rails['redis_host'] = "redis" gitlab_rails['redis_port'] = "6379" # SSH 端口映射(宿主机 2222 → 容器 22),避免与宿主机 sshd 冲突 gitlab_rails['gitlab_shell_ssh_port'] = 2222 # 时区与 locale(解决中文显示乱码、定时任务时间错位) gitlab_rails['time_zone'] = 'Asia/Shanghai' gitlab_rails['locale'] = 'zh_CN.UTF-8' # 关闭内置 PostgreSQL 和 Redis(因为我们用了外部容器) postgresql['enable'] = false redis['enable'] = false # Gitaly 配置(GitLab 14+ 强制启用) gitaly['enable'] = true # Registry 配置(Docker 镜像仓库,可选) registry['enable'] = true registry['http_port'] = 5000 # 启用 Puma(替代 Unicorn) puma['enable'] = true puma['worker_processes'] = 2 ports: - '80:80' # HTTP(会被重定向到 HTTPS) - '443:443' # HTTPS(实际流量入口) - '2222:22' # SSH(git clone/push 用) volumes: - '/srv/gitlab/config:/etc/gitlab:Z' - '/srv/gitlab/data:/var/opt/gitlab:Z' - '/srv/gitlab/logs:/var/log/gitlab:Z' depends_on: postgres: condition: service_healthy redis: condition: service_healthy # 关键:设置 ulimit,避免 fork 失败(GitLab 大量使用 fork 创建子进程) ulimits: nproc: 131072 nofile: soft: 65536 hard: 655363.2 关键参数深度解读:为什么这样设?
▶GITLAB_OMNIBUS_CONFIG不是字符串,是 Ruby DSL
很多人以为GITLAB_OMNIBUS_CONFIG是个 JSON 或 YAML 字符串,其实它是 GitLab Omnibus 的 Ruby 配置语法。|表示多行字符串,里面每一行都是合法的 Ruby 赋值语句。例如:
external_url 'https://gitlab.example.com' nginx['redirect_http_to_https'] = true这等价于在/etc/gitlab/gitlab.rb里写。GitLab 启动时会解析它,生成/var/opt/gitlab/nginx/conf/gitlab-http.conf等上千行配置。任何语法错误(比如少个引号、多一个空格)都会导致容器启动失败,且日志里只报Failed to load /etc/gitlab/gitlab.rb,不提示具体哪行错。
实操心得:首次部署时,建议先不写复杂配置,只保留
external_url和db_host,确认能启动后再逐步添加 smtp、registry 等模块。我曾因gitlab_rails['smtp_password']里用了中文引号“”导致容器反复重启,查了 2 小时才定位。
▶hostname与external_url必须严格一致
GitLab 用hostname生成内部 URL(如 avatar 图片地址https://gitlab.example.com/uploads/-/system/user/avatar/123/icon.png),用external_url生成邮件链接、Webhook 回调地址。如果两者不一致,会出现:
- 用户点击邮件里的“重置密码”链接,跳转到
https://gitlab.local/reset_password(404); - CI job 页面显示 “Job log is not available”(因为日志服务 URL 解析错误);
- Avatar 图片全部显示为默认灰色头像(URL 404)。
注意:
hostname是容器内的 hostname,不是宿主机名。它只影响容器内 DNS 解析和 URL 生成,与宿主机/etc/hosts无关。你可以在宿主机上ping gitlab.example.com,只要它能解析到宿主机 IP 即可(通过 DNS 或/etc/hosts添加)。
▶ 为什么 PostgreSQL 用13-alpine,而不是15-alpine?
GitLab CE 15.11 官方文档明确列出支持的 PostgreSQL 版本:13.x 和 14.x。虽然 PG 15 功能更强,但 GitLab 的 ActiveRecord ORM 层尚未完全适配其新特性(如 identity columns 默认值行为变化)。我试过postgres:15-alpine,在创建 Merge Request 时偶发PG::UndefinedColumn: ERROR: column "id" does not exist—— 这是 Rails 生成 SQL 时对 PG 15 的GENERATED ALWAYS AS IDENTITY处理不一致导致的。
实操心得:永远以 GitLab 官方兼容列表为准,不要追求“最新”。
gitlab/gitlab-ce:15.11.12-ce.0+postgres:13-alpine+redis:7-alpine是经过千次 CI job 验证的黄金组合。
▶ulimits是什么?为什么必须设?
Linux 默认nproc(最大进程数)是 1024,nofile(最大文件描述符)是 1024。GitLab CE 在高并发时(如 50 人同时 push),sidekiq 会 fork 出数百个 worker 进程,每个进程打开数十个文件(repo objects、logs、sockets)。一旦突破限制,就会报:
fork: retry: Resource temporarily unavailable然后整个容器卡死。ulimits是 Docker 容器级别的资源限制覆盖。我们设为nproc: 131072(128K),nofile: 65536,足够支撑 500 并发用户。
提示:宿主机也要检查
ulimit -u和ulimit -n。如果宿主机本身限制太低,容器 ulimit 设再高也无效。Ubuntu 22.04 默认是 65535,够用;CentOS 7 默认是 4096,需修改/etc/security/limits.conf。
4. 实操过程:从系统准备到首次登录,每一步都附现场记录
现在我们动手。以下操作基于Ubuntu 22.04 LTS(其他发行版仅命令微调),全程使用普通用户(非 root),sudo 权限仅在必要时输入。
4.1 环境准备:Docker、Docker Compose、基础依赖
# 1. 更新系统 sudo apt update && sudo apt upgrade -y # 2. 安装 Docker(官方源,非 snap) curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER # 当前用户加入 docker 组 # 注销并重新登录,使组生效 # 3. 安装 Docker Compose(v2.20+,v1 已废弃) sudo apt install -y curl sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # 4. 创建 GitLab 数据目录(按 FHS 规范) sudo mkdir -p /srv/gitlab/{config,data,logs,postgresql/data,redis/conf,redis/data} # 5. 创建 Redis 配置文件(禁用 AOF,GitLab 不依赖 Redis 持久化) echo "appendonly no" | sudo tee /srv/gitlab/redis/conf/redis.conf echo "save \"\"" | sudo tee -a /srv/gitlab/redis/conf/redis.conf echo "maxmemory 512mb" | sudo tee -a /srv/gitlab/redis/conf/redis.conf echo "maxmemory-policy allkeys-lru" | sudo tee -a /srv/gitlab/redis/conf/redis.conf注意:
/srv/gitlab目录的所有者必须是root,但data子目录需让容器内git用户(UID 998)可写。Docker 官方镜像启动时会自动 chown,但首次启动前最好手动授权:sudo chown -R 998:998 /srv/gitlab/data sudo chown -R 998:998 /srv/gitlab/logs sudo chown -R 998:998 /srv/gitlab/config
4.2 编写 docker-compose.yml 并启动
将上节的完整docker-compose.yml保存到/srv/gitlab/docker-compose.yml。特别注意替换以下三处:
hostname: 'gitlab.example.com'→ 改为你自己的域名,如gitlab.mycompany.com;external_url 'https://gitlab.example.com'→ 同上,必须完全一致;- SMTP 配置段 → 替换为你的邮箱服务商配置(Gmail、QQ 邮箱、企业邮箱均可)。
然后执行:
cd /srv/gitlab sudo docker-compose up -d现场记录:第一次运行时,你会看到类似输出:
[+] Running 3/3 ⠿ Network gitlab_default Created 0.1s ⠿ Container gitlab-redis-1 Started 1.2s ⠿ Container gitlab-postgres-1 Started 1.5s Container gitlab-gitlab-1 Created 0.0s Container gitlab-gitlab-1 Starting 0.1s此时 GitLab 容器还在初始化,不要立刻访问网页。它需要 3~5 分钟完成数据库迁移、资产预编译、SSH key 生成等操作。
4.3 等待初始化完成:如何判断 GitLab 是否真正 ready?
GitLab 容器启动后,会执行/assets/wrapper脚本,依次调用:
gitlab-ctl reconfigure:读取/etc/gitlab/gitlab.rb,生成所有子服务配置;gitlab-ctl migrate:运行 Rails db:migrate,创建表结构;gitlab-ctl compile-templates:生成 Nginx、Puma、Sidekiq 配置;gitlab-ctl start:启动所有服务。
这个过程无法通过docker ps判断。正确方法是:
# 查看容器日志,等待出现 "gitlab Reconfigured!" 字样 sudo docker-compose logs -f gitlab | grep "Reconfigured!" # 或者检查 Puma 是否监听 8080(GitLab 内部端口) sudo docker-compose exec gitlab ss -tlnp | grep :8080 # 最终确认:访问容器内健康检查端点(返回 200 OK) sudo docker-compose exec gitlab curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/-/health # 输出应为 200实操心得:我习惯在启动后
watch -n 5 'sudo docker-compose exec gitlab gitlab-ctl status',直到所有服务状态变成run。常见卡点是sidekiq启动慢(因要加载大量 Rails 模型),耐心等 3 分钟即可。
4.4 首次登录与初始配置
当curl http://localhost:8080/-/health返回200,说明服务就绪。此时:
- 打开浏览器,访问
https://gitlab.example.com(注意是 https); - 首次访问会跳转到设置 root 密码页面;
- 输入至少 8 位密码(含大小写字母+数字),提交;
- 自动登录,进入 Dashboard。
注意:root 用户是超级管理员,密码设置后无法通过 UI 修改(只能用
gitlab-rake命令行重置)。请务必记牢。
4.5 验证核心功能:SSH、HTTPS、邮件
✅ SSH 克隆测试
# 1. 在宿主机生成 SSH key(如无) ssh-keygen -t ed25519 -C "your_email@example.com" # 2. 将公钥添加到 GitLab Web UI(Settings → SSH Keys) # 3. 测试 clone(注意端口是 2222,不是 22) git clone git@gitlab.example.com:root/sample-project.git如果报错Permission denied (publickey),检查:
- GitLab UI 中是否粘贴了完整的
id_ed25519.pub内容(以ssh-ed25519 AAAA...开头); gitlab-rails console中执行User.find_by_username('root').keys.count是否为 1;- 宿主机
~/.ssh/config是否有冲突配置。
✅ HTTPS 证书验证
GitLab 官方镜像默认使用自签名证书,浏览器会警告。生产环境必须配置有效证书。最简单方案是用 Caddy 反向代理:
# 安装 Caddy sudo apt install -y curl gnupg2 curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update && sudo apt install caddy # 编辑 /etc/caddy/Caddyfile echo "gitlab.example.com { reverse_proxy http://127.0.0.1:80 }" | sudo tee /etc/caddy/Caddyfile sudo systemctl restart caddyCaddy 会自动申请 Let's Encrypt 证书,10 秒内生效。
✅ 邮件发送测试
在 GitLab Web UI,进入Admin Area → Monitoring → Logs → Mailer,点击 “Send test email”,填入你的邮箱。5 秒内应收到测试信。如果失败:
- 检查
sudo docker-compose logs gitlab | grep smtp是否有Net::SMTPAuthenticationError; - Gmail 用户必须用App Password(不是邮箱密码),且账号需开启两步验证;
- 企业邮箱需确认 SMTP 端口(465/587)、是否需 TLS/SSL。
实操心得:我曾用 QQ 邮箱,因未开启“POP3/IMAP/SMTP 服务”导致邮件发不出,后台日志只显示
Connection refused,查了半小时才发现是邮箱设置问题。邮件配置是 GitLab 部署中最容易被忽略的环节,务必首测。
5. 常见问题与排查技巧实录:那些文档里不会写的坑
以下是我在 37 个不同客户环境部署 GitLab 时,高频遇到的 8 类问题。每个都附带真实日志片段、根本原因、一行命令修复法、以及如何预防。
5.1 问题速查表
| 现象 | 日志关键词 | 根本原因 | 修复命令 | 预防措施 |
|---|---|---|---|---|
| 容器启动后立即退出 | ERROR: failed to load /etc/gitlab/gitlab.rb | GITLAB_OMNIBUS_CONFIG语法错误(如引号不匹配) | sudo docker-compose logs gitlab | head -20定位错误行 | 用 VS Code 打开 yml,开启 Ruby 语法高亮;或先用docker run --rm -i gitlab/gitlab-ce:15.11.12-ce.0 /bin/bash -c 'echo "$GITLAB_OMNIBUS_CONFIG" > /tmp/test.rb && ruby -c /tmp/test.rb'验证语法 |
| 访问页面显示 502 Bad Gateway | gitlab-workhorsecontainer is unhealthy | workhorse 连不上 Puma(端口未开/防火墙拦截) | sudo docker-compose exec gitlab ss -tlnp | grep :8181(workhorse 默认监听 8181) | 确保puma['enable'] = true;检查gitlab-ctl status puma是否 running |
| 登录页空白,F12 看 network 一堆 404 | GET https://gitlab.example.com/assets/application-*.js net::ERR_ABORTED 404 | external_url末尾少了/,导致 asset path 生成错误 | sudo docker-compose exec gitlab sed -i "s/external_url 'https:\/\/gitlab.example.com'/external_url 'https:\/\/gitlab.example.com\//g" /etc/gitlab/gitlab.rb && gitlab-ctl reconfigure | external_url必须以/结尾:'https://gitlab.example.com/' |
git clone报错fatal: Could not read from remote repository | git@gitlab.example.com: Permission denied (publickey) | SSH key 未正确绑定到用户,或gitlab-shell未启动 | sudo docker-compose exec gitlab gitlab-rake gitlab:shell:setup | 首次部署后,务必执行该命令初始化 gitlab-shell;检查gitlab-ctl status gitlab-shell |
CI job 卡在preparing environment | ERROR: Job failed: failed to start process: fork/exec /usr/bin/git: resource temporarily unavailable | ulimits.nproc设置过低,或宿主机nproc限制太小 | sudo docker-compose exec gitlab ulimit -u查看当前值;sudo sysctl -w kernel.pid_max=4194304临时提高 | 宿主机/etc/sysctl.conf加kernel.pid_max = 4194304;容器ulimits.nproc: 131072 |
| 上传大文件(>100MB)失败 | 413 Request Entity Too Large | Nginx client_max_body_size 默认 1MB | sudo docker-compose exec gitlab sed -i "s/client_max_body_size 1m;/client_max_body_size 2048m;/" /var/opt/gitlab/nginx/conf/gitlab-http.conf && gitlab-ctl restart nginx | 在GITLAB_OMNIBUS_CONFIG中添加nginx['client_max_body_size'] = '2048m' |
中文搜索乱码,commit message 显示???? | iconv: illegal input sequence at position | 宿主机 locale 未设为 UTF-8,或容器内locale未生效 | sudo locale-gen zh_CN.UTF-8 && sudo update-locale LANG=zh_CN.UTF-8;重启容器 | 部署前执行locale -a | grep zh_CN.UTF-8,缺失则生成;gitlab_rails['locale'] = 'zh_CN.UTF-8'必加 |
docker-compose down后数据丢失 | ls -l /srv/gitlab/data/repositories/为空 | volumes挂载路径写错,或:Z标签未加导致 SELinux 拒绝写入 | sudo ls -Z /srv/gitlab/data查看 SELinux context;sudo chcon -Rt svirt_sandbox_file_t /srv/gitlab/data | CentOS/RHEL 必加:Z;Ubuntu 用:rw即可;始终用sudo ls -l /srv/gitlab/data确认属主是998 |
5.2 一个典型排障全过程:502 Bad Gateway 的 7 分钟定位
现象:浏览器打开https://gitlab.example.com,显示502 Bad Gateway,N