本节摘要:内网环境推不走公共仓库时,自建 registry 是标准解法。本节用官方 registry 镜像现场搭建:起服务、配置放行、推送回拉验证、挂卷持久化,每个报错现场都给出真实文案与处置动作。看完即可在内网复刻一座最小可用的镜像港口。
不是所有镜像都适合公开,也不是所有机房都能直连公共仓库——私有仓库不是可选项而是刚需。好消息是自建一座最小仓库只需要一条 run 命令;坏消息是默认配置会撞上"HTTP 不安全"的墙。本节按施工顺序走完全程,撞墙的姿势也一并演示。
$ docker run -d -p 5000:5000 --name registry --restart unless-stopped \ -v registry-data:/var/lib/registry \ registry:2 a1b2c3d4e5f6... $ docker ps --filter name=registry CONTAINER ID IMAGE STATUS PORTS NAMES a1b2c3d4e5f6 registry:2 Up 4 seconds 0.0.0.0:5000->5000/tcp registry
registry:2 镜像起来即服务,仓库 API 默认监听容器内 5000 端口;-v 把存储目录挂成命名卷——不然仓库容器一删,里面所有镜像陪葬。存储布局可以进卷里看:
$ docker exec registry ls /var/lib/registry/docker/registry/v2/repositories myweb
推上去的每个镜像在这里都有以名字命名的目录,里面是清单与各层数据——这就是 4.3 推送词条的目的地。
从另一台机器向它推送,默认会撞墙:
$ docker tag myweb:0.1 registry.local:5000/myweb:0.1 $ docker push registry.local:5000/myweb:0.1 The push refers to repository [registry.local:5000/myweb] Get "https://registry.local:5000/v2/": http: server gave HTTP response to HTTPS client
读报错:客户端对非默认地址默认走 HTTPS,而我们的 registry 没配证书,只有 HTTP——于是握手谈崩。生产解法是给仓库配 TLS 证书;内网试验环境的快速解法是告诉客户端"这个地址允许走 HTTP"。编辑客户端机器的守护进程配置文件(daemon.json),加入:
{ "insecure-registries": ["registry.local:5000"] }
重启守护进程生效:
$ sudo systemctl restart docker $ docker info | grep -A 2 'Insecure Registries' Insecure Registries: registry.local:5000 127.0.0.0/8
docker info 里能看到自己名列其中,才算放行成功。要强调边界:insecure 意味着镜像传输不加密不校验证书,只限实验内网;正式环境给仓库配证书(哪怕自签并分发信任),别把放行配置带进生产。仓库端监听 HTTPS 后,客户端无须任何特殊配置,这也是为什么公司级方案都直接上证书。

推与拉是同一条路的两个方向,所以放行配置必须在每一台客户端机器上做,别只配了开发机就在生产机上干等报错。
$ docker push registry.local:5000/myweb:0.1 The push refers to repository [registry.local:5000/myweb] 9c1b6e4a2f0d: Pushed 0.1: digest: sha256:8b42de... size: 527 $ docker pull registry.local:5000/myweb:0.1 0.1: Pulling from registry.local:5000/myweb Digest: sha256:8b42de... Status: Downloaded newer image for registry.local:5000/myweb:0.1
推送输出末尾的 digest 是仓库对镜像内容的签名,回拉时逐字核对一致即闭环。到了这一步,内网里任何一台放行过的机器都能以这个引用名取货。仓库的运维词条还有两类常用项:查询目录(对仓库 API 发请求列出全部镜像)与垃圾回收(删除镜像后回收空间),属捌部治理现场,此处先立此存照。
💡 备份思路提前给:registry 的全部状态就在那个命名卷里,卷打包(伍部卷词条)加异地复制,就是仓库的灾备方案,比备份容器本身重要得多。
看货:仓库里现在躺着哪些镜像?registry 提供一组 HTTP 接口,curl 一发即知:
$ curl http://registry.local:5000/v2/_catalog {"repositories":["myweb"]} $ curl http://registry.local:5000/v2/myweb/tags/list {"name":"myweb","tags":["0.1","0.2"]}
第一发列出全部镜像名,第二发看单个镜像名下的全部标签——巡检脚本就用这两条凑齐。
控门:默认的 registry 不设防,任何连得上 5000 端口的人都能推拉。最小防御是 basic auth:用 htpasswd 生成凭据文件,起容器时挂进去并声明认证参数,客户端从此必须 login 才能动仓库。这层防护很薄,正式方案要再叠 TLS,但比裸奔强出一个量级。
验门:门装没装好,用一个没登录的客户端探一下便知,应答该是 401:
$ curl -i http://registry.local:5000/v2/_catalog 2>&1 | head -n 1 HTTP/1.1 401 Unauthorized
⚠️ 鉴权与放行是两码事:insecure-registries 管传输加不加密,htpasswd 管有没有账号。内网实验里两者常一起配,别配了一个就以为另一个也顺手好了——漏掉鉴权的仓库在办公网里等于公共下载站。
仓库立起来了,下一节解决"怎么把镜像名正言顺地推进去":tag 与 push 的完整词条。