Docker镜像获取全攻略:加速、离线迁移、自建Registry一条龙


导读:本站自托管系列里docker pull的出场率极高,但两个现实问题一直没正面解决:一是国内网络环境下从Docker Hub拉镜像又慢又玄学,今天能拉明天超时;二是多台VPS各自拉同一个镜像,纯属重复烧流量。这篇把镜像获取的所有姿势摆上桌:registry-mirrors加速、代理拉取、save/load离线搬运、用registry:2自建私有镜像仓库、再给私有仓库上好锁。读完这篇,镜像在你手里是可搬运的货物,而不是看运气的抽卡。

一、先搞懂链路:docker pull那一秒发生了什么

docker pull nginx:1.27

这条命令背后是一条完整链路:Docker客户端向Registry(默认Docker Hub)发起请求,按tag解析出manifest清单,再按清单逐层下载。这里有个关键认知:镜像不是一个大文件,而是一堆只读layer的叠加——基础系统层、apt安装层、应用代码层,层层堆叠出最终的文件系统。

这个设计解释了两件事:为什么两个都基于debian的镜像在本机只下载一次基础层(layer缓存,本机已有的层直接跳过);为什么镜像可以增量分发(你的改动往往只是顶层一两层,底下的层全网共用)。理解了"镜像=清单+层",后面的每一招都顺理成章。

二、拉取慢的四种解法,按顺序试

第一招,配置镜像加速器。编辑/etc/docker/daemon.json:

{
  "registry-mirrors": ["https://mirror.example.com"]
}

然后重启Docker生效:

systemctl restart docker

加速器地址填云厂商提供的或者公益加速器,支持填多个互为备份。改完用docker info看一眼Registry Mirrors小节,确认已经挂上。

第二招,给Docker daemon配代理。注意shell里export的代理只影响docker命令行客户端,真正下载镜像的是daemon进程,得在daemon的systemd单元里加环境变量:

systemctl edit docker
[Service]
Environment="HTTPS_PROXY=http://127.0.0.1:7890"

改完systemctl restart docker。本站systemd篇讲过的单元改写方法,在这里原样复用。

第三招,离线搬运,完全不依赖网络质量,见下一节。

第四招,曲线救国:从其他可用的镜像站拉取,再docker tag改回原名。应急时很好用,属于"先让项目跑起来再说"流派。

三、save/load:最朴素最可靠的离线方案

两台机器之间搬镜像,docker自带的导出导入最省心:

docker save -o nginx.tar nginx:1.27
scp nginx.tar root@203.0.113.20:/opt/
docker load -i nginx.tar

save导出的是完整镜像(含全部层和标签),load后原样恢复。配合本站VPS搬家篇讲的rsync,整站迁移时把镜像一起打包带走,新机器零下载等待。

两个注意点:save的对象是镜像不是容器,运行时配置要用docker inspect查出来,或者干脆由Compose文件管理——这也是本站一直推荐Compose的原因,配置即文件,可版本化可搬运;导出文件动辄几个G,留意目标盘空间。

四、自建Registry:一条命令起一个私有仓库

镜像多了、机器多了,就该有自己的仓库了。官方registry镜像五分钟起一个:

docker run -d --restart=always --name registry -p 5000:5000 -v /opt/registry:/var/lib/registry registry:2

从这一秒起,你的VPS就是一台Registry。用法三步:

docker tag nginx:1.27 203.0.113.10:5000/nginx:1.27
docker push 203.0.113.10:5000/nginx:1.27
docker pull 203.0.113.10:5000/nginx:1.27

push之前要让Docker信任这个HTTP源,daemon.json里加一段:

{
  "insecure-registries": ["203.0.113.10:5000"]
}

镜像数据全部落在/opt/registry卷里——从现在起它是你的重要资产,记得纳入备份计划,备份思路参考本站备份相关文章的轮转方案。

五、给私有仓库上锁:不做裸奔的Registry

第四节的仓库是HTTP明文加零认证,只适合内网自嗨。要上公网,标准姿势是套一层Nginx反代加Basic Auth加HTTPS,正好复用本站反代教程的全套技能。

第一步,生成认证文件:

docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin YourStrongPass > /opt/registry-auth/htpasswd

第二步,Nginx关键配置片段:

location / {
    proxy_pass http://127.0.0.1:5000;
    auth_basic "Registry";
    auth_basic_user_file /opt/registry-auth/htpasswd;
}

域名证书用certbot签发,自动续期那行cron怎么写,本站cron篇有现成答案。之后客户端先docker login仓库域名,输入htpasswd里那对账号密码,才能push/pull。反代层的更多玩法(限速、缓存、日志)反代教程里都讲过,按需取用。

六、多机镜像中转:一拉多推的省流量玩法

三台VPS都要用同一套自托管镜像时,中转站玩法登场:一台机器从Docker Hub拉取,retag后push进私有Registry,其余机器统一从私有Registry拉。跨网流量只发生一次,之后全是内网或就近传输。

离线环境同理:外网机器拉好镜像,save/load搬进内网的一台,内网机器再从它上面取——air-gapped环境的镜像供应链就是这么搭起来的。这套思路再往上一层就是CI/CD的镜像分发,不过个人规模到中转站这步就够用了。

七、tag管理:怎么打标签才不会乱

镜像多了以后,tag命名直接决定仓库的可用性,三条实用约定:语义化版本打tag(myapp:1.4.2),谁改了什么一目了然;重要构建追加日期tag(myapp:2026-09-01),天然的版本快照,回滚时指哪打哪;latest只当指针不当承诺——它只是"默认拉取"的语法糖,随时会被新构建覆盖,生产环境的Compose文件里永远写死具体版本号,用latest的机器在需要回滚的那一刻会彻底找不到北。

私有仓库同理:203.0.113.10:5000/myapp:1.4.2比203.0.113.10:5000/myapp:latest多敲几个字符,换来的是任意时刻可精确复现。配合本站Compose篇固定版本号的写法,整套自托管栈都变成可复现的——这正是"基础设施即代码"在个人规模下的样子。

八、仓库日常维护:GC与磁盘治理

Registry只进不出,磁盘早晚告急。官方的垃圾回收命令:

docker exec registry registry garbage-collect /etc/docker/config.yml

删除镜像的API比较绕,实用主义做法有两种:定期快照/var/lib/registry目录做备份,需要时整目录还原;或者重push一套干净标签后,清空目录重建。本机侧同样要定期清理无主镜像:

docker image prune -a --filter "until=168h"

一周没用过的镜像直接清掉,配合docker system df随时查看三类占用,磁盘常年健康。这和本站日志治理的思路一致:存储类资源都要有退出机制,只进不出的设计迟早炸盘。

九、安全底线:别把密码打进镜像

自建了Registry之后容易滋生一个危险想法:反正仓库是私有的,密码写进镜像里没关系吧。关系很大:镜像的每一层会流经备份文件、传输链路、每一台pull它的机器,泄漏面比你想象的大得多。

正确姿势三件套:密码类配置一律运行时注入,用Compose的environment或者专门的secret管理;构建时配好.dockerignore,把.env、密钥文件挡在构建上下文之外;镜像里只放代码和依赖,不放任何凭据。本站Vaultwarden篇的结论在这里原样适用:秘密归专门的管理器管,镜像只管装东西。

结语

镜像加速解决"拉得慢",save/load解决"搬得动",自建Registry解决"管得住",三层递进正好覆盖个人站长的全部镜像需求。配合本站的Compose体系,你的自托管栈从此不依赖任何单一网络环境:外网慢就走离线,机器多就建仓库,要安全就加锁上证书。所谓基础设施自由,就是这样一砖一瓦砌出来的。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

SSH安全加固实战:从密钥登录到fail2ban防爆破

crontab定时任务详解:从五行口诀到排坑指南,让VPS自己按时干活

评 论
更换验证码