☰
docker-gitlab 在 Docker Swarm 集群中部署 GitLab + Docker Registry + Traefik 的完整实战指南
2026/9/26 2:29:49 网站建设 项目流程
  • 运维
  • 云原生

【免费下载链接】docker-gitlab

Dockerized GitLab

项目地址:https://gitcode.com/gh_mirrors/do/docker-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-string

docker-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 的卷定义保持对应关系,可对照阅读。

为节点添加约束标签

接下来为节点打上满足约束所需的标签:

  1. 连接到 Swarm 集群的一个 manager 节点(可以是运行 GitLab 的服务器,也可以是其他节点)。
  2. 若就在当前 manager 节点上部署,获取其节点 ID:
export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')
  1. 否则用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
  1. 给该节点打标签,使gitlab与registry始终部署在同一节点(二者共享certs-data卷,Registry 需要读取 GitLab 生成的 TLS 证书):
docker node update --label-add gitlab.certs-data=true $NODE_ID
  1. 给redis打标签(集群节点多于一台时可选用其他节点,本例为简单起见使用同一节点):
docker node update --label-add gitlab.redis-data=true $NODE_ID
  1. 给postgresql打标签:
docker node update --label-add gitlab.postgresql-data=true $NODE_ID

注意:这些标签只需设置一次,之后重新部署 stack 时无需重复执行。

部署 Stack 与状态检查

标签已设置、环境变量已导出后,即可部署:

docker stack deploy --compose-file docker-compose.swarm.yml gitlab

GITLAB_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:

  1. 在 GitLab 的 "Admin Area -> Runners" 页面获取 URL 与注册 token;
  2. 在 Runner 容器的 bash 会话中设置变量:
export GITLAB_URL=https://gitlab.example.com/ export GITLAB_TOKEN=WYasdfJp4sdfasdf1234
  1. 执行注册命令(名称与标签可按需修改,之后也可在 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
  1. 之后可在 GitLab 管理后台对 Runner 做进一步编辑。

Registry 配置参数速查(来自仓库配套文档)

针对 Registry 集成,container_registry.md 给出了完整的参数表,以下是 GitLab 侧核心参数(默认值以 assets/runtime/env-defaults 为准):

参数说明
GITLAB_REGISTRY_ENABLEDtrue或false,启用 GitLab 中的 Registry,默认false
GITLAB_REGISTRY_HOSTRegistry 对外域名,用户通过该域名使用 Registry,默认registry.example.com
GITLAB_REGISTRY_PORT外部 Registry 域名监听的端口,默认443
GITLAB_REGISTRY_API_URLRegistry 内部 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

项目地址:https://gitcode.com/gh_mirrors/do/docker-gitlab
点击查看免费下载
上一篇:Docker容器渗透测试工具:awesome-docker-security中的BOtB和Gorsair
下一篇:NuQS与React Window集成:虚拟列表状态URL

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询