1. 为什么 2026 年了,Docker 镜像加速还是绕不开的话题
如果你最近折腾过 Docker,大概率遇到过这种场景:pull 一个 ubuntu 镜像,卡在 Pulling fs layer 半天不动;pull 一个 mysql:8.0,进度条跑了几分钟还在等待;更崩溃的是,镜像下到一半直接报 timeout 或者 EOF,然后整个 pull 任务作废,只能重来。
这不是你网络的问题,也不是 Docker 没装好,而是 Docker Hub 在国内的访问链路本身就不稳定。Docker Hub 的镜像存储节点分布在全球各地,走默认路由时经常要绕到境外节点,再加上各种网络波动,拉取速度确实一言难尽。所以从几年前开始,配置国内镜像加速源就成了 Docker 安装部署之后的第一件事,到现在也依然是刚需。
这篇文章整理的是我目前在用的、实测可用的 Docker 镜像加速方案。我会直接给你能用的镜像源列表、具体的配置方式,以及配置之后验证是否生效的方法。文章读完之后,你应该能在 10 分钟内完成环境配置,再也不用盯着进度条干等。
需要说明的是,镜像加速源这个生态变化非常快。今天能用的源,三个月后可能就关了或者限流了;今天没法用的源,可能过段时间又恢复正常了。我的建议是:不要只配一个源,多配几个做兜底,这样才能在某个源出问题时不影响正常工作。
2. 镜像加速到底加的是什么速,先把思路理清楚
2.1 一个 pull 请求背后发生了什么
要理解加速源,得先搞清楚 Docker 拉镜像的基本流程。当你在终端执行 docker pull nginx:latest 时,Docker 守护进程会向镜像仓库(默认是 Docker Hub)发起请求,获取镜像的 manifest 清单,然后根据清单里的层信息,逐层下载镜像数据。
整个过程可以拆成三步:解析镜像名、获取 manifest、下载镜像层。其中下载镜像层是最耗时的部分,因为一个镜像往往由多层组成,每层可能几十 MB 到几百 MB 不等。比如 mysql:8.0 解压后 600 多 MB,如果网速只有几百 KB/s,光下载就得等十几分钟。
加速源的工作原理并不复杂:它是一个反向代理或镜像缓存,部署在离你更近的网络节点上。你把 Docker 的镜像拉取请求指向这个源,它会代替你从 Docker Hub 拉取镜像,然后缓存下来,后续再有相同请求时直接走内网或更快的链路返回数据。对于热门镜像,很多源的缓存命中率非常高,所以速度优势非常明显。
2.2 “加速”解决的三个实际问题
第一个问题就是速度。走加速源拉热门镜像,基本能跑满你的带宽,这比默认链路快几个数量级。
第二个问题是稳定性。镜像拉取经常会遇到 EOF、connection reset 这类报错,这通常不是 Docker 本身的问题,而是链路不稳定导致的。加速源因为链路短、节点多,能明显减少这种中断。
第三个问题是可访问性。有一些容器镜像托管在 Docker Hub 之外的仓库(比如 GitHub Container Registry、Google Container Registry),在某些网络环境下访问困难。部分加速源支持这类仓库的镜像拉取,相当于把一层代理也做了。
2.3 配置加速源不等于把所有镜像都切换到国内
这里要澄清一个常见误区:配置加速源不会影响你拉取私有仓库镜像,也不会影响你 push 镜像。registry-mirrors 这个配置项只对 Docker Hub 的公有镜像生效。如果你拉的是私有仓库的镜像,比如 registry.example.com/myapp:v1,Docker 会直接访问对应仓库,不走加速源。
另外,如果你修改了 Docker Hub 官方镜像的完整名字,比如从 docker.io/library/nginx:latest 改成 nginx:latest,加速源依然能识别并处理。系统内置了对官方命名空间的兼容处理,所以不用太担心格式问题。
2.4 为什么需要准备多个源
加速源本质上也是公共服务,它的稳定性受自身网络条件、流量压力、运营策略影响。一个源在高峰期可能限流,另一个源可能因为域名备案问题临时不可用,还有的可能因为维护导致服务中断。
所以我会在 daemon.json 里配置 2 到 3 个源。Docker 处理多个源的方式是:优先使用第一个,如果失败则自动尝试下一个。这种 failover 机制不需要额外配置,你只要把多个地址按优先级排列即可。实际使用中,这个设计能帮你躲过很多次“某个源挂了”的坑。
3. 实测可用的镜像加速源列表
3.1 当前可用源整理
根据我这段时间的实测,以下几个源目前在国内访问相对稳定,速度和可用性都不错。我把它们分成几档,方便你按自己的网络环境选择。
| 源地址 | 支持协议 | 适用场景 | 备注 |
|---|---|---|---|
| https://docker.1panel.live | https | 通用加速 | 开源面板配套源,可用性较好 |
| https://docker.m.daocloud.io | https | 通用加速 | DaoCloud 提供,老牌稳定 |
| https://dockerproxy.net | https | 通用加速 | 免费公共源,速度波动需自测 |
| https://docker.1ms.run | https | 通用加速 | 服务较稳定,适合日常拉取 |
| https://docker.xuanyuan.me | https | 通用加速 | 个人维护,实测可用 |
| https://docker.foreverlink.net | https | 通用加速 | 备用源,可作为兜底 |
这里要特别提醒:镜像源列表的“时效性”是天然的。今天是这个状态,不代表下个月还是这个状态。我建议你在配置之后,主动跑一个 docker pull hello-world 来测试哪个源真正能用,不要迷信任何文章里写的“推荐列表”——包括我这份。
3.2 几个主流云厂商的源还能用吗
很多老教程里会提到阿里云、腾讯云、网易、中科大这类镜像加速器,它们的规则变化比较大。阿里云的个人版加速器地址是你账号专属的,需要登录容器镜像服务控制台获取,而且现在部分区域的地址已经调整过。腾讯云加速器以及中科大、网易这类高校或企业的源,在不同网络环境下表现差异很大。
如果条件允许,我的个人建议是优先使用自己云厂商提供的加速器地址。因为这类服务有明确的运维保障,而且你使用的是专属地址,不容易被其他人的流量挤爆。缺点是需要在控制台里找一下专属地址,稍微多一步操作。
但我目前无法确认这些厂商加速源是否对所有用户无条件开放,所以稳妥的做法还是先按 3.1 的源配置,如果拉取不到再手动替换成你云厂商提供的专属地址。
3.3 用脚本快速测试一组源
配置多个源之前,先测一下哪些源在你的网络环境下可用,能省去不少试错时间。下面这个 Bash 脚本会逐个测试源是否可以正常拉取镜像:
#!/bin/bash sources=( "https://docker.1panel.live" "https://docker.m.daocloud.io" "https://dockerproxy.net" "https://docker.1ms.run" "https://docker.xuanyuan.me" "https://docker.foreverlink.net" ) for source in "${sources[@]}"; do echo "Testing $source ..." curl -s --connect-timeout 10 -o /dev/null -w "HTTP %{http_code}, time %{time_total}s\n" \ "$source/v2/" || echo "Failed to connect" done这个脚本的原理是请求每个源的 /v2/ 端点,这个接口是 Docker Registry API 的版本检查端点,返回 200 说明源基本可用。执行之后,你能直观看到每个源的响应时间和状态码。把结果最好的几个源选出来,按从快到慢的顺序写进配置里。
4. 配置加速源的标准操作流程
4.1 Linux 环境手动配置
Linux 环境下,Docker 的守护进程配置集中在 /etc/docker/daemon.json。配置镜像加速就是在里面加一个 registry-mirrors 字段。下面是完整配置示例:
{ "registry-mirrors": [ "https://docker.1panel.live", "https://docker.m.daocloud.io", "https://docker.1ms.run" ] }编辑完成之后,执行 systemctl daemon-reload 重载配置,再执行 systemctl restart docker 重启 Docker 服务。
这里有个非常容易踩的坑:如果 daemon.json 文件里已经有其他配置项(比如>{ "data-root": "/data/docker", "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
合并之后应该是:
{ "data-root": "/data/docker", "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "registry-mirrors": [ "https://docker.1panel.live", "https://docker.m.daocloud.io" ] }改完配置后建议先执行 docker info 查看配置是否生效,确认 Registry Mirrors 一栏能看到你填写的地址,再重启服务,避免因为配置格式错误导致 Docker 无法启动。
4.2 Docker Desktop 图形化配置
macOS 和 Windows 上使用 Docker Desktop 的话,配置方式更简单。打开 Docker Desktop,进入 Settings,在 Docker Engine 标签页里会看到一个 JSON 编辑框,里面默认有 dockerd 的配置内容。你在里面追加 registry-mirrors 字段即可。
以 Windows 为例,默认配置长这样:
{ "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "experimental": false }修改后:
{ "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "experimental": false, "registry-mirrors": [ "https://docker.1panel.live", "https://docker.m.daocloud.io" ] }保存后 Docker Desktop 会自动重启引擎。注意 Windows 上如果开启了 WSL 2 后端,配置会同时作用于 WSL 内的 Docker 引擎,不需要额外在 WSL 里配置。
4.3 配置验证的两种方式
配置完成后,验证是否生效有两招。第一招是 docker info,在输出里找 Registry Mirrors 这一行,如果能看到你填写的地址,说明配置被正确加载。第二招是实际拉取一个小体积镜像测试,比如 docker pull hello-world,观察拉取速度是否明显变快。
我个人的习惯是配置完成后立刻跑一次 docker pull nginx:alpine,这个镜像只有几 MB,拉取速度快,而且能直观反映加速源是否真的在工作。如果速度正常,说明配置生效;如果还卡在等待层下载,那就换一个源再试。
4.4 针对 containerd 环境的配置
如果你用的是 Kubernetes 节点,容器运行时是 containerd 而不是 Docker,那么配置方式完全不同。containerd 的配置文件默认在 /etc/containerd/config.toml,你需要修改其中的 plugins."io.containerd.grpc.v1.cri".registry.mirrors 部分。
[plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = [ "https://docker.1panel.live", "https://docker.m.daocloud.io" ]修改后重启 containerd 服务,然后执行 crictl pull nginx:alpine 验证是否生效。这里的逻辑和 Docker 的 registry-mirrors 类似,只是配置格式完全不同。很多初学者会搞混这两个环境的配置方式,在这里单独提出来。
5. 实战中遇到的坑和排查技巧
5.1 配置后 Docker 无法启动
这是最高频的问题,十有八九是 daemon.json 的 JSON 格式错误。常见的低级错误包括:缺少逗号、多了一个括号、末尾多了逗号。JSON 格式严格,最后一项后面不能有逗号。
排查方法很简单:先不重启 Docker,执行 dockerd --validate 或者直接在终端执行 python3 -m json.tool /etc/docker/daemon.json,如果报错会直接提示哪一行有问题。改好之后再重启。
还有一种情况是 Docker 服务没有重载配置。修改 daemon.json 之后,必须先执行 systemctl daemon-reload,再执行 systemctl restart docker,两个步骤缺一不可。如果你跳过了 daemon-reload,服务重启时读到的还是旧的 systemd unit 配置,daemon.json 的改动不会生效。
5.2 certificate signed by unknown authority 报错
这个报错通常是因为你配置的加速源地址写错了协议,或者使用了不支持的 http 地址。Docker 默认要求镜像仓库走 HTTPS,如果源只支持 HTTP,你需要把地址明确写成 http:// 开头,同时把 insecure-registries 配置加上。但我不推荐这么干,毕竟 HTTP 链路有被劫持的风险。
另外,有些加速源使用了非公信 CA 签发的证书,或者证书链不完整,也会触发这个报错。这种情况建议直接换一个源,不要尝试绕过证书校验,安全底线还是要守住。
5.3 manifest unknown 或者 no such host
出现 manifest unknown 大概率是镜像名打错了,或者源缓存的数据不完整。换个源再试一下就能定位问题。no such host 则说明域名解析失败,可能是源已经停止服务,或者你的 DNS 有问题。
此时最快的处理方式就是:docker info 看一下当前配置了哪些源,临时把第一个源去掉,让 Docker 自动 failover 到下一个源,再重新 pull 一次。如果所有源都失败了,回到第 3.3 节用 curl 脚本测试一下,看看是不是源的域名已经无法解析了。
5.4 Docker Hub 镜像和 GHCR 镜像的拉取策略
有些镜像并不在 Docker Hub 上,比如 ghcr.io 开头的镜像。这类镜像如果直接 pull,走的链路可能同样不理想。不过加速源通常只管 docker.io,不一定支持 ghcr.io 的代理。对于这类镜像,我的经验是:在镜像源列表里找一个明确支持 ghcr 代理的源,或者手动把镜像拉下来再重新打 tag 传输到目标机器。
这里补充一个实际可操作的技巧:如果你在服务器上需要拉一个 ghcr.io 的镜像,但网络访问很慢,可以先在一台网络正常的机器上 docker pull 导入镜像,再通过 docker save 导出为 tar 包传到服务器,最后 docker load 导入。虽然步骤多一点,但稳定可控,适合在批量部署时使用。
5.5 镜像拉取到一半卡住的问题
镜像拉取卡住,常见原因有两个:网络波动导致连接中断,但连接状态没有立即释放;磁盘空间不足导致层数据写入失败。
网络波动导致的卡住,通常 Ctrl+C 中断后重新 docker pull 就能解决。如果反复在同一层卡住,很有可能是这个镜像的某层数据在当前链路上不完整,换一个加速源往往能绕过。
磁盘空间不足则更隐蔽,报错可能只在最后阶段出现,比如 write /var/lib/docker/tmp: no space left on device。此时需要清理 Docker 的悬空镜像和停止的容器,释放空间。我常用的命令是 docker system prune -a --volumes,执行前确认你不再需要已停止容器和未使用的镜像。
5.6 常见问题速查表
| 现象 | 可能原因 | 快速解决办法 |
|---|---|---|
| docker info 中 Registry Mirrors 为空 | daemon.json 未生效 | 检查路径、执行 daemon-reload、重启 docker |
| pull 报 timeout | 源不可达或网络波动 | 换一个源,或调整配置中的源顺序 |
| pull 报 certificate error | 源的证书问题 | 换用 https 地址,或直接换源 |
| pull 报 manifest unknown | 镜像名错误或源缓存异常 | 核对镜像名,换源重试 |
| pull 无限卡层 | 链路不稳定或源限流 | Ctrl+C 中断后重试,换源 |
| no space left on device | 磁盘或 Docker 目录空间不足 | 清理残留镜像和容器,释放空间 |
这张表基本覆盖了我日常运维中遇到的 90% 的镜像拉取问题。遇到问题先对照这张表排查,通常不用折腾太久。
6. 加速方案之外的三个实用建议
6.1 用更小的基础镜像减少拉取压力
以 nginx 为例,nginx:latest 的体积大约 190MB,而 nginx:alpine 只有 45MB 左右。对于日常开发测试、小型服务部署,alpine 版本完全够用。基础镜像越小,拉取速度越快,磁盘占用越少,启动也更快。
我在实际项目里,会尽量选择 alpine 或 slim 标签的镜像。如果项目里有自定义镜像,也会基于 alpine 构建,而不是用 Ubuntu 或 Debian 的完整基础镜像。这样不仅能降低镜像仓库的存储成本,也能显著减少每次部署时拉取镜像的耗时。
6.2 固定镜像版本而不是用 latest
使用镜像时绑定精确版本号,而不是 latest。原因有两点:一是可复现性,部署环境的镜像版本不会因为远端更新而变化;二是省流量,拉取相同版本的镜像时,如果本地已经有缓存层,Docker 会直接复用,不需要重复下载。
举个例子,部署 MySQL 时指定 mysql:8.0.40,部署 Redis 时指定 redis:7.2.5。这样即使加速源偶尔抽风,你本地已有的镜像层也能减少对网络的依赖。
6.3 在内网环境部署私有镜像仓库
如果是团队协作或者生产环境,给服务器单独部署一个私有镜像仓库才是长久之计。你可以用 registry 镜像起一个私有仓库,或者搭建 Harbor。内部服务器先通过加速源拉取镜像,然后 push 到私有仓库,其他机器统一从私有仓库拉取。
这样做的最大价值在于:加速源只在初始化时使用一次,之后所有机器都走内网,速度更快、更稳定,也不受公共源可用性的影响。对于有条件的读者,这其实是比镜像加速更彻底、更可控的解决方案。
7. 最后说几句我的实际体会
镜像加速这个事,看着简单,但真正稳定好用需要一点耐心。我踩过几次坑之后,形成的习惯是:配置 2 到 3 个源做兜底,配置完成后必须实际拉一次镜像验证,而不是看了 docker info 就认为万事大吉。
我个人目前的首选组合是 docker.1panel.live 配合 docker.m.daocloud.io,一个做主力,一个做备用。这套组合在最近的日常使用中表现比较稳定,拉取热门的 nginx、mysql、redis 等镜像基本能维持较快的速度。当然,不同网络环境下表现会有差异,你完全可以根据自己的实测结果调整顺序。
最后再分享一个小技巧:如果你经常需要批量拉取同一组镜像,可以把镜像列表写成一个脚本循环执行,配合加速源测试脚本使用,能在做环境初始化的同时快速验证源是否正常。镜像加速不是一劳永逸的,但把它当作环境管理的一部分勤加维护,反而能帮你省下大量等待时间。