ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

离线交付实践:用registry.tar.gz搭建私有镜像仓库避坑指南

离线交付实践:用registry.tar.gz搭建私有镜像仓库避坑指南 简介这是一份面向无法连接外网环境的Docker Registry镜像资源包适用于企业内网或隔离网络快速搭建私有镜像仓库无需访问外部镜像仓库即可在受限网络中自助完成镜像分发与版本管理满足本地镜像离线部署需求。包内是基于官方Registry生成的完整镜像数据共18个文件其中7个json文件记录镜像构建配置与层间关联5个layer.tar保存实际镜像层数据5个VERSION标识各层版本另有repositories维护仓库与镜像标签的映射关系压缩包整体约25.15MB结构清晰可直接用于内网镜像导入与仓库初始化。资源下载量已达436人对刚接触Docker私有仓库搭建的运维人员来说是一份轻量且实用的离线素材。通过该包可省去外网拉取镜像的步骤配合内网环境即可完成基础Registry服务部署同时也可作为理解Docker镜像分层结构及元数据组织的参考样例。1. 拿到 registry.tar.gz 只是第一步离线镜像仓库的完整落地链路做内网交付时最常碰到的就是「服务端连不上外网但又要部署一套带镜像的私有仓库」。这个时候registry.tar.gz就是一个已经被压缩好的 Docker Registry 离线镜像包。很多人以为把它拷过去、docker load一下就算完事结果启动容器之后一推镜像就被http: server gave HTTP response to HTTPS client卡住或者容器重启后镜像全部消失。问题不在包本身而在对 Registry 镜像的启动参数和客户端侧的配置缺乏理解。这份资源解决的核心问题是在没有公网的环境里用registry.tar.gz快速搭建一个可用的私有镜像仓库并且让docker push、docker pull走的通。适合在内网部署、离线交付、灾备迁移场景下手动操作 Docker Registry 的工程师——尤其是那些对docker save/docker load只停留在命令层面没有真正处理过镜像层结构和仓库配置的人。2. 从拉取到压缩把 registry:2 做成 tar.gz 的标准链路2.1 为什么选 registry:2 而不是 docker/distribution先把镜像选择这件事说清楚。当前 Docker Registry 的官方镜像标签是registry:2对应的上游项目就是docker/distribution最新版本已经整合到distribution/distribution。你会发现 Docker Hub 上还有一个叫docker/distribution的镜像但从 2.8 版本之后官方推荐的就是registry:2原因在于它基于alpine基础镜像构建体积更小而且修复了多个存储驱动相关的安全漏洞。我在离线交付时通常只用registry:2这个 tag而不是registry:latest。原因很简单latest会随上游更新变化离线环境下你无法控制docker pull的行为一旦某天镜像内容发生不兼容变更你在目标机上复现的仓库行为就和本地不一致。固定 tag 本质上是给整个交付链路加了一把锁。另外有人说可以用docker export把容器打成 tar再导入成镜像。这是典型的概念混淆。docker save保存的是镜像层包含完整的元数据和层信息导入后可以继续作为镜像来rundocker export导出的是容器文件系统快照丢掉了镜像的历史层和入口配置导入后不能再保留原有镜像结构不适合作为 registry 镜像的交付格式。2.2 save → gzip → 传输每一步的命令和参数含义先在联网机器上把镜像拉下来然后打包压缩。整个链路如下docker pull registry:2 docker save registry:2 -o registry.tar gzip -k registry.tar这里说明一下三个命令各自的职责。第一条docker pull把镜像从 Docker Hub 拉到本地镜像仓库如果本地已经存在同名的旧版本可以加--platform linux/amd64强制拉取指定平台架构的镜像避免在多架构环境下拿到错误的arm64版本。第二条docker save的参数-o指定输出文件路径默认会保存为未压缩的 tar 格式。第三条gzip -k中的-k保留原始文件只生成registry.tar.gz。我在实际交付时不会直接对 tar 做流式压缩而是先落盘再压缩因为流式操作出错时排查难度更大。比如以下命令虽然一行搞定docker save registry:2 | gzip registry.tar.gz但如果传输中断你无法判断到底是 save 阶段还是 gzip 阶段出了问题。分步执行的好处是每一步的产物都可以独立校验比如gzip -t registry.tar.gz验证压缩包完整性docker load -i registry.tar验证镜像 tar 的可用性。这对离线交付来说非常重要因为你大概率不会在目标环境重来一遍。2.3 在目标机上 load镜像层与 tag 的恢复逻辑目标机上执行docker load -i registry.tar.gz等一下很多人在这里会翻车。docker load并不支持直接读取 gzip 压缩文件它期望的输入是未压缩的 tar 格式。某些高版本 Docker 会自动探测并解压但这不是所有版本都支持的行为。稳妥的做法是先解压再导入gunzip registry.tar.gz docker load -i registry.tar导入完成后用docker images | grep registry确认镜像是否存在。这里有第二个翻车点docker load之后镜像的完整名称是registry:2还是library/registry:2取决于保存时镜像的原始 tag。如果docker save时用的命令是docker save registry:2那么映像的 Repository 就是registryTag 是2。如果你看到的是docker.io/library/registry:2不用紧张那只是 Docker 默认的命名空间前缀不影响docker run registry:2的执行。3. 目标机容器化部署从 docker run 到 Registry 服务对外可用3.1 目录规划与容器启动参数镜像导入只是开始。要让 Registry 真正服务外部客户端必须正确配置容器参数。我习惯在部署前先建立一个宿主机的数据目录比如/data/registry用来存放仓库的镜像数据。mkdir -p /data/registry docker run -d \ --name registry \ --restartalways \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ -e REGISTRY_STORAGE_DELETE_ENABLEDtrue \ registry:2逐项说明这些参数的含义。-d后台运行容器--restartalways保证机器重启后 Registry 容器能自动拉起这是离线环境下最省心的配置——不用写 systemd 服务来守护容器-p 5000:5000把宿主机 5000 端口映射到容器内部的 5000 端口Registry 默认监听 5000-v /data/registry:/var/lib/registry是关键/var/lib/registry是 Registry 容器内部存储镜像的默认路径如果不挂载宿主目录容器删除后所有镜像会随之消失REGISTRY_STORAGE_DELETE_ENABLED这个环境变量用于开启镜像删除能力如果预见到以后需要清理不用的仓库建议一开始就打开否则外层 API 会返回 405。3.2 自检清单验证容器是否真的提供服务容器启动后不要急着跳到客户端配置。先做一组自检确认容器内部的服务链路是通的。docker ps | grep registry curl -v http://127.0.0.1:5000/v2/ docker logs --tail 50 registry第一条命令确认容器处于Up状态。第二条命令访问 Registry 的 v2 API 根路径如果返回200 OK且响应体为空说明服务正常如果连接被拒绝先看映射端口是否被占用再检查容器日志。第三条命令是排障的核心手段——docker logs会输出 Registry 的访问日志和错误信息比如http: server gave HTTP response to HTTPS client这类问题在服务端日志里也会留下痕迹。这里要额外说明外网场景的端口问题。如果你的宿主机在云环境或者公司防火墙之后127.0.0.1通不代表外网 IP 通。你需要检查云平台安全组、iptables 和 firewalld 对 5000 端口的放行策略。常见做法是firewall-cmd --permanent --add-port5000/tcp firewall-cmd --reload但注意在裸机部署时很多生产环境是没有 firewalld 的你需要确认你的发行版和初始化工具链。我见过有人在 CentOS 7 上配了 firewalld 规则依然不通最后发现是云平台安全组没放行也有人反过来安全组放行了但本机 firewalld 没开导致局域网其他机器访问失败。结合ss -lntp | grep 5000和curl http://宿主机IP:5000/v2/两条命令一起看能快速缩小问题范围。4. 客户端对接与私有仓库配置push/pull 联调全流程4.1 insecure-registries 的真正含义Registry 容器本身已经跑起来了但客户端docker push到私有仓库还会默认拒绝。原因是 Docker 客户端对所有非 HTTPS 的私有仓库地址默认不信任除非你在配置里显式声明。编辑/etc/docker/daemon.json{ insecure-registries: [192.168.1.100:5000] }这里的关键点是数组中的地址必须包含端口号或者写为 CIDR 形式如[192.168.1.0/24]。配完之后需要重启 Docker 守护进程systemctl restart docker注意daemon.json配置的是 Docker 客户端所在机器的配置而不是 Registry 服务器所在机器的配置。如果其他开发机也要向这个仓库推送镜像每台机器都要各自配置。这是很多初学者的认知盲区他们会只在一台机器上改配置然后换一台机器推送时又提示 HTTPS 错误。为什么我用insecure-registries而不是给这一台机器配自签证书内网环境配 CA 证书的流程复杂需要为每台客户端分发证书文件而且证书过期是一个持续的运维负担。对一个内部使用的仓库来说insecure-registries是对管理与便捷性妥协后的现实选择。如果你想在生产环境做到全链路加密就去用certbot或自建 CA 签证书然后配置REGISTRY_HTTP_TLS_CERTIFICATE和REGISTRY_HTTP_TLS_KEY环境变量。4.2 从 docker tag 到 push一条完整的验证链路配置完成后随便拿一个本地镜像测试。docker pull hello-world docker tag hello-world 192.168.1.100:5000/hello-world:v1 docker push 192.168.1.100:5000/hello-world:v1执行docker tag的目的是让镜像名带上仓库地址前缀Docker 会将仓库地址/镜像名:tag解析为一次推送目标。有人会问为什么不能直接docker push 192.168.1.100:5000/hello-world这个问题的答案是 Docker Hub 默认仓库不允许你自定义地址前缀——实际上少打 tag 这条命令push 的结果就是把镜像推到了 Docker Hub而不是你的私有仓库。推送完成后在 Registry 服务器上验证仓库里的数据curl http://127.0.0.1:5000/v2/_catalog curl http://127.0.0.1:5000/v2/hello-world/tags/list第一条命令返回仓库内所有镜像的列表{repositories:[hello-world]}就是成功了。第二条命令返回这个镜像下所有的 tag。这两条 API 是排查问题时最常用的也很适合写进你的发布脚本里做冒烟验证。5. 避坑笔记离线交付 registry.tar.gz 最常见的五个翻车现场5.1 docker load 毫无输出镜像也不出现现象执行docker load -i registry.tar后命令很快结束但docker images里找不到registry这个镜像。原因tar 文件中并没有包含镜像数据或者被负载时的镜像名不是预期值。一种常见场景是打包时使用了docker export而非docker save导致 tar 内部没有镜像层的 MANIFEST 文件另一种是从别人那里拷贝的 tar 包实际内容已经是镜像 ID而不是仓库名加 tag 的映射。解决先tar -tf registry.tar查看文件内部结构确认是否存在manifest.json和repositories文件。如果没有说明打包方式有问题需要重新用docker save。如果结构正常但 tag 不对用docker images --no-trunc查看镜像 ID再手动docker tag。5.2 curl 127.0.0.1 通局域网不通现象在 Registry 宿主机上执行curl http://127.0.0.1:5000/v2/正常但另一台机器访问http://192.168.1.100:5000/v2/连接超时。原因宿主机上的服务正常监听但流量在防火墙或者安全组被拦截。云环境最常见裸机环境则需要检查 iptables。解决按从物理到逻辑的顺序排查——先 ping 宿主机确认网络通再用ssh登录宿主机执行ss -lntp | grep 5000确认监听地址是否为0.0.0.0:5000或[::]:5000最后检查iptables -L INPUT -n或云平台安全组。值得注意的是docker默认会往iptables的DOCKER链里加规则如果手动改过默认策略可能影响到端口转发。5.3 push 时提示 http: server gave HTTP response to HTTPS client现象客户端推送镜像报错http: server gave HTTP response to HTTPS client。原因仓库地址没有配置到insecure-registries或者配置后没有重启 Docker 守护进程。Docker 客户端对非 HTTPS 的私有地址默认采取拒绝策略。解决在客户端/etc/docker/daemon.json的insecure-registries数组中补上仓库地址重启 Docker。这里有一个细节不要重启 Registry 容器只重启客户端守护进程就够了。很多人会习惯性重启仓库浪费时间且无意义。5.4 registry 容器删掉后镜像没了现象容器因为某种原因被docker rm或机器重启后curl /v2/_catalog返回空列表仓库数据丢失。原因启动容器时没有挂载/var/lib/registry数据卷或者挂载了但目录不对。本地镜像数据实际存放在容器可写层容器消失就没了。解决确认启动命令中含有-v /data/registry:/var/lib/registry。如果之前启动时忘了挂载最稳妥的办法是停止容器后删除用带-v的命令重新docker run然后重新推送一遍镜像。手工从容器里docker cp目录数据也能补救但效率极低不推荐在生产环境用。5.5 gzip 压缩后大小没怎么降现象ls -lh registry.tar显示 120MB压缩成registry.tar.gz后还是 100MB 左右几乎没变化。原因镜像内部的文件已经不是文本型内容镜像层本身就可能是压缩过的数据而且 registry:2 基于 Alpine基础镜像本来就小堆叠的层很少压缩空间有限。解决不要纠结压缩率。gzip在这里的目的是降低网络传输时间不是磁盘占用。如果内网带宽足够直接用未压缩的registry.tar也完全可以但为了吻合交付规范保持 gzip 是很多公司的标准传输完毕后在目标端解压即可。6. 进阶用法给 registry.tar.gz 做一次完整的校验与版本管理离线交付最怕的其实是「带错版本」。我见过不止一次生产环境部署完仓库后发现镜像包拷的是旧版本的 Registry导致客户端兼容性问题。从那以后我每次打包镜像都不直接docker save而是先做一个带固定版本号的交付目录并把校验和写入文件一起交付。mkdir -p image_delivery/registry_2.8.3 docker pull registry:2.8.3 docker save registry:2.8.3 -o image_delivery/registry_2.8.3/registry_2.8.3.tar gzip -k image_delivery/registry_2.8.3/registry_2.8.3.tar cd image_delivery/registry_2.8.3 sha256sum registry_2.8.3.tar.gz SHA256SUMS cat SHA256SUMS这个流程里有三个细节。一是固定镜像的完整版本号registry:2.8.3确保本次交付的包与测试环境完全一致二是生成SHA256SUMS文件目标机导入前先执行sha256sum -c SHA256SUMS能拦截传输过程中静默损坏的文件三是把目录名与镜像版本绑定而不是只写registry.tar.gz这样后续排查时能直接定位到具体包版本。目标机的校验动作对应是cd image_delivery/registry_2.8.3 sha256sum -c SHA256SUMS gunzip registry_2.8.3.tar.gz docker load -i registry_2.8.3.tarsha256sum -c会读取SHA256SUMS文件自动比对当前目录下的.tar.gz文件哈希是否匹配。匹配时输出OK不匹配时输出类似FAILED的信息并在结束时返回非零退出码。这个习惯特别适合多文件交付场景。如果已经忘了原始包的内容可以重新用docker images --digests查看当前镜像的 digest再和仓库中的数据做比对——前提是你在源机上保留了镜像。另外建议每交付一次就在仓库侧用curl http://127.0.0.1:5000/v2/_catalog记录一份仓库清单和 tar 包一起归档。这样半年后有人问你「这个仓库里当时推了哪些镜像」不用再翻运维记录打开归档文件就能回答比docker ps历史记录更清晰。从那以后我每次离线部署 Registry 都会强制走一遍 save → 校验 → load → 验证/_catalog的完整闭环这四步缺一步我就觉得这包还没交付到位。希望帮到你。本文还有配套的精品资源点击获取
返回列表