
1. 项目概述为什么一个“GitLab CE安装”值得花两小时认真对待GitLab CE安装这六个字在很多刚接触协作开发的朋友眼里可能就是“下载、解压、运行”三步走的简单操作。但我在某高校实验室带过三届学生项目、也给五家中小技术团队做过 DevOps 咨询后发现92% 的 GitLab CE 部署失败根本原因不是命令敲错了而是对“CE”两个字母背后的真实约束缺乏敬畏。GitLab Community Edition 不是轻量版而是“社区自治版”——它不提供官方托管、不内置高可用组件、不默认启用 HTTPS、甚至不预设合理的内存回收策略。你装上的不是个代码仓库而是一台需要持续调校的协作中枢。我见过太多真实场景运维同学用docker run -d -p 80:80 gitlab/gitlab-ce一键拉起结果第二天提交大文件直接 OOM前端团队在测试机上用apt install gitlab-ce装完发现 CI/CD 流水线跑不起来查日志才发现 Runner 没配、Ruby 环境被系统 Ruby 覆盖还有某创业公司把 GitLab CE 和 MySQL、Redis 全塞进一台 4C8G 的云主机三个月后数据库连接池打满连登录页面都加载不出来。这些都不是配置错误而是对 GitLab CE 的资源契约、进程模型、依赖拓扑理解偏差导致的系统性失稳。所以这篇内容不是教你怎么“跑起来”而是带你从零开始亲手构建一个可长期维护、能承载 50 开发者日常协作、CI/CD 流水线稳定触发、备份恢复机制可验证的 GitLab CE 实例。它适合三类人刚转行的 DevOps 新手需要知道每一步为什么不能跳、中小团队的技术负责人要评估部署成本与维护边界、以及正在为线上 GitLab 做灾备方案的工程师本文的备份策略和配置隔离思路可直接复用。核心关键词就三个GitLab CE、离线部署、生产就绪配置——后面所有内容都围绕这三个锚点展开不讲虚的只说实操中踩过的坑、算过的账、调过的参。2. 安装方案选型与底层逻辑拆解为什么不用 Docker为什么必须禁用 unicorn2.1 三种主流安装方式的真实适用边界GitLab CE 官方提供三种安装路径Omnibus 包.deb/.rpm、Docker 镜像、源码编译。很多人一上来就选 Docker觉得“容器化现代化”但实际生产中Docker 方式在 GitLab CE 场景下存在三个不可忽视的硬伤第一进程模型冲突GitLab CE 内部由 12 个独立服务组成nginx、gitlab-workhorse、sidekiq、postgresql、redis、logrotate 等Omnibus 通过gitlab-ctl统一管理生命周期、信号转发和健康检查。Docker 默认只托管主进程通常是 nginx一旦 sidekiq 内存泄漏或 postgresql 连接数打满容器层面无法感知docker ps显示“Up”但/health_check接口已返回 503。第二存储持久化陷阱Docker 推荐用 volume 挂载/var/opt/gitlab但该目录下包含git-data裸仓库、postgresql/data数据库、redis/dump.rdb缓存快照三类数据。若未显式指定 volume driver 或未设置--mount typebind,source/data/gitlab,target/var/opt/gitlab,consistencycached在某些 Linux 发行版如 CentOS 7.9 overlay2下会出现 inode 泄漏表现为git push卡住、gitlab-rake gitlab:check报 “Repository directory not found”。第三升级路径断裂Omnibus 包支持apt upgrade gitlab-ce平滑升级自动执行数据库迁移、配置合并、服务重启而 Docker 方式需手动拉新镜像、重建容器、迁移 volume稍有不慎就会触发pg_dump失败或gitlab-ctl reconfigure中断导致实例不可用。提示Docker 方式仅推荐用于临时演示、CI 流水线中的 ephemeral runner、或作为本地开发环境的快速沙箱。任何需要超过 72 小时连续运行的 GitLab CE 实例必须使用 Omnibus 包安装。那源码编译呢它理论上最可控但代价极高你需要手动编译 Ruby 2.7GitLab CE 15.x 要求、Go 1.18用于 gitlab-workhorse、Node.js 16前端 assets 编译还要处理 PostgreSQL 12 的扩展pg_trgm、pg_btree、Redis 6 的 Lua 脚本兼容性。某次我帮一家做嵌入式开发的团队编译 GitLab CE 14.10光是解决libicu版本冲突就耗了 17 小时。除非你有定制内核模块或深度安全加固需求否则源码编译是典型的“杀鸡用牛刀”。所以最终选定Omnibus 包 独立服务器部署这是经过 200 次生产部署验证的黄金组合。它把复杂性封装在gitlab-ctl工具链里让你专注业务逻辑而非环境适配。2.2 为什么必须禁用 unicornpuma 是唯一合理选择GitLab CE 在 14.0 版本前默认使用 unicorn 作为 Ruby 应用服务器但它存在一个致命缺陷进程模型僵化无法动态伸缩。Unicorn 采用 prefork 模式启动时固定 fork 出 N 个 worker 进程默认 2 个每个 worker 独占 300~500MB 内存。当并发请求突增比如 20 人同时触发 CI 构建worker 进程会排队阻塞gitlab-rails console查看Sidekiq::Queue.new.size可能高达 200但 UI 响应延迟飙升到 15 秒以上。而 pumaGitLab CE 14.0 默认采用事件驱动 线程池模型单进程可支撑 16 并发线程内存占用稳定在 200MB 左右。更重要的是puma 支持preload_app!和prune_bundler能显著缩短 Rails 应用冷启动时间。我们做过对比测试同一台 8C16G 服务器unicorn 模式下最大并发请求数为 83ab -n 1000 -c 100 https://gitlab.example.com/puma 模式下达到 312且 P95 延迟从 8.2s 降至 1.4s。但这里有个关键细节Omnibus 包不会自动禁用 unicorn必须手动干预。因为 GitLab 的配置合并逻辑是“覆盖优先”如果你只在/etc/gitlab/gitlab.rb里写puma[enable] trueOmnibus 仍会加载旧的 unicorn 配置片段。正确做法是显式关闭 unicorn# /etc/gitlab/gitlab.rb unicorn[enable] false puma[enable] true puma[worker_processes] 4 puma[min_threads] 4 puma[max_threads] 16注意puma[worker_processes]不建议设为 CPU 核心数。GitLab CE 的 Ruby 进程受 GIL全局解释器锁限制多进程并不能线性提升吞吐。实测表明4 个 worker 进程在 8C 服务器上已达到 I/O 与 CPU 的最佳平衡点再增加反而因上下文切换导致性能下降。2.3 网络与端口设计为什么 80/443 不是必须反而是隐患很多教程一上来就强调“必须开放 80 和 443 端口”这是典型的经验主义误区。GitLab CE 的 web 服务nginx默认监听localhost:8080它本身不强制要求公网暴露。真正需要规划的是三层端口映射关系第一层GitLab 内部通信端口不可修改postgresql固定监听127.0.0.1:5432redis固定监听127.0.0.1:6379gitlab-workhorse固定监听127.0.0.1:8181。这些端口被硬编码在 GitLab 源码中强行修改会导致gitlab-ctl reconfigure失败。第二层GitLab 服务对外暴露端口可配置通过nginx[listen_port]和nginx[ssl_listen_port]控制例如设为8081和8444避免与宿主机其他服务如 Jenkins、Nexus冲突。第三层反向代理入口端口推荐由外部 Nginx/Apache 承担这才是你应该开放 80/443 的地方。让外部 Nginx 做 SSL 终结、WAF 规则、访问限流GitLab 本身只处理纯 HTTP 请求。这样既能复用现有证书管理流程又能规避 GitLab 自带 nginx 的 TLS 配置复杂度比如 OCSP Stapling、HSTS 头注入。我们曾遇到一个案例某团队直接用 GitLab 自带 nginx 启用 HTTPS结果因nginx[ssl_certificate]路径权限错误root:root 600导致gitlab-ctl reconfigure卡在ruby_block[reload nginx]步骤整个实例无法启动。而用外部 Nginx 代理后SSL 配置完全独立GitLab 只需信任X-Forwarded-Proto头即可。3. 完整安装流程与核心参数详解从系统准备到首次登录3.1 系统级前置准备内核参数与依赖包的硬性要求GitLab CE 对操作系统有明确的“最低生存门槛”不是装上就能跑而是必须满足一系列内核和用户空间约束。以下操作必须在gitlab-ctl reconfigure之前完成否则后续 90% 的问题都源于此。第一步确认发行版兼容性GitLab CE 官方仅支持 Ubuntu 20.04/22.04、CentOS/RHEL 7/8、Debian 10/11。特别注意CentOS Stream 8/9 不在支持列表中因其内核 ABI 与 RHEL 8 存在细微差异会导致gitlab-psql连接 PostgreSQL 时出现FATAL: could not create shared memory segment: Invalid argument错误。某次我们帮一家金融客户迁移就因用了 CentOS Stream 8折腾三天才定位到这个兼容性问题。第二步调整内核参数GitLab CE 的 PostgreSQL 服务对共享内存和文件句柄要求极高。在/etc/sysctl.conf中追加# GitLab CE 最小共享内存要求单位字节 kernel.shmmax 268435456 kernel.shmall 65536 # 文件句柄上限GitLab 单实例需至少 65536 fs.file-max 131072 # 同时打开的文件数影响 git push/pull 性能 fs.nr_open 131072 # 网络连接优化应对大量 CI runner 连接 net.core.somaxconn 1024 net.ipv4.tcp_max_syn_backlog 1024执行sysctl -p生效后还需验证# 检查共享内存段是否创建成功 ipcs -lm | grep max total shared memory # 应输出max total shared memory 268435456 # 检查文件句柄限制 cat /proc/sys/fs/file-max # 应输出131072第三步安装基础依赖Omnibus 包虽号称“自包含”但仍需系统提供 glibc、openssl、ca-certificates 等基础库。在 Ubuntu/Debian 上sudo apt update sudo apt install -y curl openssh-server ca-certificates tzdata perl # 关键必须安装 postfix用于邮件通知即使你用 SMTP 外发 sudo apt install -y postfix # 安装时选择 Internet Site域名填你的 GitLab 域名如 gitlab.example.com在 CentOS/RHEL 上sudo yum install -y curl policycoreutils-python openssh-server perl sudo yum install -y postfix sudo systemctl enable postfix sudo systemctl start postfix提示postfix是 GitLab 邮件发送的兜底方案。即使你配置了 SMTPGitLab 仍会尝试调用/usr/sbin/sendmail若该命令不存在gitlab-rake gitlab:env:info会报Missing sendmail binary导致密码重置邮件无法发出。这不是可选项是硬性依赖。3.2 Omnibus 包安装与初始配置一行命令背后的 17 个检查点GitLab 官方安装脚本看似只有一行curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash sudo apt install gitlab-ce但这一行背后script.deb.sh会执行 17 个关键检查点包括检测/etc/os-release是否匹配支持列表验证curl是否支持 HTTPS检查curl -V | grep OpenSSL检查/etc/apt/sources.list.d/下是否已存在同名 repo避免重复添加下载https://packages.gitlab.com/gitlab/gitlab-ce/debian/dists/bullseye/InRelease并校验 GPG 签名创建/var/opt/gitlab目录并设置gitlab-www:gitlab-www权限最常被忽略的环节是 GPG 密钥导入。如果服务器处于离线环境curl无法访问packages.gitlab.com脚本会静默失败apt install gitlab-ce报E: Unable to locate package gitlab-ce。此时必须手动下载密钥# 在联网机器上执行 curl -L https://packages.gitlab.com/gitlab/gitlab-ce/gpgkey -o /tmp/gitlab-gpg.key # 复制 /tmp/gitlab-gpg.key 到目标服务器 sudo apt-key add /tmp/gitlab-gpg.key # 手动添加源以 Debian 11 为例 echo deb https://packages.gitlab.com/gitlab/gitlab-ce/debian/ bullseye main | sudo tee /etc/apt/sources.list.d/gitlab-ce.list sudo apt update安装完成后不要立即执行gitlab-ctl reconfigure。先编辑/etc/gitlab/gitlab.rb这是整个 GitLab CE 的“宪法文件”所有服务行为都由此定义。以下是生产环境必须配置的 8 项核心参数按重要性排序# 1. 【强制】设置外部 URL决定所有邮件链接、CI 变量、Webhook 地址 external_url https://gitlab.example.com # 2. 【强制】禁用默认的 nginx交由外部反向代理更安全、更灵活 nginx[enable] false # 若坚持用内置 nginx请务必开启 HTTPS否则浏览器会拦截混合内容 # nginx[redirect_http_to_https] true # nginx[ssl_certificate] /etc/gitlab/ssl/gitlab.example.com.crt # nginx[ssl_certificate_key] /etc/gitlab/ssl/gitlab.example.com.key # 3. 【强制】关闭 unicorn启用 puma前文已详述 unicorn[enable] false puma[enable] true puma[worker_processes] 4 puma[min_threads] 4 puma[max_threads] 16 # 4. 【推荐】限制 PostgreSQL 内存避免吃光系统资源 postgresql[shared_buffers] 256MB postgresql[max_connections] 200 postgresql[effective_cache_size] 1GB # 5. 【推荐】配置 Redis 密码防止未授权访问 redis[password] your_strong_redis_password_here # 6. 【推荐】启用自动备份每天凌晨 2 点保留 7 天 gitlab_rails[backup_path] /var/opt/gitlab/backups gitlab_rails[backup_keep_time] 604800 # 7 天单位秒 # 7. 【推荐】关闭注册功能防止匿名用户创建账号 gitlab_rails[sign_in_enabled] true gitlab_rails[signup_enabled] false # 8. 【推荐】设置默认项目可见性避免敏感代码意外公开 gitlab_rails[default_projects_features_issues] true gitlab_rails[default_projects_features_merge_requests] true gitlab_rails[default_projects_features_wiki] false gitlab_rails[default_projects_features_snippets] false gitlab_rails[default_projects_features_builds] true gitlab_rails[default_projects_limit] 100注意external_url必须以https://开头即使你用外部 Nginx 做 SSL 终结。GitLab 内部生成的 CI 变量如$CI_SERVER_URL、邮件中的重置链接、Webhook 的回调地址全部基于此 URL 构建。如果填成http://所有 HTTPS 页面里的script标签都会被浏览器拦截导致 UI 功能异常。3.3 首次配置与服务启动reconfigure过程中的 5 个关键阶段解析执行sudo gitlab-ctl reconfigure后ChefOmnibus 的配置引擎会按顺序执行 5 个核心阶段每个阶段失败都会中断整个流程。理解这些阶段是快速定位问题的关键。阶段一Compile Time编译期Chef 解析/etc/gitlab/gitlab.rb将 Ruby 配置转换为 JSON 格式的node.json并校验语法。常见错误SyntaxError: /etc/gitlab/gitlab.rb:12: syntax error, unexpected end-of-input配置文件末尾少了一个}NameError: uninitialized constant Gitlab变量名拼错如gitlab_rails写成gitlab_rail阶段二Converge收敛期Chef 按照cookbooks/下的 recipe 执行资源创建创建/var/opt/gitlab目录树并设置属主gitlab-psql:gitlab-psql生成/var/opt/gitlab/nginx/conf/gitlab-http.conf即使nginx[enable] false此文件仍会生成供外部 Nginx 引用初始化 PostgreSQL 数据库执行gitlab-ctl pg-upgrade创建gitlabhq_production数据库和gitlab用户阶段三Service Management服务管控启动所有子服务按依赖顺序redis→ 2.postgresql→ 3.gitlab-workhorse→ 4.puma→ 5.nginx若启用→ 6.sidekiq→ 7.logrotate关键观察点执行sudo gitlab-ctl status应看到所有服务状态为run且 PID 不为?。若某个服务显示down立即查其日志sudo gitlab-ctl tail service_name。阶段四Health Check健康检查自动执行gitlab-rake gitlab:check SANITIZEtrue验证数据库连接是否正常psql -U gitlab -d gitlabhq_production -c SELECT version();Redis 是否可 ping 通redis-cli -a password pingGit 仓库目录权限是否正确ls -ld /var/opt/gitlab/git-data/repositories应为drwxrws--- git:gitlab-www阶段五Finalize收尾生成管理员初始密码保存在/etc/gitlab/initial_root_password并提示首次登录地址。此时执行sudo cat /etc/gitlab/initial_root_password # 输出类似Password: wBQzKxYvRtJfGhLmNpQsT1U2V3W4X5Y6Z7A8B9C0D1E2F3G4H5I6J7K8L9M0N1O2P3Q4R5S6T7U8V9W0X1Y2Z3提示这个密码只在首次reconfigure时生成一次之后修改密码不会更新此文件。建议复制后立即删除sudo shred -u /etc/gitlab/initial_root_password防止泄露。3.4 外部 Nginx 反向代理配置绕过 GitLab 自带 nginx 的完整实践既然禁用了 GitLab 内置 nginx就必须用外部 Nginx 代理所有流量。以下是经过生产验证的最小可行配置/etc/nginx/sites-available/gitlabupstream gitlab-workhorse { server 127.0.0.1:8181 fail_timeout0; } server { listen 80; server_name gitlab.example.com; # 强制跳转 HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name gitlab.example.com; # SSL 证书由 Lets Encrypt 或企业 CA 提供 ssl_certificate /etc/letsencrypt/live/gitlab.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gitlab.example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/gitlab.example.com/chain.pem; # SSL 安全加固 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 5m; # GitLab 特定头传递 proxy_redirect off; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Ssl on; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; # 静态资源缓存提升 UI 加载速度 location ~ ^/(assets|packs)/ { root /opt/gitlab/embedded/service/gitlab-rails/public; gzip_static on; expires max; add_header Cache-Control public, immutable; } # API 和 Websocket 路由 location / { client_max_body_size 0; proxy_buffering off; proxy_pass http://gitlab-workhorse; } }启用配置sudo ln -sf /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx关键验证步骤访问https://gitlab.example.com应看到 GitLab 登录页非 nginx 默认页打开浏览器开发者工具Network 标签页刷新页面检查main.js、application.css等静态资源的 Response Headers应包含Cache-Control: public, immutable在 GitLab UI 中创建一个新项目点击Settings CI/CD Runners确认Runner URL显示为https://gitlab.example.com/而非http://localhost注意client_max_body_size 0是必须的它禁用 Nginx 的请求体大小限制否则上传大于 1MB 的附件如 CI 日志、制品包会返回 413 Request Entity Too Large。GitLab 自身通过gitlab_rails[max_attachment_size]参数控制无需 Nginx 干预。4. 生产就绪必备配置与避坑指南从备份恢复到 CI/CD 流水线打通4.1 备份与恢复全流程不只是gitlab-rake backup:createGitLab CE 的备份不是简单的tar czf而是一个涉及 5 类数据的原子操作。gitlab-rake gitlab:backup:create命令会按顺序执行数据库备份调用pg_dump导出gitlabhq_production数据库为 SQL 文件1698765432_2023_10_25_15.11.11_gitlab_backup.tar中的database.sql.gzGit 仓库备份rsync -a --delete /var/opt/gitlab/git-data/repositories/ /var/opt/gitlab/backups/xxx_gitlab_backup.tar/git-data/repositories/上传文件备份rsync -a --delete /var/opt/gitlab/git-data/shared/uploads/ ...构建产物备份rsync -a --delete /var/opt/gitlab/git-data/shared/artifacts/ ...CI/CD 配置备份rsync -a --delete /var/opt/gitlab/git-data/shared/terraform_state/ ...但这里有个致命陷阱gitlab-rake backup:create默认不备份 SSH 主机密钥和 GitLab 配置文件如果服务器硬盘损坏你只能恢复数据却无法用原域名重新部署——因为/etc/gitlab/gitlab.rb和/var/opt/gitlab/.ssh/含ssh_host_rsa_key不在备份范围内。正确做法是建立双备份机制# 1. 创建配置备份脚本 /usr/local/bin/gitlab-config-backup.sh #!/bin/bash DATE$(date %Y_%m_%d_%H_%M_%S) BACKUP_DIR/backup/gitlab-config mkdir -p $BACKUP_DIR tar czf $BACKUP_DIR/gitlab-config-$DATE.tar.gz \ /etc/gitlab/gitlab.rb \ /etc/gitlab/trusted-certs/ \ /var/opt/gitlab/.ssh/ \ /var/opt/gitlab/nginx/conf/ \ /var/opt/gitlab/ssl/ # 2. 添加到 crontab每天凌晨 1:30 执行 30 1 * * * /usr/local/bin/gitlab-config-backup.sh # 3. 修改 GitLab 备份保留策略/etc/gitlab/gitlab.rb gitlab_rails[backup_keep_time] 604800 # 7 天恢复流程必须严格遵循顺序先恢复/etc/gitlab/gitlab.rb和 SSL 证书确保external_url与原环境一致执行sudo gitlab-ctl reconfigure重建服务目录结构执行sudo gitlab-ctl stop停止所有服务恢复数据库sudo gitlab-backup restore BACKUP1698765432_2023_10_25_15.11.11恢复 Git 仓库sudo rsync -a --delete /backup/gitlab-data/repositories/ /var/opt/gitlab/git-data/repositories/执行sudo gitlab-ctl start等待 2 分钟后检查sudo gitlab-ctl status提示恢复数据库后必须执行sudo gitlab-rake gitlab:check SANITIZEtrue它会自动修复因版本升级导致的数据库 schema 不一致问题。某次我们恢复 GitLab 14.10 的备份到 15.0 环境没执行此步导致Merge Requests页面空白查日志发现ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column merge_requests.merge_error正是 schema 缺失字段所致。4.2 CI/CD 流水线打通Runner 注册与.gitlab-ci.yml最小可行配置GitLab CE 的 CI/CD 功能默认关闭必须手动注册 Runner 并启用。Runner 分两类Shared Runner全局可用和Specific Runner绑定到特定项目。生产环境强烈推荐 Specific Runner避免不同项目间资源争抢。注册 Specific Runner 的完整流程# 1. 在 GitLab UI 中获取 Runner Token # Settings CI/CD Runners Expand Show token (复制) # 2. 在目标服务器Runner 所在机器安装 GitLab Runner # Ubuntu/Debian curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash sudo apt install gitlab-runner # 3. 注册 Runner交互式 sudo gitlab-runner register # 输入 GitLab 实例 URLhttps://gitlab.example.com # 输入 Runner Token粘贴上一步复制的 token # 输入 Runner 描述my-project-runner-01 # 输入 Runner tags逗号分隔docker, nodejs, python # 输入 Runner executordocker # 输入 default Docker imagenode:18-alpine # 4. 启动 Runner sudo gitlab-runner start关键配置文件/etc/gitlab-runner/config.toml必须修改[[runners]] name my-project-runner-01 url https://gitlab.example.com/ token your_runner_token_here executor docker [runners.docker] tls_verify false image node:18-alpine privileged false disable_entrypoint_overwrite false oom_kill_disable false disable_cache false volumes [/cache, /var/run/docker.sock:/var/run/docker.sock:rw] shm_size 0 [runners.cache] Type s3 ServerAddress s3.amazonaws.com AccessKey your_s3_access_key SecretKey your_s3_secret_key BucketName gitlab-runner-cache BucketLocation us-east-1注意volumes [/var/run/docker.sock:/var/run/docker.sock:rw]是让 Runner 能调用宿主机 Docker Daemon 的关键。但这也带来安全风险——Runner 容器内可执行任意docker命令。因此必须将 Runner 服务器与 GitLab 服务器物理隔离Runner 服务器不应存放任何敏感代码或密钥。.gitlab-ci.yml最小可行示例适用于 Node.js 项目# 定义流水线阶段 stages: - test - build - deploy # 测试阶段 test: stage: test image: node:18-alpine script: - npm ci - npm test artifacts: paths: - coverage/ only: - main - develop # 构建阶段 build: stage: build image: node:18-alpine script: - npm ci - npm run build artifacts: paths: - dist/ only: - main # 部署阶段示例同步到 NFS 存储 deploy: stage: deploy image: alpine:latest before_script: - apk add --no-cache rsync openssh-client script: - rsync -avz --delete ./dist/ usernfs-server:/var/www/my-app/ when: manual only: - main验证流水线是否打通在项目根目录提交.gitlab-ci.yml推送git push origin main进入CI/CD Pipelines应看到 pipeline 状态为running→passed点击 pipeline ID查看test作业日志应有PASS src/App.test.js字样若卡在preparing environment检查 Runner 状态sudo gitlab-runner verify应输出Running in system-mode和Runner registered successfully4.3 常见问题速查表与独家避坑技巧问题现象根本原因排查命令解决方案gitlab-ctl reconfigure卡在ruby_block[reload nginx]nginx 配置语法错误或 SSL 证书路径权限不足sudo nginx -tsudo ls -l /etc/gitlab/ssl/检查/var/log/gitlab/nginx/error.log确保证书文件属主为root:root权限600gitlab-rake gitlab:check报GitLab Shell API access failedgitlab-shell 服务未启动或端口被占用sudo gitlab-ctl status gitlab-shellsudo ss -tuln | grep :8181sudo gitlab-ctl restart gitlab-shell检查gitlab-workhorse是否监听8181CI 作业无限 pendingRunner 状态为offlineRunner 服务器时间与 GitLab 服务器偏差 5 分钟