企业级 GPU 集群镜像管理方案:基于 Nexus 3 的读写分离、代理加速与自动化瘦身
一、 背景与痛点
在进行大规模 AI 平台开发(如构建大模型智能底座或 SaaS 平台)时,集群运维与研发团队通常面临以下挑战:
- 外网带宽与重连压力:AI 相关镜像(如
sglang、PyTorch、CUDA)体积巨大,动辄 10GB-30GB。在国内环境下,从 Docker Hub 拉取极易遇到TLS handshake timeout或速度过慢的问题。 - 重复带宽浪费:在一个多节点的 GPU 集群中,如果每台服务器都去外网拉取同一个镜像,不仅浪费出口带宽,还极易触发公网 Docker Hub 的访问频率限制(Rate Limit)。
- 磁盘空间危机:随着项目的快速迭代,由于 Docker 镜像的分层特性,那些被覆盖的旧标签(Untagged/Dangling Images)会堆积在本地仓库中,迅速耗尽物理机的高速磁盘。
二、 架构设计:读写分离与智能路由
由于 Docker 客户端 API 的设计机制,Nexus 的 Group(组合)仓库不支持直接发起 docker push 请求。因此,我们采用业界标准的**“读写端口分离”**架构:
- 端口 5000 (Hosted 仓库):作为**“私有写入口”**。仅用于研发人员推送(Push)内部自研镜像,数据绝对安全保密。
- 不暴露端口 (Proxy 仓库):作为**“外部缓存器”**。透明代理公网 Docker Hub,自动下载并本地缓存公网的大模型镜像。
- 端口 5001 (Group 仓库):作为**“全集群统一读入口”**。将 Hosted 和 Proxy 组合在一起。节点拉取(Pull)镜像时只需访问 5001 端口,Nexus 会智能按照
私有库 -> 本地缓存 -> 公网的顺序寻找并瞬间返回镜像。
三、 服务端部署与配置 (集群管理员操作)
1. 编写 docker-compose.yml 核心编排文件
在主管理节点创建基础设施目录,并编写纯净版的 Nexus 启动配置文件。
version: '3.8'
services:
# Nexus 3 制品库核心
nexus:
image: sonatype/nexus3:latest
container_name: dgx-nexus
restart: always
ports:
- "8081:8081" # Web 管理界面
- "5000:5000" # 私有镜像推送端口 (Write/Hosted)
- "5001:5001" # 组合镜像拉取端口 (Read/Group)
volumes:
# 数据目录务必挂载到大容量的高速 RAID 阵列上
- ./nexus-data:/nexus-data
environment:
# 针对大内存服务器,建议分配至少 4GB 堆内存
- INSTALL4J_ADD_VM_PARAMS=-Xms4g -Xmx4g -XX:MaxDirectMemorySize=4g
2. 目录权限修正与服务启动
Nexus 容器内部服务默认以 UID 200 运行,必须在宿主机手动赋予数据卷权限,否则会导致 Permission denied 报错。
mkdir -p ./nexus-data
sudo chown -R 200:200 ./nexus-data
docker compose up -d
3. Nexus 仓库初始化与高级路由配置
- 登录:访问
http://服务器IP:8081。获取初始密码:sudo cat ./nexus-data/admin.password。 - 第一步:创建私有库 (Hosted)
- 进入
Settings -> Repositories -> Create repository -> docker (hosted)。 - Name 设为
dgx-private,并在 HTTP Connector 勾选并填入5000。
- 第二步:创建代理缓存库 (Proxy)
- 创建
docker (proxy)。Name 设为docker-hub-proxy。 - HTTP Connector:留空(不填写)。
- Remote Storage 填写
https://registry-1.docker.io,并勾选Use Docker Hub。
- 第三步:创建大一统组合库 (Group)
- 创建
docker (group)。Name 设为dgx-unified-group。 - **HTTP Connector:勾选并填入
5001**。 - Member repositories:将
dgx-private和docker-hub-proxy移入右侧列表。 - ⚠️ 核心关键:使用上下箭头,确保
dgx-private排在第一位!这决定了 Nexus 会优先从内网私有库匹配镜像。
4. 核心优化:配置 5001 端口免密拉取 (匿名访问)
为了让集群内的所有节点在部署时无需繁琐地输入密码(特别利于自动化脚本),我们需要开启 Docker 的匿名拉取权限。请放心,私有的 5000 写入端口依然受到密码保护。
- 激活 Docker 令牌机制:进入
Security -> Realms,将Docker Bearer Token Realm移到右侧的 Active 列表中,保存。 - 开启全局匿名访问:进入
Security -> Anonymous,勾选Allow anonymous users to access the server,保存。 - 放行仓库拉取权限:进入
Repository -> Repositories,分别点开刚才创建的dgx-unified-group、docker-hub-proxy和dgx-private三个仓库。在它们的设置页面下方找到 Docker Registry API Support,勾选Allow anonymous docker pull,保存。
四、 集群节点接入配置(跨服务器访问)
为了避免后续主服务器 IP 变动导致整个集群的脚本失效,我们统一使用内部域名 dgx-hub.local 代替 IP。在集群中的每一台计算服务器上,执行以下配置:
1. 配置本地 DNS (Host)
# 将 192.168.x.x 替换为主仓库节点的实际内网 IP
sudo sh -c 'echo "192.168.x.x dgx-hub.local" >> /etc/hosts'
2. 配置 Docker 引擎信任列表
编辑 /etc/docker/daemon.json,信任我们的私有域名和端口:
{
"insecure-registries": [
"dgx-hub.local:5000",
"dgx-hub.local:5001"
]
}
执行重启使配置生效:sudo systemctl daemon-reload && sudo systemctl restart docker
五、 开发者使用规范与实战演练
接入完成后,请团队成员严格遵守**“5000 推,5001 拉”**的核心工作流。
场景 A:通过 5001 端口免密加速拉取外部镜像
5001 端口已配置为匿名拉取,任何节点可直接获取镜像。
⚠️ 核心避坑指南(关于官方顶层镜像):
当我们通过 Nexus 代理拉取 Docker Hub 的官方顶层镜像(如nginx、ubuntu等名字里没有斜杠的镜像)时,必须手动补全library/命名空间,否则会报错manifest unknown。
1. 拉取官方基础镜像(需加 library/):
# 第一次拉取 Nexus 会去外网下载并缓存,后续拉取将跑满内网带宽实现秒传
docker pull dgx-hub.local:5001/library/nginx:latest
2. 拉取第三方开源/AI 镜像(直接拉取,无需修改):
对于带有组织名的镜像(如大模型底座),直接使用即可:
docker pull dgx-hub.local:5001/lmsysorg/sglang:dev-cu13
场景 B:将自研业务推送到 5000 私有仓库
为了保证数据安全,5000 端口严禁匿名写入。向私有库推送镜像时,必须遵循“打标 -> 登录 -> 推送”的标准三步走流程。以内部系统(如 System-Mate 或 Cloudlong 业务)为例:
第 1 步:为镜像打上 5000 端口专属标签
告诉 Docker 我们要将这个镜像送往安全的写入端口:
docker tag system-mate-backend:v1 dgx-hub.local:5000/system-mate-backend:v1
第 2 步:登录私有金库(需进行身份校验)
直接 push 会报 unauthorized 错误,该机器首次推送前必须登录:
$ docker login dgx-hub.local:5000
Username: admin
Password: [输入管理员密码]
# 提示 Login Succeeded 即代表授权成功
第 3 步:正式推送入库
携带凭证后,即可极速推送到私有仓库:
$ docker push dgx-hub.local:5000/system-mate-backend:v1
The push refers to repository [dgx-hub.local:5000/system-mate-backend]
...
latest: digest: sha256:... size: 1778
场景 C:其他节点部署内部应用
你在 A 节点推送到 5000 端口后,B 节点拉取部署时,依然使用 5001 读端口(无需鉴权):
docker pull dgx-hub.local:5001/system-mate-backend:v1
六、 最佳实践:Nexus 镜像清理与空间释放策略 (Garbage Collection)
许多开发者在使用 Nexus 时会发现,即使在 UI 界面手动删除了某个镜像,服务器的物理磁盘空间依然没有减少。这是因为 Nexus 的 Docker 垃圾回收机制必须遵循特定的工作流。为了防止高频迭代项目的旧镜像撑爆磁盘,管理员必须在 Nexus 中按顺序设置以下三大自动化任务:
1. 创建清理策略 (Cleanup Policies)
策略用于界定“哪些镜像被视为过期可以删除”。
- 进入
Settings -> Repository -> Cleanup Policies。 - 点击 Create Cleanup Policy。Format 选择
docker。 - 设定规则:例如,填写
Published Before: 15 days(清理 15 天前发布的版本),同时可以在 Regex 中填写白名单排除特定标签(例如latest)。 - 回到
dgx-private仓库设置中,将这个策略应用到该仓库上。
2. 配置自动化调度任务 (Tasks)
仅有策略是不够的,您必须在 Settings -> System -> Tasks 中创建以下三个定时任务,且执行顺序极其重要:
- Admin - Cleanup repositories using their associated policies
- 作用:根据第一步的策略,将过期的镜像执行“软删除”(Soft delete)。
- 频率:建议设为每天凌晨
02:00。
- Docker - Delete unused manifests and images
- 作用:扫描 Docker 仓库,寻找那些不再被任何 Tag 引用的“悬空清单”(Dangling Manifests)并清理它们。
- 频率:建议设为每天凌晨
03:00。
- Admin - Compact blob store
- 作用:这是唯一能真正把物理硬盘空间还给宿主机的终极步骤。它会遍历底层的 Blob 存储,物理擦除那些经过软删除后遗留下来的数据块。
- 频率:建议设为每天凌晨
04:00。
只有完成了这三步的完整闭环,您的自建 Docker 仓库才能实现真正的“自我瘦身”,一劳永逸地解决大模型镜像带来的存储压力。
七、 总结
通过上述方案,您的 GPU 集群不仅获得了内网极速的镜像分发能力,还依托 Nexus 的 Proxy 缓存机制成功跨越了拉取外部大模型镜像时的网络鸿沟。结合域名解析、读写分离的规范流转,以及专业的 Garbage Collection 策略,整套基础设施真正达到了生产可用、免维护的状态。
更多推荐



所有评论(0)