Docker镜像拉不下来国内云服务器怎么配镜像加速不翻车
Docker镜像拉不下来,先别急着改一堆配置
国内云服务器上拉 Docker 镜像,最常见的报错不是 Docker 本身坏了,而是访问 Docker Hub 的链路不稳定。实际使用中发现,同一台机器有时候上午还能 pull,下午就开始 timeout;同一个镜像,centos 拉不动,nginx 偶尔能下来;换个机房或者换条线路,问题又消失。
典型报错大概是这些:
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection
Get "https://auth.docker.io/token": context deadline exceeded
dial tcp: lookup registry-1.docker.io: i/o timeout
net/http: TLS handshake timeout
这些错误看起来不一样,本质上多半绕不开三类问题:DNS解析慢或被污染、到 Docker Hub 的 TCP/TLS 连接不稳定、镜像层下载中途断流。国内云服务器默认出口线路、运营商、机房策略都会影响结果,不是简单换一个命令就能一直稳。
先确认是 Docker Hub 链路问题,不要一上来就重装 Docker
排查时建议先看三处:DNS、HTTPS连通性、Docker daemon 日志。
DNS可以这样看:
nslookup registry-1.docker.io
nslookup auth.docker.io
如果这里就经常超时,先别折腾 Docker。把 DNS 换成 223.5.5.5、119.29.29.29、114.114.114.114 这类国内公共 DNS,或者云厂商内网 DNS。不同云厂商机房对公网 DNS 的体验差别很明显。
HTTPS连通性可以用 curl 试一下:
curl -I https://registry-1.docker.io/v2/
正常情况下返回 401 Unauthorized 也没问题,说明服务能连上,因为 Docker Hub 的 registry 本来就需要认证流程。怕的是一直卡住、TLS handshake timeout、connection reset。
Docker daemon 日志在 systemd 机器上这样看:
journalctl -u docker -n 100 --no-pager
这里补充一点,很多人只看 docker pull 的终端报错,不看 daemon 日志,容易误判。daemon 日志里能看到是解析失败、认证失败,还是 layer 下载失败。
Docker镜像加速配置放在 daemon.json,不要改错位置
Docker Engine 的镜像加速配置一般写在 /etc/docker/daemon.json。这个文件不是每台机器都有,没有就新建,有就合并配置,别直接覆盖已有的 data-root、log-driver、insecure-registries。
常见写法如下:
{ "registry-mirrors": [ "https://mirror.example.com" ] }
如果文件里已经有其他配置,要注意 JSON 逗号。比如:
{ "data-root": "/data/docker", "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "registry-mirrors": [ "https://mirror.example.com" ] }
配置完重载并重启 Docker:
systemctl daemon-reload
systemctl restart docker
检查是否生效:
docker info
输出里看到 Registry Mirrors,才算 Docker daemon 读到了配置。只是写进 daemon.json 但没重启,pull 行为不会变化。
公共镜像加速地址能用,但不要盲目复制一长串
以前很多国内公共 Docker Hub mirror 很好用,但这两年变化比较大。有的停止服务,有的只给自家云内网用,有的需要登录授权,有的对热门镜像还能缓存,对冷门镜像直接回源失败。
实际使用中发现,daemon.json 里塞十几个 mirror 并不一定更稳。Docker daemon 会按顺序尝试,前面的 mirror 如果响应慢但不立刻失败,反而会拖长 pull 时间。更稳的做法是选一两个确认可用的源,出了问题再换,不要堆配置。
可以用这种方式测一个加速源是否真的可用:
curl -I https://mirror.example.com/v2/
返回 200、401、或者带 Docker-Distribution-Api-Version 相关头信息,都说明它像一个 registry 服务。直接超时、证书错误、返回普通网页,就别放进 Docker 配置。
多说一句,很多所谓“Docker镜像加速地址合集”是过期内容。复制之前看一下最近更新时间,最好在自己的服务器上实际 curl 和 docker pull 测一次。
国内云服务器推荐的配置方式
如果只是单台业务机临时拉镜像,可以直接配置可用 mirror,然后重启 Docker。这个方式成本最低,问题是稳定性取决于第三方 mirror。
如果是多台机器、CI/CD、Kubernetes 集群,就不建议每台机器都依赖公开 mirror。更稳的做法是准备一个自己的 registry cache,或者把常用镜像同步到私有仓库。这样生产节点只访问自己的仓库,外部链路波动不会直接影响发布。
常见场景可以这样拆:
个人测试机:配置 registry-mirrors,够用就行,偶发失败手动重试。
企业业务机:常用镜像提前同步到私有 registry,发布时不直接依赖 Docker Hub。
Kubernetes 集群:节点侧统一配置 containerd 或 Docker mirror,同时在镜像名称上规范化,避免同一个镜像出现 docker.io/library/nginx、nginx、registry-1.docker.io/nginx 这种混用。
跨境业务或海外节点:在海外机房放 registry cache,国内节点按线路质量选择是否走它,不要默认认为海外一定快。
自建 registry cache,适合多台机器和发布频繁的环境
自建缓存仓库的好处是明显的:第一次拉镜像会慢,因为需要回源 Docker Hub;后面再拉同一个镜像层,直接从自己的 cache 出,速度稳定很多。对于 CI 构建、灰度发布、批量扩容,这个差别很大。
Docker 官方 registry 支持 proxy cache 模式,可以这样跑:
docker run -d --restart=always --name registry-cache -p 5000:5000 -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io registry:2
然后在业务机器的 /etc/docker/daemon.json 配置:
{ "registry-mirrors": [ "http://你的缓存服务器IP:5000" ] }
如果走公网,建议上 HTTPS,不建议长期用 HTTP。HTTP 可以在内网临时用,公网暴露 registry 服务要考虑证书、访问控制、防火墙、DDoS 风险。
HTTPS 方式可以用 Nginx 反代 registry,再配置证书。Docker 客户端访问时就写:
{ "registry-mirrors": [ "https://registry.example.com" ] }
这里要注意,registry cache 只缓存被请求过的镜像层,不是把 Docker Hub 全量同步下来。第一次拉一个冷门镜像仍然要看回源链路。生产环境里常用的 nginx、redis、mysql、postgres、openjdk、node、alpine、busybox 这些,建议提前预热。
containerd环境别只改 Docker 配置
现在 Kubernetes 节点很多已经不用 Docker 作为运行时,而是 containerd。这个时候改 /etc/docker/daemon.json 没用,kubelet 拉镜像走的是 containerd。
containerd 的配置一般在:
/etc/containerd/config.toml
如果没有完整配置,可以生成:
containerd config default > /etc/containerd/config.toml
然后找到 registry mirrors 相关位置配置 docker.io mirror。不同 containerd 版本配置格式略有差异,常见结构类似:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://mirror.example.com"]
改完重启:
systemctl restart containerd
验证拉取:
crictl pull docker.io/library/nginx:latest
如果 crictl 不通但 docker pull 通,不要混着判断。Docker 和 Kubernetes 节点运行时可能根本不是同一套配置。
DNS、MTU、防火墙这些小坑也会导致拉取失败
镜像加速不是所有问题的答案。实际现场里碰到过不少“看起来像 Docker Hub 访问慢”的问题,最后原因在网络细节。
DNS解析慢
Docker daemon 默认会使用系统 DNS。如果 /etc/resolv.conf 里写了不可用的内网 DNS,或者云服务器从旧镜像克隆过来后 DNS 没更新,docker pull 会在解析阶段卡很久。
可以在 daemon.json 指定 DNS:
{ "dns": [ "223.5.5.5", "119.29.29.29" ], "registry-mirrors": [ "https://mirror.example.com" ] }
不过这里别乱写。如果服务器在某些云厂商 VPC 内,内网域名解析依赖云厂商 DNS,直接改成公网 DNS 可能影响内网服务发现。
MTU不匹配
云服务器挂了隧道、VPN、GRE、VXLAN,或者容器网络经过多层封装时,MTU 不匹配会导致大包传输异常。表现就是小请求能通,大镜像层下载中途失败。
可以看 Docker bridge 的 MTU:
ip link show docker0
必要时在 daemon.json 配置:
{ "mtu": 1450, "registry-mirrors": [ "https://mirror.example.com" ] }
改 MTU 要结合实际网络,不建议看到别人写 1450 就照抄。公有云普通 VPC 常见 1500,叠加隧道后才需要下调。
安全组和出方向策略
有些企业服务器出方向不是全放通,只允许访问固定端口或固定 IP。Docker Hub 涉及 registry-1.docker.io、auth.docker.io、production.cloudflare.docker.com 等域名,背后 IP 还会变化。安全组如果只放了 443 但出口防火墙按域名或 SNI 做策略,也可能拉不下来。
这种环境更适合内部私有 registry。业务节点只访问内网仓库,外部回源由专门的同步机处理,审计和放行都清楚。
选择云服务器时,镜像拉取也要看线路
很多人买云服务器只看 CPU、内存、硬盘,等部署时才发现 Docker 镜像拉不下来。镜像拉取本质是跨网络下载大量小文件和大 layer,线路质量、国际出口、丢包、晚高峰拥塞都会影响体验。
国内业务节点如果经常要访问海外源,优先看网络质量,而不只是标称带宽。BGP、CN2、GIA、三网精品这些词要结合实际测试,不能只看宣传页。带宽 100Mbps 不代表 Docker Hub 稳定满速,跨境链路丢包 2% 时,下载大 layer 可能就很难受。
如果你也在找这种能承载业务部署、镜像缓存、海外访问中转的云服务器,可以看看129云。它的产品线覆盖高性能云服务器、G口大带宽服务器、高防服务器和海外云计算场景,游戏、企业、高防业务都能选到对应规格。需要确认线路、带宽、防御和机房位置时,直接问客服会省很多测试时间,热线是 400-9177118。
不同场景下怎么选机器
如果只是放一个 Docker registry cache,不一定需要很高 CPU,重点看磁盘、带宽、线路稳定性。缓存命中后主要消耗出方向带宽和磁盘 IO。SSD 比机械盘体验好很多,尤其是多节点同时拉镜像时。
如果业务在海外,国内只是少量管理访问,美国洛杉矶这类节点可以用来跑构建、缓存和海外业务服务。129云美国洛杉矶产品有 1核到4核、1G到8G内存、30G到120G硬盘、30Mbps带宽、200G到4TB流量的配置,适合轻量服务和镜像缓存测试。它标注无回国保障,只计费上行流量,所以不要把它当成国内访问强保障线路用。
如果更看重大带宽分发,比如镜像层比较大、构建产物多、海外访问为主,德国大宽带的 10Gbps 峰值比较适合做大流量下载和分发测试。但它是普通线路,不保证大陆网络访问,用之前要明确访问对象在哪里。
如果服务容易被打,或者 registry 同时暴露给公网业务系统,高防节点就有意义。比如美国高防-B型,4C CPU、4G DDR4 ECC、80G SSD、75Mbps 峰值带宽、1个 IPv4、三网精品、霄龙 CPU、200G 防御。DDoS 风险不高的内部缓存没必要上高防,面向公网客户访问的业务入口才需要重点考虑。
镜像名写法不统一,也会让加速失效
Docker 对镜像名有默认补全规则。比如 docker pull nginx,实际会被解析成 docker.io/library/nginx:latest。很多 mirror 配置只针对 docker.io 生效,如果项目里有人写 registry-1.docker.io/library/nginx,有人写 docker.io/library/nginx,还有人写 nginx,排查时会很乱。
建议业务里统一写法,例如:
docker.io/library/nginx:1.26
docker.io/library/redis:7.2
不要在生产里长期使用 latest。latest 会带来两个问题:缓存不可控,发布不可追踪。今天拉到一个 layer,明天同一个 tag 指向新 layer,节点间版本可能不一致。
在 Kubernetes YAML 里也一样,镜像 tag 尽量固定。发布系统可以用明确版本号或者 digest:
nginx@sha256:xxxxxxxx
digest 写法最稳,但维护成本高一些,适合对一致性要求高的环境。
私有仓库同步比临时 pull 更靠谱
生产环境里常见做法是把外部镜像同步到自己的 registry。比如把 docker.io/library/nginx:1.26 同步成 registry.example.com/base/nginx:1.26。业务发布只从 registry.example.com 拉。
可以用 skopeo、crane、docker pull + docker tag + docker push 做同步。简单命令类似:
docker pull nginx:1.26
docker tag nginx:1.26 registry.example.com/base/nginx:1.26
docker push registry.example.com/base/nginx:1.26
这种方式比 registry mirror 更可控。mirror 是请求时缓存,同步仓库是提前准备好。遇到 Docker Hub 抽风、第三方 mirror 失效、跨境链路抖动,发布系统不受影响。
缺点也很直接:需要维护仓库、清理旧镜像、做权限控制、备份元数据。Harbor 在企业里用得比较多,支持项目、用户、镜像扫描、复制策略。轻量场景用 registry:2 也可以,别把公网匿名 push 打开。
Docker Hub限流也要考虑
Docker Hub 对匿名拉取和免费账号有速率限制。很多服务器共用一个出口 IP 时,很容易被限流。NAT 网关、办公出口、CI Runner 集群都可能遇到。
表现通常是:
toomanyrequests: You have reached your unauthenticated pull rate limit
解决方式不是换 DNS,也不是重启 Docker。要么登录 Docker Hub:
docker login
要么使用自己的私有仓库同步镜像,要么使用有授权的镜像服务。CI 环境里尤其要注意,几十个 Runner 并发构建,很快就能把匿名额度打满。
配置后拉取仍然慢,按这个顺序查
先看 docker info,确认 Registry Mirrors 已经生效。没生效就是配置文件路径、JSON格式、daemon 重启问题。
再用 curl 测 mirror 的 /v2/ 接口。mirror 自己都慢,Docker 不可能快。
然后拉一个小镜像测试:
docker pull hello-world
小镜像能拉,大镜像失败,多半是链路稳定性、MTU、磁盘空间或中途断流。
看磁盘空间:
df -h
看 Docker 数据目录:
docker info | grep "Docker Root Dir"
看是否有残留下载占空间:
docker system df
清理时要谨慎:
docker system prune -a
这条命令会删掉未使用镜像,生产机器上别随手执行。尤其是回滚依赖旧镜像的环境,清掉以后重新拉不下来会很尴尬。
一份比较稳的 daemon.json 写法
单机 Docker Engine 可以按这个结构写,mirror 地址换成自己验证可用的:
{ "registry-mirrors": [ "https://mirror.example.com" ], "dns": [ "223.5.5.5", "119.29.29.29" ], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }
如果服务器已经有 daemon.json,就合并进去,不要覆盖。
执行:
dockerd --validate --config-file=/etc/docker/daemon.json
如果系统里的 Docker 版本支持这个参数,可以提前检查配置。老版本不支持就跳过。
重启:
systemctl daemon-reload
systemctl restart docker
确认:
docker info
拉取:
docker pull nginx:1.26
别把公网 registry 裸奔放出去
自建 registry cache 如果放公网,至少要做 HTTPS、认证、IP白名单或防火墙限制。开放 5000 端口让所有人访问,轻则被别人蹭流量,重则被刷爆磁盘。
Nginx 反代时可以限制 body size、连接数、来源 IP。云服务器安全组只放自己的业务节点 IP。高频拉取场景还要关注磁盘清理策略,registry cache 时间长了会堆很多 layer。
registry:2 的垃圾回收不是简单删目录,清理前要了解 manifest 和 blob 关系。Harbor 的清理策略更直观,但也要定期执行垃圾回收,不然磁盘迟早满。
国内云服务器拉 Docker 镜像,真正稳的是减少外部依赖
临时测试靠 mirror,生产发布靠私有仓库,集群节点统一 runtime 配置,常用镜像提前同步。网络层面把 DNS、线路、MTU、安全组查清楚,别让 Docker 背所有锅。
需要快速验证当前机器问题时,直接跑这几条:
curl -I https://registry-1.docker.io/v2/
docker info
journalctl -u docker -n 100 --no-pager
docker pull hello-world
docker pull nginx:1.26