离线部署Docker私有仓库:从registry.tar.gz到完整镜像分发服务

发布时间:2026/9/8 3:12:41
离线部署Docker私有仓库:从registry.tar.gz到完整镜像分发服务 简介面向无法连接外网环境的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 save和docker 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 runmkdir -p /opt/registry/data docker run -d \ --name registry \ --restartalways \ -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 push和docker pull都需要这个HTTP服务正常响应。3. 仓库配置与镜像流转3.1 推送镜像到私有仓库假设你在内网机器上有一个镜像myapp:1.0.0想放到仓库里直接docker push 192.168.1.100:5000/myapp:1.0.0是不行的必须先打tagdocker tag myapp:1.0.0 192.168.1.100:5000/myapp:1.0.0 docker push 192.168.1.100:5000/myapp:1.0.0tag的写法有讲究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.0和192.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 └── repositoriesblobs存放的是镜像层的实际内容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] }改完重启Dockersystemctl 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是数据存放点容器一删这个目录就跟着没了。判断方法很直接启动时看有没有-v或volumes配置。补救的办法也有但只能针对已删除容器做数据抢救利用Docker的存储机制去老容器目录里找数据是很麻烦的事不如一开始就养成挂卷的习惯。数据卷是容器安全的第一道防线这话真不是口号。4.4 镜像推上去之后tag版本对不上有时候你推了一个myapp:latest进仓库过了几天发现另一台机器拉下来的是旧的。其实不是仓库出了问题而是latest这个标签本身就是一个“移动标签”——每次push同名镜像都会覆盖。解决方式尽量用语义化版本号myapp:1.0.0、myapp:1.0.1这样避免用latest作为正式标签。仓库里的镜像越多版本管理的价值就越明显。一个人用的时候无所谓十个人同时用的时候一个latest就能把所有人折磨一遍。4.5 其他值得注意的点有几个容易被忽略的细节点我放在最后说docker load加载镜像的时间取决于文件大小和磁盘性能一个200MB的镜像在机械硬盘上可能需要一两分钟不要看到卡住就以为死机了。另外registry:2镜像本身是一个精简的Linux系统镜像不需要也不建议往里装调试工具要排查问题直接在宿主机上操作。最后如果内网机器架构不一样比如有x86也有ARM需要为每种架构单独打包镜像因为docker save导出的镜像不能跨架构使用。最后的经验分享做了这么多次离线交付我最大的体会是registry.tar.gz只是入口真正的复杂度都在细节里。版本锁定、哈希校验、数据卷挂载这些看起来“多做一步”的操作恰恰是现场少踩坑的关键。再分享一个后续扩展思路如果你有多台内网机器都需要访问同一个仓库可以在registry前面加一层Nginx做HTTPS终止和访问日志记录这样既解决了客户端HTTPS报错的问题也方便追溯谁在什么时候拉取了什么镜像。数据目录的定期备份脚本也可以加上打包后扔到内网的对象存储或另一台备份服务器上这样整个私有仓库的容灾链路才算完整。本文还有配套的精品资源点击获取