☰
离线环境部署Docker私有镜像仓库:registry.tar.gz实战与避坑指南
2026/10/12 16:12:53 网站建设 项目流程

简介:本资源为面向内网离线环境的Docker Registry镜像包,主要解决服务器无法连接外网时私有仓库难以搭建的问题,适合运维人员、后端开发者及需要隔离网络部署容器镜像的团队使用。压缩包共包含18个文件,以json元数据、tar层文件、version版本标识及repositories索引为主,整体约25.15MB,结构符合Docker镜像分层存储规范,可直接导入本地Registry服务。目前已有436人学习下载,说明其在离线部署场景中具有一定参考价值。借助该镜像包,读者能够在内网快速完成私有仓库的初始化与镜像推送,避免因外网受限而中断容器化流程,同时可结合分层文件理解镜像的存储与索引机制,为后续镜像迁移、备份及仓库维护提供可复用的基础素材。

1. 从 registry.tar.gz 说起:离线环境里把镜像仓库搬回家

如果你在机房、产线或者客户内网里干过交付,大概率遇到过这种场面:服务器没有外网,Docker 镜像拉不下来,docker pull转圈转到天荒地老,最后甩给你一个connection timed out。这时候手里如果有一个registry.tar.gz,事情就完全不一样了——它本质上是把一整套私有镜像仓库(Registry)打包成了一个压缩包,解压、加载、起容器,几分钟内就能在内网里跑起一个能推能拉的镜像仓库。

这份资源解决的核心问题就一个:在没有外网的环境里,让 Docker 镜像的存储和分发重新跑起来。它适合三类人:一是做离线交付的运维和交付工程师,二是需要在隔离网络里搭 CI/CD 的开发者,三是想在自己机器上研究 Registry 行为、不想依赖公网的技术人。下面我从这个包怎么用、参数怎么调、坑在哪,一步步拆开讲。

2. 拆包与加载:registry.tar.gz 里到底装了什么

拿到一个registry.tar.gz,第一反应不应该是直接解压,而是先看清楚它的结构。不同来源的包,内容差别很大:有的里面是一个完整的registry二进制加配置文件,有的是一份docker save出来的镜像 tar 包,还有的是把镜像 tar 再套一层 gzip。搞错了结构,后面的命令全是白费。

2.1 先看包结构再动手

我一般会先用tar -tzf列出内容,不急着解压。这一步能帮你判断这个包属于哪种类型:

# 只列出压缩包内容,不解压,先看结构 tar -tzf registry.tar.gz | head -30 # 常见输出一:直接是镜像 tar # registry.tar # # 常见输出二:带目录结构 # registry/ # registry/registry # registry/config.yml

如果输出里只有一个.tar文件,那它多半是docker save导出的镜像归档,需要先解压再docker load。如果输出里有config.yml和二进制文件,那它是一套可以直接运行的 Registry 程序,走的是另一条路。这两种情况后面的处理方式完全不同,所以第一步的判断不能省。

提示:head -30只是看开头,如果包很大,别用tar -tzf反复扫,扫一次把结果存到文件里,后面查起来快。

2.2 镜像归档型:docker load 的正确姿势

假设确认里面是镜像 tar,标准流程是解压再加载。这里有个细节很多人忽略:docker load加载出来的镜像名和标签,取决于打包时docker save用的名字,不是你想改就能在 load 阶段改的。

# 解压出内层 tar tar -xzf registry.tar.gz # 加载镜像到本地 Docker docker load -i registry.tar # 查看加载结果,确认 REPOSITORY 和 TAG docker images | grep registry

docker load -i的-i指定输入文件,加载完成后用docker images核对。如果加载出来的镜像名是registry:2或registry:latest,说明这是一个标准的 Registry 镜像。如果名字是一串<none>,那说明打包时镜像没有打标签,需要手动docker tag补一个名字再用。

参数上唯一需要留意的是:docker load不支持在加载时重命名,所以标签管理要在 load 之后做。另外,如果内层 tar 很大(几个 GB),加载过程会占满磁盘 IO,别在业务高峰期干这事。

2.3 程序目录型:直接跑二进制还是起容器

如果包里是registry二进制加config.yml,你有两个选择:直接跑二进制,或者把它做成镜像再起容器。直接跑二进制最省事,适合临时用:

# 解压 tar -xzf registry.tar.gz # 前台启动,方便看日志 ./registry serve config.yml

serve是 Registry 的子命令,后面跟配置文件路径。前台启动的好处是日志直接打在终端上,排错方便;确认没问题后再用nohup或 systemd 托管。如果选择容器方式,就需要先写 Dockerfile 把二进制和配置打进去,多一步但更干净。两种方式没有绝对优劣,临时验证用二进制,长期运行用容器。

3. 把 Registry 跑起来:配置、存储与端口映射

包能加载只是第一步,真正让 Registry 可用,靠的是配置文件里的几个关键参数。很多人跑起来之后发现推不上去、拉不下来,八成是config.yml没配对。这一章把配置拆开讲,每个参数说清楚它管什么。

3.1 config.yml 里必须搞懂的四个字段

一份典型的 Registry 配置长这样,我把它精简到最核心的部分:

version: 0.1 storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true http: addr: :5000 headers: X-Content-Type-Options: [nosniff]

version是配置格式版本,固定写0.1,别改。storage.filesystem.rootdirectory是镜像数据实际落盘的位置,这个目录会随着推送的镜像越来越多而膨胀,务必挂到大盘上。storage.delete.enabled设为true才允许删除镜像,默认是关的,不打开的话你删了标签空间也不会释放。http.addr是监听地址,:5000表示监听所有网卡的 5000 端口。

注意:delete.enabled打开只是允许删除操作,真正回收空间还需要跑垃圾回收(garbage-collect),这两步是分开的,后面会讲。

3.2 用容器方式启动并挂载数据卷

如果走容器路线,启动命令里最关键的是数据卷映射。镜像数据不能放在容器内部,否则容器一删全没了:

# 启动 Registry 容器 docker run -d \ --name registry \ --restart=always \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ -v /data/registry-config/config.yml:/etc/docker/registry/config.yml \ registry:2

-p 5000:5000把容器端口映射到宿主机,内网其他机器通过宿主机IP:5000访问。-v /data/registry:/var/lib/registry是数据持久化的关键,左边是宿主机目录,右边要和配置文件里的rootdirectory一致。--restart=always保证宿主机重启后 Registry 自动起来,离线环境里没人盯着,这个参数很实用。

启动后用docker ps确认容器状态,再用curl探一下:

# 探测 Registry 是否存活 curl -s http://127.0.0.1:5000/v2/ # 正常返回:{}

返回{}说明 Registry 的 API 正常响应了。如果返回连接拒绝,检查容器是否真的起来了;如果返回 404,检查端口映射对不对。

3.3 客户端配置:让 docker 信任这个仓库

Registry 默认走 HTTP,而 Docker 客户端默认要求 HTTPS,所以直接推会报http: server gave HTTP response to HTTPS client。解决办法是在客户端的daemon.json里把它加进信任列表:

{ "insecure-registries": ["192.168.1.100:5000"] }

把192.168.1.100换成你 Registry 所在机器的实际 IP。改完重启 Docker 服务:

# 重启 Docker 使配置生效 systemctl restart docker

这一步是离线环境里最容易翻车的地方。很多人 Registry 起得好好的,一推就报错,就是忘了配insecure-registries。配完之后,打标签、推送、拉取就顺了:

# 给本地镜像打上私有仓库标签 docker tag nginx:latest 192.168.1.100:5000/nginx:latest # 推送到私有仓库 docker push 192.168.1.100:5000/nginx:latest # 从私有仓库拉取 docker pull 192.168.1.100:5000/nginx:latest

标签格式是仓库地址/镜像名:标签,缺一不可。推送成功后,数据就落在/data/registry下面了,可以用du -sh看增长情况。

4. 避坑与排查:Registry 离线部署的五个血泪经验

这一章是我自己踩过的坑,每条都按「现象 → 原因 → 解决」写。离线环境没有外网兜底,出了问题只能自己扛,所以这些经验比命令本身更值钱。

4.1 推送报 413:请求体过大

现象:小镜像推得上去,大镜像推到一半报413 Request Entity Too Large。

原因:如果 Registry 前面挂了 Nginx 做反向代理,Nginx 默认的client_max_body_size是 1MB,超过就拦。即使没挂 Nginx,某些版本的 Registry 也有默认限制。

解决:在 Nginx 配置里加client_max_body_size 0;(0 表示不限制),重启 Nginx。如果没挂代理,检查 Registry 配置里有没有maxuploadsize之类的限制项。

4.2 删除镜像后空间不释放

现象:用 API 删了镜像,docker images里也没了,但/data/registry目录大小纹丝不动。

原因:Registry 的删除是「标记删除」,blob 数据还在磁盘上,需要手动跑垃圾回收才能真删。

解决:先确保delete.enabled: true,然后停掉 Registry(或进入容器),执行:

# 进入容器执行垃圾回收 registry garbage-collect /etc/docker/registry/config.yml

回收完成后再启动 Registry。注意回收期间不要有推送操作,否则可能误删正在使用的层。

4.3 重启后镜像全没了

现象:容器重启一次,之前推的镜像全消失,/v2/_catalog返回空。

原因:启动容器时没挂数据卷,或者挂载路径和rootdirectory不一致,数据写在了容器内部,容器一重建就丢。

解决:docker inspect registry看Mounts字段,确认/var/lib/registry确实映射到了宿主机目录。没映射的话,停容器、加-v重新起,之前的数据如果还在容器里可以docker cp出来。

4.4 客户端报证书错误

现象:docker push报x509: certificate signed by unknown authority或server gave HTTP response to HTTPS client。

原因:客户端没把 Registry 加入insecure-registries,或者加了但没重启 Docker。

解决:确认daemon.json里的 IP 和端口与实际一致,改完必须systemctl restart docker。如果用了域名,域名也要加进去。改完用docker info看Insecure Registries列表里有没有你的地址。

4.5 磁盘写满导致 Registry 假死

现象:Registry 容器还在跑,但推送一直卡住,日志里报no space left on device。

原因:rootdirectory所在分区被镜像数据撑满,Registry 无法写入新数据。

解决:先清理无用镜像并跑垃圾回收,长期方案是把数据目录迁到大容量分区,或者加监控告警。离线环境里磁盘满了没人通知,等发现时业务已经停了,所以提前规划容量比事后救火重要。

5. 进阶技巧:用 API 管理仓库和验证数据完整性

Registry 跑起来只是开始,真正让它好用,得会通过 API 查目录、删镜像、验证数据。这一章讲几个我常用的操作,都是命令行能直接抄的。

5.1 用 _catalog 接口列出所有仓库

Registry 提供了 REST API,最常用的是_catalog,能列出所有仓库名:

# 列出所有仓库 curl -s http://192.168.1.100:5000/v2/_catalog # 返回示例:{"repositories":["nginx","redis","myapp"]}

如果仓库多,可以加分页参数?n=10限制返回数量。这个接口在排查「镜像到底推没推上去」时特别有用,比翻磁盘目录直观。

5.2 查标签和删镜像

知道仓库名后,可以查它的标签列表:

# 列出某个仓库的所有标签 curl -s http://192.168.1.100:5000/v2/nginx/tags/list # 返回示例:{"name":"nginx","tags":["latest","1.21"]}

删除某个标签对应的镜像,需要先拿到 digest:

# 获取镜像的 digest curl -s -I \ -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \ http://192.168.1.100:5000/v2/nginx/manifests/latest \ | grep Docker-Content-Digest # 用 digest 删除 curl -X DELETE http://192.168.1.100:5000/v2/nginx/manifests/sha256:xxxx

-I只取响应头,Docker-Content-Digest就是 digest 值。删除后记得跑垃圾回收,否则空间不释放。这套 API 操作在写自动化脚本时很有用,比如定时清理过期镜像。

5.3 验证数据完整性

离线环境里数据损坏是隐性风险,我一般会定期验证。最简单的方式是拉一个镜像下来,和源端对比 digest:

# 拉取镜像并查看 digest docker pull 192.168.1.100:5000/nginx:latest docker inspect --format='{{index .RepoDigests 0}}' 192.168.1.100:5000/nginx:latest

把输出的 digest 和推送时的 digest 对比,一致说明数据没坏。如果对不上,说明存储层可能出了问题,需要检查磁盘健康状态。这个习惯帮我提前发现过一次磁盘坏道,避免了交付现场翻车。

从那以后我每次部署完 Registry,都会强制走一遍「推一个测试镜像 → 拉下来 → 对比 digest → 删掉测试镜像 → 跑垃圾回收」的完整流程,确认整条链路通了才交给业务用。希望这些经验帮到你,少走几个我踩过的坑。

本文还有配套的精品资源,点击获取

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

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

立即咨询