2025 版 GitLab 完整搭建指南:Docker Compose 部署 + Runner 注册 + CICD 配置
概述
GitLab 是个开源工具,把代码托管、CI/CD 流水线和项目管理这几件事都包了,团队协作用它很顺手。比起 GitHub 或 Gitee 的私有仓库,自己搭一个 GitLab 最大的好处就是数据隐私和流水线流程都捏在自己手里。
这篇文章用 Docker Compose 把 GitLab 跑起来(包含 GitLab CE 核心服务和 GitLab Runner 执行器),从启动环境、注册 Runner 到配置项目的 CI/CD 全流程都走一遍,版本用的是 2025 年最新的 GitLab 17.7.0。新手照着步骤能复刻,团队也能直接把配置文件拿去用。
一、核心准备:环境与依赖检查
动手搭之前,先确认服务器满足下面这些条件,不然后面可能启动失败或者跑起来卡得要命:
1. 服务器配置要求
- 硬件:内存至少 4GB(GitLab 挺吃内存的,2GB 可能动不动就崩)、磁盘 20GB 以上(放代码、日志和 Runner 缓存);
- 系统:Linux 发行版(比如 Ubuntu 22.04、CentOS 9,下面以 Linux 为例,MacOS 得自己调一下挂载路径权限);
- 软件:装好 Docker 和 Docker Compose(没装的话先跑下面这两条命令):
# 安装 Docker(以 Ubuntu 为例,其他系统参考官方文档)
sudo apt update && sudo apt install -y docker.io
# 安装 Docker Compose
sudo apt install -y docker-compose-plugin
# 验证安装:查看版本
docker --version && docker compose version
2. 网络与域名准备
- 端口占用:确认服务器的 8929(GitLab 网页端口)和 2424(GitLab SSH 端口)没被别的程序占着,可以用 netstat -tuln | grep 8929 查一下;
- 域名解析:提前把 gitlab.luojia.work(就是配置文件里的 hostname)解析到服务器 IP;要是只在本地试,改一下 /etc/hosts 加条映射也行(比如 192.168.1.100 gitlab.luojia.work)。
二、Step 1:编写 Docker Compose 配置文件
用一个 docker-compose.yml 把 GitLab 核心服务和 Runner 服务一起管起来,启动就一条命令,数据也不会丢。配置文件里版本锁定、端口映射、数据挂载这些关键的都写好了,直接复制就能用(域名和端口按自己情况改改就行)。
1. 创建配置文件与目录
# 1. 创建 GitLab 工作目录(统一管理配置、日志、数据)
mkdir -p ~/gitlab-docker && cd ~/gitlab-docker
# 2. 创建 volumes 子目录(用于挂载数据,避免容器删除后数据丢失)
mkdir -p volumes/config volumes/logs volumes/data
# 3. 编写 docker-compose.yml 文件(用 vim 或 nano 均可)
vim docker-compose.yml
2. 完整配置文件内容
services:
# GitLab 核心服务(CE 社区版,免费且功能满足大部分团队需求)
gitlab:
image: gitlab/gitlab-ce:17.7.0-ce.0 # 锁定 17.7.0 版本,避免自动更新导致兼容问题
container_name: roger-gitlab # 容器名,便于后续管理(如停止、进入容器)
restart: always # 容器异常退出时自动重启(保证服务可用性)
hostname: "gitlab.luojia.work" # GitLab 内部 hostname,需与 external_url 域名一致
environment:
# GitLab 核心配置:通过环境变量注入,无需进入容器修改配置文件
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://gitlab.luojia.work:8929' # 外部访问地址(含端口)
gitlab_rails['gitlab_shell_ssh_port'] = 2424 # Git SSH 访问端口(默认 22,避免与主机 22 冲突)
ports:
- "8929:8929" # Web 端口映射:主机 8929 → 容器 8929(外部通过 http://域名:8929 访问)
- "2424:22" # SSH 端口映射:主机 2424 → 容器 22(Git 克隆时用 ssh://git@域名:2424/项目.git)
volumes:
# 数据持久化挂载:将容器内关键目录挂载到主机,确保容器删除后数据不丢失
- "./volumes/config:/etc/gitlab" # GitLab 配置文件目录
- "./volumes/logs:/var/log/gitlab" # GitLab 日志目录(排查问题时需查看)
- "./volumes/data:/var/opt/gitlab" # GitLab 数据目录(代码、数据库等核心数据)
shm_size: "256m" # 共享内存大小(GitLab 部分功能依赖,避免内存不足报错)
# GitLab Runner 服务(用于执行 CI/CD 流水线任务,如代码构建、部署)
gitlab-runner:
image: gitlab/gitlab-runner:v17.7.0 # Runner 版本需与 GitLab 版本匹配(避免 API 不兼容)
container_name: roger-gitlab-runner # Runner 容器名
restart: always
depends_on:
- gitlab # 确保 GitLab 服务启动后,再启动 Runner(避免 Runner 先启动无法连接 GitLab)
volumes:
# 挂载 Docker 套接字:让 Runner 能在容器内调用主机 Docker(实现 Docker 镜像构建)
- "/var/run/docker.sock:/var/run/docker.sock"
# 挂载 Runner 配置目录:持久化 Runner 注册信息(避免容器重启后需重新注册)
- "./volumes/config/gitlab-runner:/etc/gitlab-runner"
# 挂载主机 Docker 二进制文件:确保 Runner 内 Docker 命令可用(部分环境需此配置)
- "./volumes/bin/docker:/usr/bin/docker"
command: ["run", "--user=root", "--working-directory=/home/gitlab-runner"]
# 赋予特权模式:解决 Runner 内操作 Docker 时的权限问题(生产环境需评估安全性,非必需可删除)
privileged: true
3. 配置关键参数说明
| 参数 | 作用 | 修改建议 |
|---|---|---|
| external_url | 外部访问 GitLab 的 URL,决定网页访问与 Git 克隆地址 | 需改为实际域名 + 端口(如 http://gitlab.your-domain.com:8080) |
| gitlab_shell_ssh_port | Git SSH 协议端口 | 若主机 22 端口未被占用,可改为 22(克隆地址更简洁:git@域名:项目.git) |
| ports | 端口映射 | 避免与主机现有服务冲突(如 80 端口可用,可将 8929 改为 80) |
| volumes | 数据挂载 | 建议使用绝对路径(如 /home/user/gitlab-docker/volumes/config),避免路径混乱 |
三、Step 2:启动 GitLab 与 Runner 服务
配置文件写好后,用 Docker Compose 把服务拉起来。第一次启动要初始化数据库和配置,耗时比较长(大概 5 到 10 分钟,看服务器性能),耐心等一会儿。
1. 启动服务
# 后台启动服务(-d 表示 detached 模式,日志不会打印到控制台)
docker compose up -d
# 查看服务启动状态(确认 gitlab 与 gitlab-runner 均为 Up 状态)
docker compose ps
# 查看 GitLab 初始化日志(可选,监控初始化进度,出现 "Configuration finished" 表示初始化完成)
docker logs -f roger-gitlab
2. 验证 GitLab 网页访问
当日志显示初始化完成后,打开浏览器访问 http://gitlab.luojia.work:8929(或你配置的 external_url):
- 首次访问会提示 “设置管理员密码”(用户名默认 root),设置完成后登录;
- 若无法访问,检查服务器防火墙(如 sudo ufw allow 8929 开放端口)或 Docker 网络(docker network inspect gitlab-docker_default)。
四、Step 3:配置 Docker 权限(关键步骤)
GitLab Runner 构建镜像时要调用主机的 Docker 服务,但默认 /var/run/docker.sock(Docker 套接字文件)的权限是 root:docker,Runner 容器里的用户访问不了,得手动改下权限。
# 修改 docker.sock 权限为 666(允许所有用户读写,简单高效,适合内部测试环境)
sudo chmod 666 /var/run/docker.sock
# 验证权限(输出 "-rw-rw-rw-" 表示权限修改成功)
ls -l /var/run/docker.sock
注意事项(生产环境优化):
不过生产环境别这么干。直接给 666 权限等于所有用户都能操作 Docker,风险太大,建议:
- 在主机创建 docker 用户组(若不存在):sudo groupadd docker;
- 将 Runner 容器内用户加入主机 docker 组:sudo usermod -aG docker gitlab-runner;
- 恢复 docker.sock 权限为 660:sudo chmod 660 /var/run/docker.sock。
五、Step 4:注册 Runner 到 GitLab
Runner 就是干 CI/CD 活的“工人”,得先注册到 GitLab 并绑定项目,才能接到任务。注册之前要先拿到 GitLab 的“注册令牌”,步骤如下:
1. 获取 GitLab 注册令牌
1.登录 GitLab 网页后台(root 账号); 2. 进入 “Admin Area”(管理员区域,左侧导航栏最下方)→ “Runners” → “New instance runner”; 3. 按提示选择 Runner 类型(此处选 “Docker”),获取 “Registration token”(注册令牌,后续步骤需用到)。
2. 执行 Runner 注册命令
# 进入 Runner 容器,执行注册命令(容器名与配置文件中 container_name 一致)
docker exec -it roger-gitlab-runner gitlab-runner register
3. 按提示完成注册(关键步骤)
注册过程会弹出交互提示,按以下说明填写(其他默认选项直接回车):
# 1. 输入 GitLab 实例 URL(与 external_url 一致)
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
http://gitlab.luojia.work:8929
# 2. 输入刚才获取的注册令牌
Please enter the gitlab-ci token for this runner:
abcdefghijklmnopqrstuv # 替换为你的 Registration token
# 3. 输入 Runner 描述(自定义,便于识别,如 "Docker Runner for Build")
Please enter the gitlab-ci description for this runner:
[roger-gitlab-runner]: Docker Build Runner
# 4. 输入 Runner 标签(关键!CI/CD 配置中需通过标签指定 Runner,此处填 "docker")
Please enter the gitlab-ci tags for this runner (comma separated):
docker
# 5. 选择 Runner 执行器(此处选 "docker",因为我们要通过 Docker 构建镜像)
Please enter the executor: custom, docker, docker-ssh, parallels, shell, ssh, virtualbox, docker+machine, docker-ssh+machine, kubernetes:
docker
# 6. 若选择 docker 执行器,需指定默认 Docker 镜像(填 "alpine:latest" 即可,轻量且通用)
Please enter the default Docker image (e.g. ruby:2.7):
alpine:latest
4. 验证 Runner 注册成功
回到 GitLab 网页后台 “Admin Area → Runners”,若能看到状态为 “Active” 的 Runner(标签含 docker),表示注册成功。
六、Step 5:配置项目 CI/CD 流水线(.gitlab-ci.yml)
Runner 注册好之后,在 GitLab 项目里加一个 .gitlab-ci.yml 文件,把“构建(build)→ 部署(deploy)”的流水线定义出来。下面这个例子做的是“Docker 镜像构建 → 部署到 Kubernetes 集群”,你可以按自己的需要改脚本里的内容。
1. 前置准备(项目级配置)
在 GitLab 项目中添加 “环境变量”(避免敏感信息硬编码到配置文件):
- 进入项目 → “Settings” → “CI/CD” → “Variables” → “Add variable”;
- 添加以下变量(均设为 “Protected” 和 “Masked”,避免泄露):
- IMAGE_NAME:Docker 镜像名(如 my-project);
- IMAGE_TAG:Docker 镜像标签(如 $CI_COMMIT_SHORT_SHA,自动取当前提交的短哈希);
- SSH_KEY:用于登录部署服务器的 SSH 私钥(需提前在部署服务器添加公钥);
- DEPLOY_USER:部署服务器用户名(如 root);
- DEPLOY_HOST:部署服务器 IP(如 192.168.1.101);
- K8S_CONFIG_PATH:Kubernetes 部署配置文件路径(如 k8s/deployment.yaml)。
2. 编写 .gitlab-ci.yml 文件
在项目根目录创建 .gitlab-ci.yml,内容如下:
# 定义流水线阶段(顺序执行:先 build 再 deploy,可新增 test 等阶段)
stages:
- build # 构建阶段:构建 Docker 镜像
- deploy # 部署阶段:将镜像部署到 Kubernetes 集群
# 构建任务(属于 build 阶段)
build:
stage: build
tags:
- docker # 指定使用标签为 "docker" 的 Runner(与注册 Runner 时的标签一致)
script:
# 构建 Docker 镜像(镜像名+标签从环境变量获取,避免硬编码)
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
# 可选:将镜像推送到私有仓库(如 GitLab Container Registry)
# - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# - docker push $CI_REGISTRY/$CI_PROJECT_PATH/$IMAGE_NAME:$IMAGE_TAG
# 部署任务(属于 deploy 阶段,依赖 build 阶段完成)
deploy:
stage: deploy
tags:
- docker
before_script:
# 给 SSH 私钥设置只读权限(SSH 要求私钥权限不能过高,否则报错)
- chmod 400 $SSH_KEY
script:
# 通过 SSH 登录部署服务器,执行部署命令(一行命令用双引号包裹,多命令用分号分隔)
- ssh -o StrictHostKeyChecking=no -i $SSH_KEY ${DEPLOY_USER}@${DEPLOY_HOST} "
# 1. 将本地构建的镜像加载到 Kubernetes 集群(kind 是轻量 K8s 工具,根据实际环境调整)
kind load docker-image $IMAGE_NAME:$IMAGE_TAG --name roger &&
# 2. 应用 Kubernetes 部署配置,更新服务
kubectl apply -f $K8S_CONFIG_PATH
"
# 可选:仅在 master/main 分支提交时触发部署(避免测试分支误部署)
only:
- master
3. 触发流水线并验证
- 将 .gitlab-ci.yml 提交到 GitLab 项目(git add . && git commit -m “add ci/cd config” && git push);
- 进入项目 → “CI/CD” → “Pipelines”,可看到流水线自动触发,状态从 “pending” 变为 “running”;
- 点击流水线任务,查看 “Job log”,若最后显示 “Job succeeded”,表示构建与部署均成功。
七、常见问题与解决方案
1. GitLab 启动后网页无法访问
- 检查防火墙端口:若使用 Ubuntu 系统,通过 sudo ufw status 确认 8929 端口已开放,未开放则执行 sudo ufw allow 8929;CentOS 系统需检查 firewalld,执行 sudo firewall-cmd —zone=public —add-port=8929/tcp —permanent 并 sudo firewall-cmd —reload。
- 排查容器日志:执行 docker logs -f roger-gitlab 查看初始化日志,若出现 “database connection timeout” 或 “memory exhausted”,大概率是服务器内存不足(GitLab 最低需 4GB 内存),需升级服务器配置或关闭其他占用内存的服务。
- 验证 external_url 一致性:确保浏览器访问地址与 docker-compose.yml 中 external_url 完全一致(含域名、端口),例如配置的是 http://gitlab.luojia.work:8929,则不能用 http://192.168.1.100:8929 访问(除非 /etc/hosts 已配置域名映射)。
2. Runner 注册时提示 “connection refused”
- 确认 GitLab 服务状态:先通过 docker compose ps 检查 roger-gitlab 容器是否为 Up 状态,若为 Exited,需先重启服务 docker compose restart gitlab。
- 检查网络连通性:进入 Runner 容器内部测试网络,执行 docker exec -it roger-gitlab-runner ping gitlab.luojia.work,若无法 ping 通,需检查 Docker 网络(默认 bridge 模式下,容器间可通过容器名或 hostname 通信,若自定义网络需调整)。
- 核对注册令牌与 URL:确保输入的 GitLab 实例 URL(如 http://gitlab.luojia.work:8929)末尾无多余斜杠,注册令牌与 GitLab 后台 “Admin Area → Runners” 中显示的完全一致(区分大小写)。
3. CI/CD 流水线提示 “docker: command not found”
- 检查 Docker 挂载配置:确认 docker-compose.yml 中 Runner 服务的 volumes 已包含 /var/run/docker.sock:/var/run/docker.sock,若遗漏需添加后重启 Runner:docker compose restart gitlab-runner。
- 验证 Docker 权限:进入 Runner 容器执行 ls -l /var/run/docker.sock,若显示 “Permission denied”,需重新执行 sudo chmod 666 /var/run/docker.sock(测试环境)或按前文 “生产环境优化” 方案配置 docker 用户组权限。
- 检查 Docker 二进制文件:若配置了 - ”./volumes/bin/docker:/usr/bin/docker” 挂载,需确认主机 /home/user/gitlab-docker/volumes/bin/docker 路径下存在 docker 二进制文件,若不存在可从主机 /usr/bin/docker 复制:cp /usr/bin/docker ~/gitlab-docker/volumes/bin/。
4. SSH 部署时提示 “Host key verification failed”
- 关闭 StrictHostKeyChecking:在 deploy 任务的 ssh 命令中添加 -o StrictHostKeyChecking=no(已在示例配置中包含),跳过首次连接的主机密钥验证(适合自动化场景,生产环境可提前在 Runner 容器中添加部署服务器的主机密钥)。
- 验证 SSH 私钥有效性:在 GitLab 项目 “CI/CD → Variables” 中检查 SSH_KEY 变量是否完整(无多余空格、换行),可在本地测试私钥:ssh -i ~/local-ssh-key deploy-user@deploy-host,确保能正常登录。
- 检查私钥权限:确认 before_script 中的 chmod 400 $SSH_KEY 已执行(SSH 要求私钥权限不能高于 600,否则拒绝使用),若仍报错,可在脚本中添加 ls -l $SSH_KEY 查看权限是否正确。
5. Kubernetes 部署提示 “kind: command not found”
- 确认部署服务器环境:kind load docker-image 命令仅适用于使用 Kind(Kubernetes IN Docker)搭建的 K8s 集群,若部署目标是真实 K8s 集群(如 EKS、AKS 或自建集群),需替换为 docker push 镜像到集群可访问的镜像仓库(如 Docker Hub、GitLab Container Registry),再通过 kubectl apply 部署。
- 检查 kubectl 配置:确保部署服务器已安装 kubectl 且配置了集群访问权限(~/.kube/config 文件正常),可在部署服务器本地执行 kubectl get nodes 验证,若报错需先配置 K8s 集群访问凭证。
八、总结与后续优化建议
1. 搭完之后有了啥
按上面这套步骤走下来,你已经有了:
- GitLab 核心服务:用 Docker Compose 一条命令启动,配置、日志、代码数据都做了持久化,容器删了也不丢;
- 注册好的 Runner:能正常接 GitLab 下发的 CI/CD 任务,支持构建 Docker 镜像;
- 一条完整的 CI/CD 流水线:从提交代码触发构建,到把镜像部署上 Kubernetes 集群,全自动化。
2. 生产环境优化方向
(1)安全性增强
- 换成 HTTPS:在 docker-compose.yml 里把 external_url 改成 https://gitlab.your-domain.com,再用 GITLAB_OMNIBUS_CONFIG 配上 SSL 证书(比如用 Let’s Encrypt 免费证书):
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.your-domain.com'
nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.your-domain.com.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.your-domain.com.key"
- 收一下 Runner 的权限:生产环境别用 privileged: true,改成通过 docker 用户组授权(前面提过),再在 GitLab 后台 “Runner → Restrict projects” 里限制 Runner 只能访问必要的项目。
- 给敏感变量加密:GitLab 项目的 CI/CD 变量记得勾上 “Masked”(隐藏值)和 “Protected”(只有保护分支能用),别让敏感信息漏出去。
(2)性能与可用性优化
- 加上资源限制:在 docker-compose.yml 里给 GitLab 服务限制资源,免得它把服务器资源吃满:
services:
gitlab:
# 其他配置...
deploy:
resources:
limits:
cpus: "2"
memory: 4G
reservations:
cpus: "1"
memory: 2G
- 配上 GitLab 备份:写个定时任务自动备份 GitLab 数据(用 gitlab-rake gitlab:backup:create 命令),再把备份同步到异地存储(如 S3、OSS):
# 示例:每天凌晨 2 点执行备份,输出到 /backup 目录
0 2 * * * docker exec roger-gitlab gitlab-rake gitlab:backup:create BACKUP_DIR=/var/opt/gitlab/backups && cp ~/gitlab-docker/volumes/data/backups/*.tar /backup/
- 用 GitLab Container Registry:把 GitLab 内置的镜像仓库开起来(项目 → “Packages & Registries → Container Registry”),就不用依赖外部镜像仓库了,流水线也能更顺(示例配置里已经有推送镜像的注释代码)。
(3)功能扩展
- 加上 GitLab Pages:配一下 GitLab Pages 就能部署静态网站(比如项目文档、博客),在 GITLAB_OMNIBUS_CONFIG 里加一句 pages_external_url ‘https://pages.your-domain.com/’;
- 接上 Mattermost/Teams:配一下 GitLab 通知,把流水线状态、代码提交信息推到团队沟通工具(如 Mattermost、Microsoft Teams),协作更顺;
- 开 LDAP 认证:如果团队用 LDAP 统一认证,在 GitLab 后台 “Admin Area → Settings → General → Sign-in restrictions” 里配一下 LDAP 登录,就能单点登录了。
把上面这些优化做了,你自建的 GitLab 就能从“能跑起来”变成“生产级稳当的服务”,团队从托管代码到自动部署全链路都覆盖。后面再根据团队规模和业务需要慢慢加功能,GitLab 那一套生态够你玩的。