简介:面向无法访问外网的内网环境,这份资源提供了一套可直接导入的 Docker Registry 镜像文件,帮助运维与开发人员在隔离网络中快速搭建私有镜像仓库,免去在线拉取镜像的困扰。压缩包共 18 个文件,以 json 元数据、tar 层数据、version 版本标识及 repositories 仓库索引为主,完整保留了镜像的分层结构与清单信息,整体约 25.15MB,体积轻量便于内网传输与分发。已有 436 人学习下载,适合需要离线部署容器基础设施的中级技术人员参考。借助这些文件,读者可省去自行导出镜像的步骤,直接获得可用的 Registry 镜像素材,理解镜像分层与清单组织方式,并据此完成私有仓库的导入与启动,为内网镜像托管、团队协作与后续运维排错打下基础。
1. 拿到 registry.tar.gz 先别急着 docker load:一个离线镜像仓库的安装现场
上周帮一个做内网交付的朋友处理环境,对方甩过来一个registry.tar.gz,说“装个私有镜像仓库,机器不能出网”。我第一反应不是解压,而是先问清楚三件事:目标机器有没有 Docker、这个包是镜像 tar 还是仓库数据目录、端口 5000 有没有被占。因为registry.tar.gz这个名字太容易让人误会——它可能是docker save出来的镜像归档,也可能是整个 registry 存储目录的打包,甚至可能是别人把二进制和配置一起塞进去的混合包。装错方向,后面全是无用功。
私有 registry 在离线交付、内网 CI、多机镜像分发里几乎是标配,装不好会怎样?轻则docker push报http: server gave HTTP response to HTTPS client,重则仓库起来但数据目录权限不对,重启一次镜像全丢。这篇笔记按“先验包、再装 Docker、再起 registry、最后验证推送拉取”的顺序走,适合第一次在内网搭 registry 的开发者,也适合已经装过但被 TLS 和存储路径坑过的熟手。
2. 装前环境核对:Docker 版本、端口与磁盘先过一遍
2.1 确认 registry.tar.gz 到底是什么
拿到包先别tar -xzf一把梭,先看文件列表和大小。常见做法是先tar -tzf只列内容不解压,判断它是镜像归档还是目录打包。
# 只看包内前 30 个条目,判断包的类型 tar -tzf registry.tar.gz | head -30 # 看包大小,镜像 tar 通常几百 MB 起,纯配置包很小 ls -lh registry.tar.gz如果列表里出现manifest.json、repositories、若干layer.tar或<sha>/layer.tar,基本是docker save出来的镜像归档,后面走docker load。如果出现docker/registry/v2/这种路径,说明是 registry 的存储目录打包,解压后要挂到容器的/var/lib/registry。如果出现registry二进制加config.yml,那是二进制部署方式,和容器方式不能混着来。这一步判断错,后面所有命令都是白费。
提示:包名带
.tar.gz不代表一定是镜像归档,内网交付里把存储目录打包的情况很常见,先tar -tzf看一眼能省半小时。
2.2 Docker 版本与内核参数核对
registry 官方镜像对 Docker 版本要求不苛刻,但太老的 Docker(比如 1.x 早期)在docker load大镜像时容易出问题。我一般要求目标机 Docker 不低于 20.10,用下面两条命令确认版本和存储驱动。
# 确认 Docker 客户端与服务端都在跑,版本不低于 20.10 docker version --format '{{.Server.Version}}' # 看存储驱动,overlay2 是当前主流,devicemapper 老环境要留意 docker info --format '{{.Driver}}'docker version --format '{{.Server.Version}}'只取服务端版本,比整段输出干净。如果这条命令报Cannot connect to the Docker daemon,说明 Docker 没起或者当前用户不在 docker 组,先解决这个再谈 registry。存储驱动如果是overlay2就放心走,如果是vfs,镜像层多的时候磁盘会涨得很快,内网小机器要提前算空间。
端口方面,registry 默认监听 5000,先确认没被占:
# 检查 5000 端口占用,有输出说明已被别的服务占了 ss -lntp | grep ':5000'如果 5000 被占,起 registry 时把宿主端口换成 5001 之类,容器内仍是 5000,映射写-p 5001:5000即可。磁盘至少留出镜像总量两倍的空间,registry 的 blob 存储和临时解压都会吃盘。
2.3 离线环境的前置依赖
不能出网的机器,docker load本身不需要外网,但如果包是二进制方式,可能缺ca-certificates之类的基础包。我一般先确认两件事:系统时间是否准确(TLS 证书校验依赖时间),以及curl是否可用(后面验证要用)。
# 时间偏差太大会导致后续 TLS 校验失败,先看一眼 date # 确认 curl 存在,验证 registry 接口时要用 command -v curl || echo "curl missing"时间偏差超过几分钟,后面配 HTTPS 时证书会直接报 not yet valid 或 expired,这种问题排查起来很玄学,不如装之前就对齐。curl缺失的话,用wget替代也行,但 registry 的/v2/接口用curl -I看响应头最直观。
3. 安装 Docker 与加载 registry 镜像:load、tag、run 三步别跳
3.1 安装或确认 Docker 可用
如果目标机还没装 Docker,离线环境一般用系统包管理器装本地 rpm/deb,或者用官方静态二进制。这里不展开系统包细节,重点确认装完后systemctl能拉起服务。
# 启动并设开机自启,老系统没有 systemctl 的用 service docker start systemctl enable --now docker # 确认服务状态,active (running) 才算过 systemctl is-active dockerenable --now一条命令同时做开机自启和立即启动,比先enable再start少一步。is-active返回active就继续,返回inactive或failed先看journalctl -u docker -n 50的日志,常见是存储目录权限或 SELinux 拦截。
3.2 加载镜像归档并确认 tag
如果 2.1 判断是镜像归档,直接docker load。加载完镜像的 tag 可能是registry:2,也可能是别人重新 tag 过的名字,用docker images确认。
# 加载镜像归档,输出会显示 Loaded image: xxx docker load -i registry.tar.gz # 过滤出 registry 相关镜像,确认 tag 和镜像 ID docker images | grep -i registrydocker load -i指定输入文件,比docker load < registry.tar.gz更明确。加载后如果 tag 是<none>,说明归档里没带 tag,需要手动docker tag <IMAGE_ID> registry:2补一个。我一般统一 tag 成registry:2,后面docker run引用方便,也避免不同人环境里 tag 不一致。
如果 2.1 判断是存储目录打包,这一步跳过docker load,改为解压到宿主机目录:
# 存储目录方式:解压到 /data/registry-data,注意保留目录结构 mkdir -p /data/registry-data tar -xzf registry.tar.gz -C /data/registry-data # 确认解压后能看到 docker/registry/v2 结构 ls /data/registry-data-C指定解压目标目录,避免污染当前目录。解压后如果多了一层顶层目录,挂载时路径要跟着调整,这一点后面 4.2 会讲。
3.3 启动 registry 容器的最小命令
先用最小参数把容器跑起来,确认能起再补配置。最小命令只做端口映射和存储挂载:
# 最小启动:宿主 5000 映射容器 5000,数据挂到 /data/registry docker run -d \ --name registry \ --restart=always \ -p 5000:5000 \ -v /data/registry:/var/lib/registry \ registry:2-d后台运行,--restart=always保证机器重启后容器自动拉起,内网仓库最怕重启后没人手动起。-v /data/registry:/var/lib/registry把容器内存储目录挂到宿主机,容器删了数据还在。如果 3.2 是存储目录方式,这里-v的宿主路径要指向解压出来的实际数据目录,比如/data/registry-data/docker/registry/v2的上一级,具体看解压结构。
启动后立刻看日志:
# 看容器日志,正常会输出 listening on [::]:5000 docker logs --tail 20 registry日志里出现listening on和version=基本就起来了。如果容器秒退,docker logs会给出原因,常见是端口占用或挂载路径权限不对。
4. 配置 registry:端口、存储、TLS 与认证的取舍
4.1 用配置文件替代一长串环境变量
最小命令能跑,但生产内网一般要调存储删除、日志级别、TLS。registry 支持-v config.yml:/etc/docker/registry/config.yml挂配置文件,比堆环境变量清晰。先写一个基础版:
version: 0.1 log: level: info storage: filesystem: rootdirectory: /var/lib/registry delete: enabled: true http: addr: :5000 headers: X-Content-Type-Options: [nosniff]delete.enabled: true允许通过 API 删除镜像,不开的话docker push覆盖同名 tag 会留垃圾 blob,磁盘只涨不降。rootdirectory要和容器挂载路径一致,改这里不改挂载等于白改。http.addr: :5000监听所有网卡 5000 端口,只在内网用可以保持 HTTP,后面 4.3 再讲 TLS。
启动时挂配置:
# 先删旧容器再按配置重启,数据在宿主机不受影响 docker rm -f 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:2docker rm -f强制删旧容器,因为数据在宿主机卷里,删容器不丢镜像。配置文件路径我习惯放/data/registry-config/,和存储目录分开,备份时清楚哪些是配置哪些是数据。
4.2 存储路径与权限:最容易翻车的一处
registry 容器默认以 root 跑,挂载目录权限一般不是问题,但如果宿主机开了 SELinux 或用了非 root 运行,就会出permission denied。常见做法是先给目录放权,再确认 SELinux 状态。
# 建目录并给足权限,内网环境图省事直接 755 mkdir -p /data/registry chmod -R 755 /data/registry # 看 SELinux 是否 enforcing,enforcing 时挂载要加 :z 标签 getenforce如果getenforce返回Enforcing,-v挂载要写成-v /data/registry:/var/lib/registry:z,让容器有写权限。返回Permissive或Disabled就不用加。这一条血泪经验来自一次内网机器,容器日志一直报mkdir /var/lib/registry/docker: permission denied,查了半天是 SELinux 拦的,加:z立刻好。
另外存储目录不要放在/tmp或会被清理的路径,registry 数据被清等于镜像全丢。我一般固定/data/registry,并在部署文档里写死,避免不同人换路径导致数据分散。
4.3 HTTP 还是 TLS:内网环境的实际取舍
registry 默认走 HTTP,Docker 客户端对非 localhost 的 HTTP registry 默认拒绝,会报http: server gave HTTP response to HTTPS client。内网两种做法:配insecure-registries走 HTTP,或者上自签 TLS。前者快,后者规范,看交付要求。
走 HTTP 的话,在每台要推拉的机器上改 Docker 配置:
{ "insecure-registries": ["192.168.1.10:5000"] }把这段写进/etc/docker/daemon.json,然后systemctl reload docker或重启 Docker。注意 IP 和端口要写实际 registry 地址,写localhost只对本机生效。改完用docker info看Insecure Registries段是否包含该地址。
走 TLS 的话,需要证书和私钥,配置里加:
http: addr: :5000 tls: certificate: /etc/docker/registry/certs/domain.crt key: /etc/docker/registry/certs/domain.key证书路径要挂进容器,且客户端要信任该 CA。内网自签证书的常见坑是证书 SAN 没写 IP,Docker 校验主机名失败,生成证书时subjectAltName要把 IP 写进去。这一块比 HTTP 多不少步骤,如果只是内网几台机器用,insecure-registries更省事;如果交付要求加密传输,再上 TLS。
4.4 加一层基础认证
裸 registry 谁都能推镜像,内网也不该完全裸奔。registry 自带 htpasswd 认证,先生成密码文件:
# 安装 htpasswd 工具(httpd-tools 或 apache2-utils),生成密码文件 htpasswd -Bbn admin 'YourStrongPass' > /data/registry-config/htpasswd-B用 bcrypt 加密,-b从命令行取密码,-n输出到标准输出。生成后配置里加:
auth: htpasswd: realm: basic-realm path: /etc/docker/registry/htpasswd挂载时把 htpasswd 文件挂到对应路径,重启容器。之后docker login 192.168.1.10:5000输入账号密码才能推拉。密码文件权限建议 600,别让普通用户读到。
5. 避坑与排查:registry 起不来、推不上去的常见现场
5.1 容器起来但 docker push 报 HTTPS 错误
现象:docker push报http: server gave HTTP response to HTTPS client。原因:客户端把 registry 当 HTTPS 访问,但服务端是 HTTP。解决:在客户端/etc/docker/daemon.json加insecure-registries,重启 Docker,再docker info确认生效。注意改的是推拉镜像那台机器的配置,不是 registry 宿主机的。
5.2 日志报 permission denied 但目录权限看着没问题
现象:容器日志mkdir /var/lib/registry/docker: permission denied,ls -l看目录是 755。原因:SELinux enforcing 拦截了容器挂载写入。解决:getenforce确认,挂载加:z标签,或临时setenforce 0验证(验证完记得改回)。长期方案是加标签而不是关 SELinux。
5.3 重启后镜像全没了
现象:容器重启或重建后docker pull拉不到之前推的镜像。原因:启动时没挂-v,数据写在容器层,容器删了数据跟着没。解决:确认-v /data/registry:/var/lib/registry存在,且config.yml里rootdirectory和挂载路径一致。已经丢了的只能重新推,所以第一次启动就要把挂载写对。
5.4 磁盘只涨不降,删了镜像空间不释放
现象:docker push覆盖同名 tag 后磁盘持续增长,删镜像也不降。原因:delete.enabled没开,或者开了但没跑垃圾回收。解决:配置里开delete.enabled: true,删镜像后进容器跑registry garbage-collect /etc/docker/registry/config.yml。注意 GC 期间最好停写,内网低峰期做。
5.5 5000 端口被占导致容器秒退
现象:docker run后容器立刻退出,docker logs报listen tcp :5000: bind: address already in use。原因:宿主机 5000 被别的服务占用。解决:ss -lntp | grep ':5000'找到占用进程,换端口映射-p 5001:5000,客户端地址跟着改成 5001。别直接杀占用进程,先确认那是什么服务。
6. 装完怎么验证:从 /v2/ 接口到一次完整推拉
registry 装完不能只看容器Up就收工,要按“接口通、能推、能拉、重启还在”四步验。先验接口:
# 无认证时返回 200,有认证时返回 401 也算接口通 curl -I http://192.168.1.10:5000/v2/ # 有认证时带账号密码验,返回 200 说明认证也通 curl -u admin:'YourStrongPass' -I http://192.168.1.10:5000/v2//v2/是 registry 的健康检查接口,返回 200 或 401 都说明服务在监听,401 只是没带认证。返回connection refused说明容器没起或端口没映射对。
然后做一次完整推拉,用一个小镜像避免传大文件:
# 拉一个小镜像,重新 tag 到私有仓库地址 docker pull busybox:latest docker tag busybox:latest 192.168.1.10:5000/demo/busybox:v1 # 推送,成功会显示 pushed docker push 192.168.1.10:5000/demo/busybox:v1 # 删本地镜像再从仓库拉,验证真的存进去了 docker rmi 192.168.1.10:5000/demo/busybox:v1 docker pull 192.168.1.10:5000/demo/busybox:v1docker tag的仓库地址必须和客户端insecure-registries里写的一致,差一个端口都推不上去。docker rmi删本地再pull,能拉下来才说明数据真在 registry 里,而不是本地缓存骗人。
最后验重启存活:
# 重启容器,再拉一次,确认数据没丢 docker restart registry docker pull 192.168.1.10:5000/demo/busybox:v1重启后还能拉,说明挂载和--restart=always都生效。我一般还会看一眼存储目录里有没有 blob:
# 确认宿主机存储目录下有数据,不是空目录 du -sh /data/registrydu -sh有几百 KB 以上说明数据落盘了。从那以后我每次装完 registry,都强制走一遍“接口 → 推 → 删本地 → 拉 → 重启再拉”这条链,少一步都可能在上线当天才发现问题。希望帮到你。
本文还有配套的精品资源,点击获取