- 运维
- 云原生
【免费下载链接】docker-gitlab
Dockerized GitLab
本文以 docker-gitlab 仓库提供的docker-compose.swarm.yml为蓝本,讲解如何在 Docker Swarm 模式集群中部署一套完整的 GitLab 服务,并通过 Traefik 统一处理基于域名的路由、HTTPS 通信与 Let's Encrypt 自动证书签发。文中覆盖 DNS 与 SSH 端口调整、环境变量配置、节点标签(placement constraints)与命名卷(named volumes)绑定、GitLab 与 Registry 内部自签证书自动生成、以及 GitLab Runner 的独立部署等完整环节。读完本文,你将能独立把 GitLab 与 Docker Registry 以"一栈多服务"的形式稳定部署到 Swarm 集群,并让其通过 GitLab 凭据完成镜像认证、配合 GitLab CI 使用。
部署方案总览:为什么是 Swarm + Registry + Traefik
该方案的核心架构由三个组件协作而成,对应 docker-compose.swarm.yml 中的三个服务:
- Docker Swarm mode:负责集群管理与服务编排,让 GitLab、Registry、PostgreSQL、Redis 作为一组 stack services 统一调度、统一升级;
- Docker Registry:提供镜像存储与分发能力,使用 GitLab 的凭据体系完成认证,并与 GitLab CI 深度集成——开发者在 GitLab 上 push 代码后可直接把镜像推到同一个 Registry;
- Traefik:作为全局反向代理处理基于域名的路由、HTTPS 通信以及 Let's Encrypt 自动证书生成,不需要自建 Nginx 代理或类似组件。
此外,GitLab 与 Registry 之间的内部通信证书(自签名)由 GitLab 容器自动生成并配置,无需手工签发。
整套编排的核心入口是仓库根目录的 docker-compose.swarm.yml,其中包含了 redis、postgresql、registry、gitlab 四个服务以及 5 个命名卷(redis-data、postgresql-data、gitlab-data、registry-data、certs-data)。其中:
gitlab与registry共享certs-data卷(GitLab 生成的自签证书需要被 Registry 读取);gitlab服务通过ports以mode: host方式独占宿主机的22端口,保证 Git 的 SSH 协议可用;- 所有对外服务通过
traefik-public外部网络接入公共 Traefik,docker-compose.swarm.yml 中声明该网络为external: true,需要提前由 Traefik 部署创建。
前置步骤一:搭建 Docker Swarm 集群与全局 Traefik
按 DockerSwarm.rocks 的引导部署一个 Swarm 模式集群(单机或多机皆可),并在集群中部署一个全局的 Traefik 负载均衡器。该步骤大约需要 20 分钟,完成后集群即可供后续步骤使用。
从 docker-compose.swarm.yml 中可以看到,registry和gitlab服务的 Traefik 标签(labels)要求集群中存在名为traefik-public的外部网络、http/https两个 entrypoints,以及名为le的证书解析器(certresolver),例如:
- traefik.http.routers.gitlab-registry-http.entrypoints=http - traefik.http.routers.gitlab-registry-https.tls.certresolver=le因此在准备集群时,需要确保 Traefik 使用这些命名约定,否则标签无法生效。
前置步骤二:配置 DNS 记录
为 GitLab 实例和 Docker Registry 各配置一个子域名,指向服务器:
gitlab.example.com:用于浏览器访问 GitLab 以及git push/pull;registry.example.com:用于存储、push、pull Docker 镜像,例如docker pull registry.example.com/mygroup/myproject/imagename:sometag。
若集群有多个节点,DNS 记录需要指向承载gitlab与registry服务的那个节点 IP。原因在于:gitlab服务为了 Git 协议必须监听宿主机的22端口,而该端口通过mode: host模式只在 GitLab 所在的节点上发布,其他节点不受影响,无需改动默认 SSH 端口。对应配置见 docker-compose.swarm.yml:
ports: # Listen on port 22, default for SSH and Git in host mode (only in its host) # So other nodes in the cluster can keep listening on port 22 - target: 22 published: 22 mode: host前置步骤三:修改服务器 SSH 端口
Git 默认使用 SSH 端口22,而 GitLab 容器需要占用该端口,因此需将服务器自身的 SSH 服务改到其他端口。本文以2222作为服务器 SSH 端口、22留给 GitLab。
首先按正常方式连接服务器:
ssh root@gitlab.example.com备份 SSH 配置:
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup修改配置,确保存在一行Port 2222且不存在Port 22。可用如下命令自动完成替换(匹配Port 22或#Port 22并替换为Port 2222):
sed -i 's|^#\?Port 22$|Port 2222|' /etc/ssh/sshd_config或用nano手工编辑:
nano /etc/ssh/sshd_config确认结果:
grep "^Port" /etc/ssh/sshd_config然后重启 SSH 服务:
systemctl restart sshd.service警告:如果 SSH 配置有误,你可能会把自己锁在服务器外。请在不关闭当前会话的情况下另开一个终端,用新端口测试连接:
ssh -p 2222 root@gitlab.example.com如果能够正常登录,说明配置成功;若失败,可回到原会话修正配置并重启服务,避免被锁死。
下载 Compose Stack 文件
下载仓库提供的 Swarm 编排文件:
curl -L https://raw.githubusercontent.com/sameersbn/docker-gitlab/master/docker-compose.swarm.yml -o docker-compose.swarm.yml该文件即仓库根目录的 docker-compose.swarm.yml,是后续所有部署的基础。
设置环境变量:GITLAB_HOST 与 REGISTRY_HOST
导出两个核心环境变量,指向你配置的子域名:
export GITLAB_HOST=gitlab.example.com export REGISTRY_HOST=registry.example.com这两个变量会被 docker-compose.swarm.yml 使用:它们既在服务内部作为配置项注入,也被用于生成 Traefik 的路由标签(例如Host(\${GITLAB_HOST?Variable not set}`))。因此**每次部署 stack 之前都必须重新导出**,否则 Compose 解析会因变量未定义而报错(文件中的?Variable not set` 语法会直接给出明确提示,见 docker-compose.swarm.yml)。
从镜像标签sameersbn/gitlab:19.3.2可以看到该方案当前对应的 GitLab 版本(docker-compose.swarm.yml),它与仓库 VERSION 文件保持一致。
其他环境变量与敏感值生成
除了两个 HOST 变量,还有大量可配置项。Registry 相关的完整参数说明可参考仓库的 container_registry.md;全部选项可参考仓库根目录 README.md。所有变量都可以直接编辑 docker-compose.swarm.yml 进行配置:
nano docker-compose.swarm.yml开放注册:若希望任何人都能注册而不是仅限受邀用户,将GITLAB_SIGNUP_ENABLED改为true(默认值为false,见 docker-compose.swarm.yml):
export GITLAB_SIGNUP_ENABLED=true随机密钥生成:多个密钥类变量要求随机字符串,每次生成一个并复制输出:
openssl rand -hex 32 # Outputs something like: 99d3b1f01aa639e4a76f4fc281fc834747a543720ba4c8a8648ba755aef9be7f在文件中替换为对应值:
- GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string - GITLAB_SECRETS_ENCRYPTED_SETTINGS_KEY_BASE=long-and-random-alphanumeric-stringdocker-compose.swarm.yml 中除上述四项外,还包含 GitLab 19.x 引入的 Active Record 加密相关变量:
- GITLAB_SECRETS_ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=["long-and-random-alphanumeric-string"] - GITLAB_SECRETS_ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=["long-and-random-alphanumeric-string"] - GITLAB_SECRETS_ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=long-and-random-alphanumeric-string其余常见配置还包括邮件通知账号、SMTP 凭据(SMTP_ENABLED、SMTP_HOST、SMTP_PORT、SMTP_USER、SMTP_PASS等,见 docker-compose.swarm.yml)、IMAP 收件配置、OAuth 各 Provider 参数,以及备份计划(GITLAB_BACKUP_SCHEDULE=daily、GITLAB_BACKUP_TIME=01:00,见 docker-compose.swarm.yml)。
上传文件到服务器
如果在本地修改了文件,将其复制到远程服务器(使用新的 SSH 端口2222):
scp -P 2222 docker-compose.swarm.yml root@gitlab.example.com:/root/然后连接服务器:
ssh -p 2222 root@gitlab.example.com注意:即使你已在本地改好了 Compose 文件,连接服务器后仍需重新导出
GITLAB_HOST和REGISTRY_HOST——它们被用于 Traefik 标签,Compose 文件本身无法提供这些值。
理解卷、标签与约束(placement constraints)
由于 Swarm 集群可能包含多台机器,凡是读写命名卷的服务都必须被固定调度到同一节点,否则每次重新部署后服务可能漂移到别的节点而读不到数据。以redis服务为例,docker-compose.swarm.yml 中:
volumes: - redis-data:/var/lib/redis:Z以及对应的部署约束:
deploy: placement: constraints: - node.labels.gitlab.redis-data == true这告诉 Docker:redis服务只能部署到带有node.labels.gitlab.redis-data=true标签的节点上。只要给集群中一个节点打上该标签,redis就会始终落在同一节点,持续读写同一个redis-data卷——即使反复重新部署或升级 stack 也不会丢失数据。
仓库根目录的 docker-compose.yml(非 Swarm 版)与 docker-compose.swarm.yml 的卷定义保持对应关系,可对照阅读。
为节点添加约束标签
接下来为节点打上满足约束所需的标签:
- 连接到 Swarm 集群的一个 manager 节点(可以是运行 GitLab 的服务器,也可以是其他节点)。
- 若就在当前 manager 节点上部署,获取其节点 ID:
export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')- 否则用
docker node ls查看可用节点并选出目标节点:
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION m48gz5e8ucmk59af4m6enmnaz * dog.example.com Ready Active Leader 19.03.9 4w456u9lnanau629v3y456k9d cat.example.com Ready Active 19.03.9 mue36qqwqnzrqt4iqi0yyd6ie gitlab.example.com Ready Active 19.03.9本例选择gitlab.example.com(节点 IDmue36qqwqnzrqt4iqi0yyd6ie)作为gitlab服务的目标节点:
export NODE_ID=mue36qqwqnzrqt4iqi0yyd6ie- 给该节点打标签,使
gitlab与registry始终部署在同一节点(二者共享certs-data卷,Registry 需要读取 GitLab 生成的 TLS 证书):
docker node update --label-add gitlab.certs-data=true $NODE_ID- 给
redis打标签(集群节点多于一台时可选用其他节点,本例为简单起见使用同一节点):
docker node update --label-add gitlab.redis-data=true $NODE_ID- 给
postgresql打标签:
docker node update --label-add gitlab.postgresql-data=true $NODE_ID注意:这些标签只需设置一次,之后重新部署 stack 时无需重复执行。
部署 Stack 与状态检查
标签已设置、环境变量已导出后,即可部署:
docker stack deploy --compose-file docker-compose.swarm.yml gitlabGITLAB_HOST与REGISTRY_HOST每次部署都必须可用,而节点标签只需首次部署时设置。
查看部署状态:
docker stack ps gitlab查看某个服务的日志,例如gitlab_gitlab:
docker service logs gitlab_gitlab内部证书:GitLab 与 Registry 的自签通信
GitLab 与 Docker Registry 对外使用 Let's Encrypt 签发的公网 HTTPS 证书(由 Traefik 自动处理),但二者之间的内部通信使用另一套自签名证书。该证书由 GitLab 容器自动生成。
在 docker-compose.swarm.yml 中,gitlab服务通过环境变量开启自动生成:
- GITLAB_REGISTRY_GENERATE_INTERNAL_CERTIFICATES=true证书写入位置由GITLAB_REGISTRY_KEY_PATH指定:
- GITLAB_REGISTRY_KEY_PATH=/certs/registry.key/certs目录挂载为命名卷certs-data(docker-compose.swarm.yml):
volumes: - gitlab-data:/home/git/data:Z - certs-data:/certs因此自签证书实际生成在命名卷certs-data中。registry服务同样挂载该卷:
volumes: - registry-data:/registry - certs-data:/certs并配置为从 GitLab 生成证书的同一位置读取根证书:
- REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/registry.crt源码级验证:证书生成逻辑实现在 assets/runtime/functions 的generate_registry_certificates()函数中。该函数在GITLAB_REGISTRY_GENERATE_INTERNAL_CERTIFICATES=true时执行:从GITLAB_REGISTRY_KEY_PATH推导证书目录,由registry.key文件名推导出同名的.crt文件,随后依次用openssl rand生成随机口令文件、openssl req创建 PKCS#10 证书请求、openssl rsa转换 RSA 私钥、openssl x509签发有效期为 10000 天的自签证书;若同名文件已存在则跳过,实现幂等。该函数在configure_gitlab()流程中位于gitlab_configure_registry之前被调用(assets/runtime/functions),保证配置写入时证书已就绪。
默认值:这些变量的默认值定义在 assets/runtime/env-defaults:GITLAB_REGISTRY_ENABLED默认false、GITLAB_REGISTRY_HOST默认registry.example.com、GITLAB_REGISTRY_PORT默认443、GITLAB_REGISTRY_API_URL默认http://127.0.0.1:5000/、GITLAB_REGISTRY_ISSUER默认gitlab-issuer、GITLAB_REGISTRY_GENERATE_INTERNAL_CERTIFICATES默认false。Swarm 编排文件正是覆盖了这些默认值才让 Registry 集成生效。
Registry 认证要点:REGISTRY_AUTH_TOKEN_REALM、REGISTRY_AUTH_TOKEN_SERVICE=container_registry、REGISTRY_AUTH_TOKEN_ISSUER、REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE四个参数共同构成 Registry 的 token 认证体系,其中GITLAB_REGISTRY_ISSUER必须与 Registry 的issuer保持一致,否则认证不通过。完整参数表可参考 container_registry.md。
在 Docker 中部署 GitLab Runner
若要启用 CI/CD,可按本节安装 GitLab Runner。建议使用 Docker 独立模式(standalone)运行 Runner 而非 Swarm 模式,因为 Runner 的配置需要持久化,而 Swarm 模式下容器可能被调度到其他服务器导致配置丢失。
测试与部署场景:
- 仅用于测试时,Runner 可运行在任意节点;
- 若 Runner 同时承担部署任务(或复用同一 Runner),它必须运行在 Swarm 集群的 manager 节点上,才能执行集群相关操作。
以独立模式创建 Runner:
docker run -d \ --name gitlab-runner \ --restart always \ -v gitlab-runner:/etc/gitlab-runner \ -v /tmp/builds:/tmp/builds \ -v /var/run/docker.sock:/var/run/docker.sock \ gitlab/gitlab-runner:latest进入容器:
docker exec -it gitlab-runner bash注册 Runner:
- 在 GitLab 的 "Admin Area -> Runners" 页面获取 URL 与注册 token;
- 在 Runner 容器的 bash 会话中设置变量:
export GITLAB_URL=https://gitlab.example.com/ export GITLAB_TOKEN=WYasdfJp4sdfasdf1234- 执行注册命令(名称与标签可按需修改,之后也可在 Web 界面调整):
gitlab-runner \ register -n \ --name "Docker Runner" \ --executor docker \ --locked false \ --access-level not_protected \ --builds-dir /tmp/builds \ --docker-image docker:latest \ --docker-volumes /tmp/builds:/tmp/builds \ --docker-volumes /var/run/docker.sock:/var/run/docker.sock \ --url $GITLAB_URL \ --registration-token $GITLAB_TOKEN \ --tag-list dog-cat-cluster,stag,prod- 之后可在 GitLab 管理后台对 Runner 做进一步编辑。
Registry 配置参数速查(来自仓库配套文档)
针对 Registry 集成,container_registry.md 给出了完整的参数表,以下是 GitLab 侧核心参数(默认值以 assets/runtime/env-defaults 为准):
| 参数 | 说明 |
|---|---|
GITLAB_REGISTRY_ENABLED | true或false,启用 GitLab 中的 Registry,默认false |
GITLAB_REGISTRY_HOST | Registry 对外域名,用户通过该域名使用 Registry,默认registry.example.com |
GITLAB_REGISTRY_PORT | 外部 Registry 域名监听的端口,默认443 |
GITLAB_REGISTRY_API_URL | Registry 内部 API 地址,默认http://127.0.0.1:5000/ |
GITLAB_REGISTRY_KEY_PATH | 与 Registry 的rootcertbundle配对的私钥路径 |
GITLAB_REGISTRY_ISSUER | 必须与 Registry 的issuer保持一致,否则认证失败,默认gitlab-issuer |
GITLAB_REGISTRY_GENERATE_INTERNAL_CERTIFICATES | 是否让 GitLab 自动生成内部自签证书,默认false |
SSL_REGISTRY_KEY_PATH/SSL_REGISTRY_CERT_PATH | 用于 Nginx 代理 Registry 的 HTTPS 私钥与证书 |
从源码实现看,gitlab_configure_registry()(assets/runtime/functions)会将上述变量渲染进 GitLab 配置模板;当GITLAB_REGISTRY_PORT为443时,该函数会将其置空后再渲染——因为 443 是 HTTPS 默认端口,docker pull registry/some/image与docker pull registry:443/some/image等价,GitLab 界面也不必显示端口号。Nginx 侧则通过nginx_configure_gitlab_registry()(assets/runtime/functions)在GITLAB_REGISTRY_ENABLED=true且存在 SSL 证书时生成 registry 站点配置。
关于 Registry 存储驱动(filesystem、azure、gcs、s3、swift、oss)、备份与恢复(gitlab:backup:create/gitlab:backup:restore)等维护操作,均可直接参考 container_registry.md;S3 对象存储场景还可结合 s3_compatible_storage.md 阅读。若需要对外暴露 GitLab 的 SSH 端口,可参考 exposing-ssh-port.md;Swarm 与 Traefik 的 Registry 组合另有 docker-swarm-traefik-registry.md(即本文对应文档)可对照。
小结
至此,一条完整的 Swarm 部署链路已经打通:DNS 指向 → 服务器 SSH 端口让位 → 节点标签固定卷归属 → 导出环境变量 →docker stack deploy一键拉起 → Traefik 自动签发 HTTPS 证书 → GitLab 自动生成与 Registry 通信的内部证书 → Runner 独立部署接入 CI/CD。这套方案的关键设计在于:用节点标签 + 命名卷保证有状态服务的数据归属,用 Traefik 标签消除手工 Nginx 配置,用GITLAB_REGISTRY_GENERATE_INTERNAL_CERTIFICATES自动化内部证书生命周期,从而让 GitLab、Registry 与 CI 在一个 Swarm 集群中自洽运转。
- 运维
- 云原生
【免费下载链接】docker-gitlab
Dockerized GitLab
相关推荐
Hyperf 项目 Docker Swarm 集群部署实战指南
Hyperf 项目 Docker Swarm 集群部署实战指南 前言 在现代微服务架构中,容器化部署已成为主流方案。本文将详细介绍如何在 Hyperf 项目中利
后端微服务Hyperf项目Docker Swarm集群部署实战指南
Hyperf项目Docker Swarm集群部署实战指南 前言 在现代微服务架构中,容器化部署已成为主流方案。本文将详细介绍如何基于Hyperf框架和Docke
后端微服务Hyperf项目Docker Swarm集群部署实战指南
Hyperf项目Docker Swarm集群部署实战指南 前言 在现代云原生应用开发中,容器化和集群部署已成为必备技能。本文将详细介绍如何基于Hyperf框架构
后端微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考