不想折腾 Harbor?用 Docker Registry 自建一个轻量级 Docker Hub 镜像缓存

前面围绕这个项目:
https://github.com/Rodert/DockerHub
我们已经聊过很多 Docker 镜像相关问题:
公共 Docker Mirror
registry-mirrors
Manifest / Layer / Digest
Harbor Proxy Cache
docker pull 排错
Docker Build 网络
Build Cache
Docker 磁盘清理
其中有一篇我们讲过:
用 Harbor Proxy Cache 自建 Docker Hub 缓存。
Harbor 确实很好用。
但很多个人开发者或者小团队看完以后会有一个想法:
我就是想缓存一下 Docker Hub 镜像,有必要装一整套 Harbor 吗?
毕竟 Harbor 还包含:
Web UI
用户管理
Project
RBAC
Replication
Retention
Scanner
数据库
Redis
如果你的需求真的只有:
第一次去 Docker Hub 下载,第二次直接从自己的服务器拿。
那完全可以再轻一点。
直接使用:
CNCF Distribution Registry。
也就是 Docker Registry 背后的开源 Registry 实现。
官方 Distribution 当前直接支持:
Pull-through Cache
模式。
简单来说:
Docker Host
↓
自己的 Registry Mirror
↓
Docker Hub
第一次:
Cache Miss
↓
去 Docker Hub 拉
↓
本地缓存
↓
返回客户端
第二次:
Cache Hit
↓
直接从自己服务器返回
Distribution 官方文档当前仍然明确支持这种 Pull-through Cache 架构,而且特别适合多个 Docker Host、虚拟机或者 Kubernetes 节点共享外部镜像缓存。
今天就基于:
https://github.com/Rodert/DockerHub
继续把这套轻量级方案讲透。
一、先看我们到底要解决什么问题
假设你有:
10 台 Linux 服务器
每一台都要运行:
nginx
redis
mysql
node
golang
现在每台机器都直接:
Server 1 ─────→ Docker Hub
Server 2 ─────→ Docker Hub
Server 3 ─────→ Docker Hub
...
Server 10 ────→ Docker Hub
同一个:
nginx Layer
可能被下载:
10 次。
同一个:
golang:1.25
可能每台服务器都重新跨公网拉取。
这就出现三个问题:
重复公网流量
Docker Hub 访问不稳定
Docker Hub Rate Limit
如果加一台缓存服务器:
Docker Hub
↑
│
Registry Mirror
/ | \
↓ ↓ ↓
Server1 Server2 Server3
第一次:
Server1
↓
Mirror
↓
Docker Hub
第二台开始:
Server2
↓
Mirror Cache
整个体验就完全不一样了。
二、什么是 Pull-through Cache?
名字其实已经解释得很清楚:
Pull
Through
Cache
也就是说客户端:
向本地 Registry Pull。
本地没有:
继续向上游 Pull。
同时:
把内容缓存下来。
下次:
直接使用缓存。
Distribution 官方现在的描述就是:
第一次请求镜像时,从远程 Registry 获取并存储到本地;后续请求可以直接从本地 Registry 提供。
这和普通 HTTP CDN:
Origin
↓
Edge Cache
↓
User
其实是同一个思路。
三、为什么 Docker 镜像特别适合缓存?
因为 Docker 镜像不是:
一个巨大 zip。
而是:
Manifest
+
Config
+
Layers
每一个 Layer:
都有自己的 Digest。
例如:
sha256:abc123...
如果服务器已经缓存:
Layer A
Layer B
另外一个镜像也使用:
Layer A
就不需要再重新保存完全相同的内容。
所以:
Docker Registry 天生就很适合做代理缓存。
四、它和普通 Private Registry 有什么区别?
普通 Registry:
Developer
↓
docker push
↓
Registry
里面的镜像:
由你主动 Push。
例如:
docker tag myapp:v1 \
registry.example.com/myapp:v1
docker push \
registry.example.com/myapp:v1
Pull-through Cache:
Developer
↓
docker pull nginx
↓
Registry Mirror
↓
Docker Hub
里面的数据:
由 Pull 请求自动触发。
也就是:
一个是主动 Push。
一个是按需缓存 Pull。
五、Pull-through Cache 模式不能拿来正常 Push
这是一个特别需要注意的点。
Distribution 当前配置文档明确说明:
配置成 pull-through cache 的 Registry
不支持 Push。
所以不要把一个 Registry:
既当 Docker Hub Cache
又当自己公司正常 Push 的私有仓库
混着用。
更合理:
registry-cache.example.com
→ Docker Hub Cache
registry.example.com
→ 公司自己的 Private Registry
分开。
六、最核心配置只有一个:proxy.remoteurl
Distribution 配置文件:
config.yml
最关键的部分:
proxy:
remoteurl: https://registry-1.docker.io
意思很简单:
当前 Registry
的上游
=
Docker Hub Registry
Distribution 官方现在的 Pull-through Cache 最低配置要求就是指定这个 proxy.remoteurl。
七、先准备目录
例如服务器:
/opt/docker-registry/
创建:
sudo mkdir -p \
/opt/docker-registry/data
再:
sudo mkdir -p \
/opt/docker-registry/config
最终:
/opt/docker-registry
├── config/
│ └── config.yml
└── data/
八、写 config.yml
例如:
version: 0.1
log:
fields:
service: registry
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: :5000
proxy:
remoteurl: https://registry-1.docker.io
ttl: 168h
几个重点。
九、filesystem 是什么?
storage:
filesystem:
rootdirectory: /var/lib/registry
代表:
镜像缓存
存到 Registry Container 内:
/var/lib/registry
我们后面把这个目录:
Mount 到宿主机。
Distribution 官方 Pull-through Cache 文档当前也建议缓存 Registry 使用 filesystem Storage Driver,以获得正确且稳定的缓存行为。
十、delete.enabled 为什么打开?
delete:
enabled: true
因为 Pull-through Cache:
时间长了
一定会积累:
旧 Manifest
旧 Blob
不再使用的数据。
Distribution 当前文档特别提醒:
如果希望缓存清理调度器能够清理旧内容,需要启用 delete。
这和我们上一篇:
Docker 磁盘越来越大
正好连接起来。
缓存解决性能问题,
但:
缓存必须有生命周期。
十一、ttl: 168h 又是什么?
proxy:
ttl: 168h
就是:
7 天。
Distribution 当前配置说明中:
proxy.ttl
默认就是:
168h
也就是七天;如果配置为 0,则可以关闭 Cache Expiration。
例如:
proxy:
remoteurl: https://registry-1.docker.io
ttl: 72h
就是:
3 天。
十二、ttl 并不是“3 天后所有镜像立刻消失”
这里不要误解。
它主要用于:
Proxy Cache 的过期和回收策略。
真正什么时候清理:
还要看内部调度和缓存使用。
所以不要把:
ttl
简单理解成:
Linux rm -rf 每 72 小时。
它是:
Registry Cache Policy。
十三、然后用 Docker Compose 跑起来
例如:
services:
registry:
image: registry:2
container_name: dockerhub-cache
restart: unless-stopped
ports:
- "5000:5000"
volumes:
- ./data:/var/lib/registry
- ./config/config.yml:/etc/distribution/config.yml:ro
启动:
docker compose up -d
检查:
docker ps
应该能看到:
dockerhub-cache
十四、查看日志
docker logs \
-f dockerhub-cache
如果第一次请求某个 Blob:
本地不存在
Registry 会:
向上游获取。
官方文档甚至特别提醒,有些日志看起来像:
unknown blob
但实际上只是:
本地缓存暂时没有
正在去上游获取
的信息日志,不一定是真错误。
所以:
看日志一定要看 level。
不要看到 error 字样就立刻判断服务挂了。
十五、现在先直接测试 Registry
例如:
curl http://127.0.0.1:5000/v2/
如果正常:
{}
或者返回符合 Registry V2 行为的结果,
说明:
Registry Service
基本启动成功。
十六、但是这里有一个问题:HTTP
我们现在:
http://server:5000
没有 HTTPS。
Docker 默认:
更希望 Registry 使用 HTTPS。
如果你直接:
docker pull \
192.168.1.20:5000/library/nginx:latest
可能遇到:
server gave HTTP response
to HTTPS client
怎么办?
有两条路。
十七、测试环境:insecure-registries
例如:
{
"insecure-registries": [
"192.168.1.20:5000"
]
}
写入:
/etc/docker/daemon.json
然后:
sudo systemctl restart docker
就能:
通过 HTTP Registry。
但这更适合:
内网实验。
生产环境还是建议:
HTTPS。
十八、正式环境:Nginx + HTTPS
例如:
mirror.example.com
前面放:
Nginx
结构:
Docker Client
↓
HTTPS 443
↓
Nginx
↓
Registry :5000
Nginx:
server {
listen 443 ssl;
server_name mirror.example.com;
ssl_certificate
/etc/nginx/ssl/fullchain.pem;
ssl_certificate_key
/etc/nginx/ssl/privkey.pem;
location / {
proxy_pass
http://127.0.0.1:5000;
proxy_set_header
Host $host;
proxy_set_header
X-Real-IP $remote_addr;
proxy_set_header
X-Forwarded-Proto https;
}
}
这样客户端:
正常走 HTTPS。
不需要:
insecure-registries。
十九、为什么我强烈建议 HTTPS?
因为你以后可能:
开放给多个服务器
甚至多个团队。
如果继续 HTTP:
Registry 请求
没有 TLS 保护。
正式环境不值得省这点事。
二十、客户端怎么配置成透明 Mirror?
这才是最方便的地方。
你不想每次写:
docker pull \
mirror.example.com/library/nginx
而是还想:
docker pull nginx
Docker Daemon 可以配置:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
Distribution 官方当前文档就是这样建议让 Docker Daemon 使用 Pull-through Registry Mirror 的。
然后:
sudo systemctl restart docker
检查:
docker info
应该看到:
Registry Mirrors:
https://mirror.example.com/
二十一、以后使用方式完全不变
还是:
docker pull nginx:latest
不需要告诉开发者:
换地址。
Docker Daemon 会优先:
通过 Registry Mirror 获取。
所以:
Docker Compose
原来:
services:
nginx:
image: nginx:latest
redis:
image: redis:7
也不需要改成:
mirror.example.com/...
这就是:
透明代理。
二十二、这和 Harbor Proxy Cache 最大区别之一
Harbor 常见使用:
harbor.example.com/dockerhub/library/nginx
你显式:
修改 Image Reference。
而 Distribution Pull-through Mirror:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
用户依然:
docker pull nginx
体验:
更透明。
二十三、第一次 Pull 会发生什么?
假设缓存目录:
完全为空。
执行:
docker pull nginx:latest
流程:
Docker Daemon
↓
mirror.example.com
↓
Cache Miss
↓
registry-1.docker.io
↓
Manifest
↓
Layers
↓
写入本地 Registry Cache
↓
返回 Docker Host
所以:
第一次不一定快很多。
因为它:
还是需要访问 Docker Hub。
二十四、甚至第一次可能略慢一点
因为链路从:
Client
↓
Docker Hub
变成:
Client
↓
Mirror
↓
Docker Hub
多了一层代理处理。
Pull-through Cache 真正的价值不是:
第一次立刻比 Docker Hub 快十倍。
而是:
后面的请求越来越便宜。
二十五、第二台服务器才是价值体现
Server A:
docker pull nginx
触发:
Mirror Cache Miss。
下载完成。
Server B:
docker pull nginx
此时:
Mirror 已经有 Layers。
流程:
Server B
↓
Mirror
↓
Local Cached Blob
不需要重复:
Mirror
↓
Docker Hub
下载全部 Blob。
这时候速度差距:
才会真正体现。
二十六、怎么正确测试 Cache?
很多人会犯一个错误:
在同一台客户端:
docker pull nginx
第二次马上再:
docker pull nginx
然后发现:
秒开。
就说:
Mirror Cache 太牛了。
其实未必。
因为第二次:
可能只是客户端自己的 Docker Layer Cache。
二十七、正确测试应该用两台机器
机器 A:
docker pull nginx:latest
让:
Mirror 完成缓存。
机器 B:
确认本地:
docker images
没有 nginx。
然后:
time docker pull nginx:latest
如果:
B 拉取明显更快。
这才更能证明:
命中了 Registry Server Cache。
二十八、也可以删除客户端本地镜像
例如:
docker rmi nginx:latest
然后:
docker image prune
确认客户端:
没有对应 Layers。
再:
time docker pull nginx
但多台机器测试:
更干净。
二十九、Tag 更新以后怎么办?
比如今天:
nginx:latest
指向:
Manifest A。
Mirror:
缓存 A。
过几天 Docker Hub:
latest
→ Manifest B。
Pull-through Cache 会不会永远返回旧 A?
不会这么简单。
Distribution 当前官方说明:
当通过 Tag 请求镜像时,
Registry 会检查上游内容,
确认是否仍然是最新版本;
如果上游发生变化,
则获取并缓存新内容。
所以:
Cache 不是永久死缓存。
三十、但 Digest Pull 更简单
例如:
nginx@sha256:abc123
Digest:
代表确定内容。
内容不变:
Digest 也不变。
这种资源:
天生特别适合长期缓存。
这也是 Docker Registry 设计很漂亮的地方。
三十一、磁盘会不会越来越大?
会。
比如团队一年内拉:
Ubuntu 20 个版本
Node 50 个版本
Java 100 个版本
各种 AI 镜像
各种数据库
这些:
Manifest
Blob
Layer
都会占用服务器磁盘。
所以 Pull-through Cache 不是:
无限免费缓存。
你还是要:
监控磁盘。
三十二、Distribution 会清理旧 Cache
官方当前说明:
Pull-through Cache
在高变化环境里会产生旧数据,
Registry 会周期性回收旧内容,之后如果再次请求已经被移除的数据,就重新从上游拉取。
这就是:
TTL
+
Delete
配置存在的意义。
三十三、不要把 ttl 直接设置成 0 就觉得最好
比如:
proxy:
ttl: 0
意味着:
不因为 TTL 过期。
听起来:
缓存永远保留
=
性能最好。
但你的磁盘:
也可能永远增长。
如果只是:
几台个人服务器
固定十几个镜像
没什么问题。
如果:
大型 CI
每天拉几百种 Image Tag
风险就很大。
三十四、所以 TTL 应该跟使用场景有关
个人:
7 天
14 天
甚至更久
都可以。
CI 高频环境:
可以更积极清理旧缓存。
关键不是:
哪个 TTL 最正确。
而是:
你的磁盘成本和网络成本谁更贵。
三十五、这和 Build Cache 是同一个思想
缓存本质都是:
Disk
换
Network / CPU / Time
BuildKit:
Build Cache
Registry:
Pull Cache
npm:
Package Cache
Redis:
Memory Cache
背后的工程思想:
完全相同。
三十六、Docker Hub 登录账号要不要配置?
Distribution Proxy 支持:
proxy:
remoteurl:
https://registry-1.docker.io
username:
YOUR_USERNAME
password:
YOUR_PASSWORD
用于访问:
Docker Hub Private Repository
或者:
通过账号请求上游。
Distribution 当前配置也支持 username/password 或 Credential Helper。
但是这里:
风险非常大。
三十七、为什么?
假设这个 Docker Hub 用户:
能访问:
company/private-api
company/private-db
你的 Mirror:
又完全公开在 Internet。
那么本来:
只能这个 Docker Hub Account
看到的 Private Repository,
现在有可能通过:
你的 Proxy Cache
暴露出去。
Distribution 官方对此有明确警告:如果给 Pull-through Cache 配置具有私有仓库访问权限的 Docker Hub 凭据,就必须保护 Mirror 自身,因为这些私有资源可能通过 Mirror 被访问。
所以:
Public Mirror 不要随便配置高权限 Docker Hub Account。
三十八、如果只缓存 Public Image 呢?
最简单:
proxy:
remoteurl:
https://registry-1.docker.io
不配置:
username
password
减少:
凭据泄露
私有 Repository 暴露
风险。
对于你的:
DockerHub 镜像集中营
这种项目场景:
公共镜像缓存更合理。
三十九、镜像仍然受到 Docker Hub 使用政策影响
这里也需要说明。
自建 Pull-through Cache:
不是无限绕过 Docker Hub 规则的神器。
Distribution 官方当前 Pull-through Cache 文档仍提醒:
Docker Hub Mirror
会受到 Docker Hub Fair Usage Policy 影响。
所以正确使用场景:
减少团队重复请求
提高稳定性
提高内网访问速度
而不是:
拿公共缓存无限刷 Docker Hub。
四十、Pull-through Cache 目前还有一个限制
Distribution 当前官方说明:
一个 Registry Mirror 一次只能 Mirror 一个 Upstream Registry。
比如这个实例:
proxy:
remoteurl:
https://registry-1.docker.io
就是:
Docker Hub Cache。
你不能再同时把同一个实例:
又指向 GHCR
又指向 Quay
又指向 Docker Hub。
四十一、如果想同时缓存多个 Registry?
最简单:
运行多个 Registry 实例。
例如:
dockerhub-cache.example.com
→ Docker Hub
ghcr-cache.example.com
→ GHCR
quay-cache.example.com
→ Quay
每个:
独立 config
独立 Storage
独立 Domain
更清晰。
四十二、但这里还有 Docker Daemon 的限制
Distribution 当前 Mirror 文档说明:
Docker daemon
通过 registry-mirrors 机制:
主要支持 Docker Hub Mirror。
不能直接把这一机制当成:
所有 Registry 的通用 Mirror 功能。
所以:
GHCR
Quay
ECR
这类 Registry 的缓存策略:
需要另外设计。
Harbor 在这一点上:
能力会更全面。
四十三、这就是 Harbor 和 Distribution 的真正区别
如果你的需求:
Docker Hub
↓
缓存
↓
几台服务器
Distribution:
非常合适。
如果你的需求:
Docker Hub
GHCR
ECR
公司内部镜像
权限
团队
扫描
审计
Web UI
Harbor:
更合适。
四十四、可以简单做一个对比
公共 Mirror
优点:
不用维护
开箱即用
缺点:
不可控
可能失效
可能限流
适合:
个人临时使用。
Distribution Pull-through Cache
优点:
非常轻量
部署简单
自己控制
Docker Hub 缓存透明
资源消耗低
缺点:
管理能力少
没有完整 UI
没有复杂 RBAC
一个实例一个 Upstream
适合:
个人
家庭实验室
小团队
少量服务器。
Harbor
优点:
Proxy Cache
Private Registry
用户权限
Project
Replication
Security
Retention
UI
缺点:
部署和维护成本更高。
适合:
团队
企业。
四十五、最小架构其实可以非常简单
比如一台:
2C2G
50GB Disk
的小服务器。
运行:
Nginx
+
Registry
架构:
Docker Hub
↑
│
registry:2
↑
│
Nginx HTTPS
↑
┌──────────┼──────────┐
│ │ │
Server1 Server2 Server3
如果只是:
几十个常用镜像
这套就已经很好用了。
四十六、甚至可以和 Tailscale 结合
比如你的 Mirror:
只给自己的设备使用。
可以:
Docker Cache Server
↓
Tailscale
↓
MacBook
Linux Server
NAS
这样:
根本不需要把 Registry
公开到整个互联网。
安全性和运维复杂度:
都会下降。
四十七、比如访问地址
docker-cache.tailnet.ts.net
然后:
{
"registry-mirrors": [
"https://docker-cache.tailnet.ts.net"
]
}
自己的:
Mac mini
MacBook
云服务器
NAS
共享一套缓存。
对于个人开发者:
其实非常实用。
四十八、还有一个非常实用的场景:国内服务器 + 海外缓存节点
比如:
香港
访问 Docker Hub:
很稳定。
你的国内服务器:
访问香港 比 Docker Hub 稳定。
那么:
Docker Hub
↓
香港 Registry Cache
↓
国内服务器
就成为:
自建 Docker Hub 加速层。
相比:
今天换这个 Mirror
明天换那个 Mirror
你自己:
控制域名
控制服务器
控制缓存
控制日志
稳定性更高。
四十九、如果缓存服务器本身访问 Docker Hub 也困难呢?
那当然:
它也解决不了。
Pull-through Cache 的前提就是:
Cache Server 到 Upstream 必须可访问。
如果 Cache Server:
同样访问 Docker Hub Timeout。
第一次 Cache Miss:
照样失败。
所以节点选址:
很重要。
五十、可以这样理解节点选择
用户到 Mirror:
链路 A
Mirror 到 Docker Hub:
链路 B
最终体验取决于:
A + B
第一次。
后续 Cache Hit:
主要只剩 A。
所以最理想:
Mirror 到 Docker Hub
网络好
用户到 Mirror
网络也好
这就是:
Cache Node 选址。
五十一、甚至可以做多个节点
例如:
香港 Cache
新加坡 Cache
东京 Cache
然后不同服务器:
选择最近节点。
不过一旦做到这里:
运维复杂度
就开始上涨。
个人项目:
一个稳定节点通常足够。
五十二、缓存目录一定要挂 Volume
这个坑特别容易踩。
如果 Compose:
services:
registry:
image: registry:2
什么 Volume 都没挂。
Registry 数据:
存在 Container Writable Layer。
然后:
docker compose down
重新创建:
缓存可能跟着 Container 生命周期丢失。
所以:
volumes:
- ./data:/var/lib/registry
非常重要。
否则:
你搭的不是缓存服务器。
而是:
临时缓存 Container。
五十三、磁盘监控同样重要
例如:
du -sh \
/opt/docker-registry/data
定期看:
5GB
20GB
80GB
如果增长特别快:
需要调整 TTL
或者扩容磁盘。
也可以接:
Node Exporter
Prometheus
Grafana
监控:
Filesystem Usage。
五十四、日志也别无限增长
Registry Container:
本身也会输出日志。
如果使用 Docker 默认:
json-file
又没有 Rotation,
Registry 访问量高:
日志同样可能越来越大。
例如 Compose:
services:
registry:
logging:
driver: local
options:
max-size: "20m"
max-file: "5"
这样:
Cache Data
和:
Registry Logs
都不会完全失控。
五十五、一个更完整的 Compose
可以写成:
services:
registry:
image: registry:2
container_name:
dockerhub-cache
restart:
unless-stopped
ports:
- "127.0.0.1:5000:5000"
volumes:
- ./data:/var/lib/registry
- ./config/config.yml:/etc/distribution/config.yml:ro
logging:
driver: local
options:
max-size: "20m"
max-file: "5"
注意:
5000
只绑定:
127.0.0.1
然后:
Nginx
对外提供:
443。
安全性更合理。
五十六、为什么不直接暴露 5000?
如果:
5000
直接:
0.0.0.0:5000
那么互联网:
可能直接绕过 Nginx。
你前面配置:
HTTPS
认证
限流
就可能失去意义。
所以更好的架构:
Internet
↓
443 Nginx
↓
127.0.0.1:5000 Registry
这也是常见反代原则。
五十七、公开 Registry Mirror 最好再加访问控制
如果只是自己使用:
完全公开
意义不大。
因为别人发现以后:
可能拿你的服务器
当公共 Docker 加速站。
然后:
流量
磁盘
Docker Hub Pull
全部你买单。
所以至少考虑:
IP 白名单
Basic Auth
VPN / Tailscale
Cloudflare Access
等访问控制。
五十八、不过 registry-mirrors 和认证组合需要提前测试
因为:
Docker Daemon
对 Registry Mirror:
认证
重定向
TLS
都有自己的交互逻辑。
所以如果只是:
自己的几台服务器。
我更推荐:
网络层限制。
例如:
Security Group
Tailscale
内网 IP
往往比:
把 Registry Authentication
搞得特别复杂
简单。
五十九、DockerHub 项目可以怎么利用这个方向?
现在:
https://github.com/Rodert/DockerHub
主要是:
公共 Mirror 地址。
可以增加一个:
自建镜像源
章节。
分成:
Level 1
公共 Mirror
Level 2
registry:2 自建 Cache
Level 3
Harbor Proxy Cache
用户一眼就知道:
不同规模应该用什么。
六十、甚至可以提供一键部署脚本
比如:
curl -fsSL \
https://your-domain/install-registry-cache.sh \
-o install.sh
bash install.sh
脚本:
检测 Docker
创建目录
生成 config.yml
生成 docker-compose.yml
启动 Registry
检查 /v2/
输出 daemon.json 配置
最后:
✅ Docker Hub Cache Started
Mirror:
https://mirror.example.com
Client config:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
这会非常适合小白。
六十一、也可以做状态检测
例如:
Mirror Status:
🟢 Online
Upstream:
Docker Hub
Cache Size:
18.4GB
TTL:
7 days
Disk:
43%
Last Pull:
2 minutes ago
甚至:
Top Cached Images
虽然 Distribution 本身不是为了:
做漂亮 Dashboard。
但完全可以在外层:
自己做监控。
六十二、未来还可以做预热
比如常用:
nginx:latest
redis:7
mysql:8.4
node:24
golang:1.25
部署 Registry 后:
docker pull nginx
docker pull redis:7
docker pull mysql:8.4
通过:
已经配置 Mirror
自动:
Cache Warm-up。
这样团队第一次真正使用:
也不需要等上游下载。
六十三、甚至 GitHub Actions 可以每天预热
例如:
name:
Warm Docker Cache
on:
schedule:
- cron: "0 2 * * *"
然后:
每天检查基础镜像
↓
Pull
↓
让 Mirror 更新热门缓存
不过:
不要无意义大量拉镜像。
只维护:
团队真正使用的 Base Images。
六十四、如果上游内容变了怎么办?
比如:
node:24
更新。
客户端下一次请求:
Mirror
会根据 Tag:
检查远程版本。
如果上游变了:
拉新内容
+
缓存新 Layers。
如果没变:
继续使用本地缓存。
这就是 Pull-through Cache:
比纯静态镜像拷贝方便的地方。
六十五、但是生产环境仍然建议固定版本
Cache:
解决下载问题。
并不解决:
latest 会变化
的问题。
例如:
FROM node:latest
即使有自建 Mirror:
内容仍然可能变化。
所以正式环境:
FROM node:24.10.0
甚至:
Tag + Digest
仍然更稳。
Cache 和版本治理是两件不同的事。
六十六、Pull-through Cache 不是备份
这也一定要讲清楚。
如果:
上游镜像消失
你本地:
碰巧还缓存了一份。
短期可能:
还能使用。
但 Cache 本身:
有 TTL
有清理策略
不是永久归档。
所以关键生产镜像:
不应该只依赖 Cache。
真正重要:
应该主动 Mirror 到自己的 Private Registry。
六十七、可以这样区分
Cache:
“如果有就快一点。”
Private Mirror / Archive:
“这是我要长期保留的。”
前者:
性能系统。
后者:
资产管理系统。
这个思路特别重要。
六十八、比如公司基础镜像
这些:
ubuntu:24.04
node:24
golang:1.25
eclipse-temurin:21
可以:
Pull-through Cache
提高日常速度。
但发布生产的:
company-api:v1.8.2
应该:
正式 Push 到企业 Registry。
不要:
把 Cache 当生产制品仓库。
六十九、最终我们可以得到一条非常清晰的演进路线
最开始:
docker pull 太慢
于是:
公共 Mirror
但:
公共 Mirror 会失效。
于是:
自建 Distribution Cache
团队继续扩大:
需要用户权限
扫描
审计
多 Registry
于是:
Harbor。
再继续:
多机房
Kubernetes
企业供应链
就进入:
完整 Registry Platform。
也就是说:
基础设施应该跟规模一起长。
不是:
个人两台服务器
也一定装一整套企业平台。
七十、三种方案最终怎么选?
如果你只有:
1~3 台个人机器
优先:
公共 Mirror。
如果:
3~20 台服务器
而且:
主要缓存 Docker Hub
我会优先考虑:
Distribution Pull-through Cache。
如果:
团队开发
Kubernetes
公司内部镜像
多 Registry
权限管理
我会倾向:
Harbor。
这套判断:
比单纯说 Harbor 更专业
因为:
没有一个方案适合所有规模。
总结
很多开发者遇到 Docker Hub 网络问题以后,会一直寻找:
下一个能用的公共镜像地址。
今天:
Mirror A。
明天:
Mirror B。
后天:
Mirror C。
但如果你已经拥有:
多台长期运行的服务器
一个更稳定的思路其实是:
自己成为自己的 Mirror。
Distribution Pull-through Cache 的核心架构非常简单:
Docker Host
↓
Local Registry Mirror
↓
Docker Hub
第一次:
Cache Miss
↓
访问 Docker Hub
↓
保存 Manifest / Layer
第二次:
Cache Hit
↓
直接返回
整个部署最核心的配置甚至只有:
proxy:
remoteurl:
https://registry-1.docker.io
再通过:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
让 Docker Daemon:
透明使用你的缓存节点。
相比 Harbor:
它更轻。
相比公共 Mirror:
它更可控。
相比每台服务器直接 Docker Hub:
它更节省重复公网流量。
如果只记住一句话:
公共 Docker Mirror 是“别人帮你缓存”,Distribution Pull-through Cache 是“你自己掌握缓存节点”。
对于:
https://github.com/Rodert/DockerHub
这个项目来说,我觉得这也是非常自然的一步:
公共 Docker 镜像列表
↓
镜像健康检测
↓
Docker Pull 排错
↓
一键自建 Distribution Mirror
↓
Harbor 企业级 Registry
这样项目就可以真正形成一条:
从“小白解决 docker pull 失败”到“自己搭 Docker Registry 基础设施”的完整路线。
项目地址:
https://github.com/Rodert/DockerHub

浙公网安备 33010602011771号