离线部署Docker私有仓库:从registry.tar.gz到完整镜像分发服务
2026/9/8 3:12:34 网站建设 项目流程

简介:面向无法连接外网环境的Docker离线部署场景,这份Registry私有仓库镜像包能解决内网环境下镜像拉取与仓库搭建难题,适合企业运维人员与Docker初学者使用。压缩包共18个文件,约25.15MB,核心结构包含7个json元数据、5个layer层tar包、5个version版本记录及repositories仓库索引文件,完整保留镜像分层与配置信息,既可单独查看每层文件,也可直接加载为本地Registry镜像使用。已有436人学习下载,适用于离线安装、私有化部署。借助该压缩包,读者可在无外网环境快速导入Docker Registry,实现镜像的存储、推送与拉取,降低对外网依赖,同时可观察镜像分层组织方式,加深对Docker镜像存储机制的理解,是内网基础架构搭建的实用工具。 我先说个真实场景:你在客户现场搭Docker私有仓库,服务器在内网,没法直接docker pull官方镜像。这时候同事丢过来一个几百兆的registry.tar.gz,扔下一句“加载一下就能用”。如果你没接过这个活儿,大概率会卡在“怎么把tar.gz变成能用的仓库”这一步上。

这个包其实就是Docker官方镜像仓库registry:2的离线归档,用docker save打包后用gzip压缩而来。它解决的核心问题只有一个:在没有外网的环境里,快速恢复一个标准的镜像分发服务。适合所有要在内网搭仓库的运维、实施工程师,以及正在做离线交付的开发者。

1. 项目概述:一个tar.gz背后的完整逻辑

1.1 这个tar.gz到底是什么

先说清楚,registry.tar.gz不是registry的源码包,也不是安装脚本,它是Docker镜像的导出归档。Docker里有一个专门用来保存和分发镜像的服务,官方镜像就叫registry,我们平时说的“私有仓库”“镜像仓库”基本都是它。

正常的在线部署方式是这样的:

docker run -d -p 5000:5000 --name registry registry:2

但内网机器拉不了这个镜像,所以需要在有网环境先把镜像打出来,带进内网。打包命令就两个:

docker pull registry:2 docker save registry:2 | gzip > registry.tar.gz

拿到手的registry.tar.gz,本质上就是一个包含了Docker镜像层数据的压缩包。到了内网机器上执行docker load,就把镜像恢复到本地Docker里,接下来再用docker run启动这个镜像,一个私有仓库就跑起来了。

1.2 离线部署方案的选型考量

2024年之后再来看“离线装仓库”,至少有几种做法,但绝大多数场景下save/load这个方案依然是最稳的。

方案优点缺点适用场景
机器直连网络安装简单,一步到位内网环境不适用开发测试机
构建机导出tar包离线可用,文件体积可控镜像与运行环境绑定,需要明确平台架构同架构内网集群
docker save打包镜像操作简单,恢复快,版本固定需要手动管理传输过程离线交付、现场实施
搭建内网yum源/apt源能覆盖所有依赖包搭建复杂,维护成本高大规模裸机集群

一个容易被忽略的点是docker savedocker export的区别。前者作用于镜像,导出的是完整的镜像层和元数据,load回来还能保留版本号、Entrypoint这些信息;后者作用于容器,导出的是容器当前的文件系统,load回来会丢失镜像的构建信息,不能算是“镜像”。离线部署仓库必须用save/load这条链路。

1.3 搞定它能解决什么

registry.tar.gz玩明白,你得到的不仅仅是“能启动一个容器”,而是一整套离线镜像分发能力:你可以把应用镜像打成app.tar.gz带进内网,推到这个私有仓库里,内网所有机器统一从它拉取。这样既避免了每台机器单独传镜像,也方便做版本管控。

这个项目适合谁来参考?负责内网系统交付的实施工程师、DevOps平台搭建者、还在用docker load痛苦地一台台传镜像的人。

2. 完整实操:从tar.gz到可用仓库

2.1 在有网环境准备registry.tar.gz

打包前先确定版本。很多人习惯直接docker pull registry:2,这样拉下来的是当前时间点的最新2.x版本,今天是2.8.3,过几个月可能变成2.9.x。离线环境里版本一旦固定就不会变了,所以建议直接锁版本:

docker pull registry:2.8.3 docker save registry:2.8.3 | gzip > registry-2.8.3.tar.gz

这里有个细节:docker save的输出可以走管道直接给gzip,不用先存一个未压缩的tar文件。未压缩的registry:2.8.3镜像大概在250MB左右,gzip之后能压到80~90MB,传输速度能快不少。

打包完成后,强烈建议记一下文件的SHA256值:

sha256sum registry-2.8.3.tar.gz

内网机器load完再算一次,两边一致再往下走。这个动作看起来多余,但现场交付时如果出现镜像损坏、加载失败,哈希可以帮你快速判断是传输问题还是文件问题。

2.2 内网导入镜像

把tar.gz文件传到内网机器后,执行:

docker load -i registry-2.8.3.tar.gz

输出末尾会出现一行Loaded image: registry:2.8.3,说明镜像已经进入本地镜像库。执行docker images | grep registry确认一下。

很多人在这里会踩一个坑:docker load会把镜像文件解压到Docker的数据目录(通常是/var/lib/docker),如果这个目录所在磁盘空间不足,会出现no space left on device。所以加载前先检查:

df -h /var/lib/docker

如果空间不够,优先清理旧镜像和构建缓存,docker system prune -a是好工具,但要注意它会把所有未被容器使用的镜像删掉,执行前确认不影响现有服务。

2.3 启动registry容器

加载完镜像,启动方式有两种。临时验证用docker run

mkdir -p /opt/registry/data docker run -d \ --name registry \ --restart=always \ -p 5000:5000 \ -v /opt/registry/data:/var/lib/registry \ registry:2.8.3

生产环境建议用docker-compose.yml管理:

version: '3' services: registry: image: registry:2.8.3 container_name: registry restart: always ports: - "5000:5000" volumes: - /opt/registry/data:/var/lib/registry

启动后用docker ps检查状态,然后测试一下仓库的HTTP接口:

curl http://127.0.0.1:5000/v2/

正常返回{},说明registry已经工作。这一步为什么重要?因为后面所有内网机器的docker pushdocker pull都需要这个HTTP服务正常响应。

3. 仓库配置与镜像流转

3.1 推送镜像到私有仓库

假设你在内网机器上有一个镜像myapp:1.0.0想放到仓库里,直接docker push 192.168.1.100:5000/myapp:1.0.0是不行的,必须先打tag:

docker tag myapp:1.0.0 192.168.1.100:5000/myapp:1.0.0 docker push 192.168.1.100:5000/myapp:1.0.0

tag的写法有讲究:192.168.1.100:5000是仓库地址,后面的myapp:1.0.0是镜像名和标签。Docker根据这个地址判断推送目标,如果地址不带端口,默认推送到Docker Hub。

多台机器拉取也一样:

docker pull 192.168.1.100:5000/myapp:1.0.0

这里我之前犯过一个错误:把镜像推上仓库之后,本地镜像还在,结果过了一段时间发现本地镜像和仓库里的镜像不一致,排查了半天,最后才反应过来是忘了在推送前重新tag和push。你可以在docker images里看到两个条目:myapp:1.0.0192.168.1.100:5000/myapp:1.0.0,后者才是仓库里的版本。

3.2 存储布局与数据持久化

registry容器内部存放镜像数据的路径是/var/lib/registry,在docker run里用-v把它挂载到了宿主机的/opt/registry/data。这样做的好处是:容器删除、升级、崩溃重建,镜像数据都还在。

数据目录里是标准的Docker Registry存储结构:

/opt/registry/data └── docker └── registry └── v2 ├── blobs └── repositories

blobs存放的是镜像层的实际内容,repositories存放的是镜像名、标签和索引信息。如果你手工去翻这个目录,会发现所有文件按sha256散列存储,没有直观的文件名,这很正常,不用慌。

备份时就拷贝这个目录:

tar czf registry-data-backup.tar.gz /opt/registry/data

恢复时把目录解压回去,再启动registry容器,镜像都在。这个操作在处理“仓库迁移”时特别有用。

3.3 加认证与TLS配置

如果你只是内网内部用,HTTP+无认证是能运行的,但一旦涉及多团队协作,建议至少加一层密码认证。用htpasswd生成密码文件:

docker run --rm --entrypoint htpasswd registry:2.8.3 -Bbn admin '你的密码' > htpasswd

然后把htpasswd文件挂进容器,并加上环境变量:

version: '3' services: registry: image: registry:2.8.3 container_name: registry restart: always ports: - "5000:5000" environment: REGISTRY_AUTH: htpasswd REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd volumes: - /opt/registry/data:/var/lib/registry - /opt/registry/auth:/auth

配置认证之后,所有机器的docker login 192.168.1.100:5000都需要输入账号密码。这是最基础的访问控制,虽然挡不住所有场景,但已经是内网环境里性价比极高的安全措施。

4. 常见问题与排查技巧实录

4.1 推送时报错:http: server gave HTTP response to HTTPS client

这是离线部署中最常见的报错,没有之一。原因很简单:Docker客户端默认用HTTPS访问仓库,而你的registry只起了HTTP服务。

解决思路有两个。如果你内网没有被劫持风险且追求便利,在需要访问仓库的机器上修改/etc/docker/daemon.json

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

改完重启Docker:

systemctl restart docker

注意,重启Docker会导致该机器上所有容器重启,生产环境机器要提前通知窗口。另一个思路是给registry配TLS证书,走HTTPS访问,这样不用在每个客户端做配置,但需要统一的证书分发机制,内网维护成本会高一些。我个人的建议是:如果只是临时交付,insecure-registries最快;如果要做长期基础设施,就上TLS。

4.2 docker load时报no space left on device

这个报错我之前遇到过好几次,每次都是因为/var/lib/docker所在分区满了。注意,docker load不只是解压tar.gz到磁盘,它还会额外占用一部分空间用于临时文件和索引。如果几台机器都在同时加载大镜像,磁盘很容易被打满。

排查命令:

df -h docker system df

解决方式很直接:清空间再load。我一般优先清理悬空镜像和无效缓存:

docker image prune -f docker builder prune -f

如果还是不够,检查Docker的>{ "data-root": "/data/docker" }

改完同样需要重启Docker。

4.3 容器删了之后,镜像数据全没了

这个坑特别典型。有人用docker run -d -p 5000:5000 registry:2这样“裸跑”启动仓库,容器本身工作很正常,push、pull都成功。但某天容器异常退出,运维人员一慌直接docker rm,再启动一个新容器,发现之前推送的所有镜像都不见了。

原因就是没挂数据卷。registry镜像的/var/lib/registry是数据存放点,容器一删,这个目录就跟着没了。

判断方法很直接:启动时看有没有-vvolumes配置。补救的办法也有,但只能针对已删除容器做数据抢救,利用Docker的存储机制去老容器目录里找数据是很麻烦的事,不如一开始就养成挂卷的习惯。数据卷是容器安全的第一道防线,这话真不是口号。

4.4 镜像推上去之后,tag版本对不上

有时候你推了一个myapp:latest进仓库,过了几天发现另一台机器拉下来的是旧的。其实不是仓库出了问题,而是latest这个标签本身就是一个“移动标签”——每次push同名镜像都会覆盖。

解决方式:尽量用语义化版本号,myapp:1.0.0myapp:1.0.1这样,避免用latest作为正式标签。仓库里的镜像越多,版本管理的价值就越明显。一个人用的时候无所谓,十个人同时用的时候,一个latest就能把所有人折磨一遍。

4.5 其他值得注意的点

有几个容易被忽略的细节点,我放在最后说:

docker load加载镜像的时间取决于文件大小和磁盘性能,一个200MB的镜像在机械硬盘上可能需要一两分钟,不要看到卡住就以为死机了。另外,registry:2镜像本身是一个精简的Linux系统镜像,不需要也不建议往里装调试工具,要排查问题直接在宿主机上操作。最后,如果内网机器架构不一样,比如有x86也有ARM,需要为每种架构单独打包镜像,因为docker save导出的镜像不能跨架构使用。

最后的经验分享

做了这么多次离线交付,我最大的体会是:registry.tar.gz只是入口,真正的复杂度都在细节里。版本锁定、哈希校验、数据卷挂载,这些看起来“多做一步”的操作,恰恰是现场少踩坑的关键。

再分享一个后续扩展思路:如果你有多台内网机器都需要访问同一个仓库,可以在registry前面加一层Nginx做HTTPS终止和访问日志记录,这样既解决了客户端HTTPS报错的问题,也方便追溯谁在什么时候拉取了什么镜像。数据目录的定期备份脚本也可以加上,打包后扔到内网的对象存储或另一台备份服务器上,这样整个私有仓库的容灾链路才算完整。

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

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

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

立即咨询