周五下午三点,我准备拉一个mysql:8.0镜像复现线上问题,进度条卡在第三个 layer,几分钟后直接报超时重试失败。同事那边同样卡住,群里一堆人开始互相问“你家网络也断了吗”。其实网络没断,就是 Docker 默认走的官方仓库在我们这边的链路状态实在不稳定。这种场面这几年我碰了太多次,最后养成了习惯:不管在哪台机器上装完 Docker,第一件事就是先把国内镜像源配好,再考虑别的。
这份列表是 2026 年 9 月 13 日重新整理过的版本。这一轮我不但把市面常见的加速源全部重新探测了一遍,还顺手归纳了配置之后的常见报错和排查路线。如果你正被docker pull卡到怀疑人生,或者刚装完 Docker Desktop 却连引擎都启动不了,这篇应该能帮你少走不少弯路。Linux、Windows、macOS 上的配置方法我都会写到,最后还会聊一聊团队场景下更稳的自建镜像方案。
1. 镜像源加速到底在加速什么:先弄懂 registry mirror 的机制
1.1 一次 docker pull 背后经历了什么
很多人以为docker pull就是“下载一个文件”,实际上它的链路比想象中长。客户端先向 registry 发起 manifest 请求,拿到镜像的元数据,然后并行下载多个 layer 压缩包,全部下载完成后再校验、解压、落盘。任何一个环节出现超时、中断、校验失败,整个 pull 就会报错或者卡死。
在国内这个场景下,卡点通常集中在两个地方:一是 DNS 解析结果不理想,域名被解析到一个访问质量很差的节点;二是国际出口链路拥堵,尤其是晚高峰时段,一个几十 MB 的 layer 能拖到几分钟。这两个问题都不是单纯“换网”能解决的,所以才需要镜像加速器这个东西。
1.2 registry mirror 是“前置缓存层”,不是换个仓库
Docker daemon 支持配置registry-mirrors,它的机制是:当你执行docker pull nginx:latest时,daemon 会先去镜像源地址查找这个镜像。如果镜像源里有缓存,直接返回给你;如果没有,镜像源会代替你从上游官方仓库拉取,并把拉下来的镜像保存在自己的缓存里,下次再有人拉同一个镜像就直接命中。
用生活里的事来类比,Docker Hub 就好比品牌总仓,镜像加速器则是开在你家楼下的小型自提点。自提点里有的货,随时拿走;自提点没有的货,它帮你向总仓调货,到了再给你。整个过程对用户透明,你只感觉自己“拿到了货”,而且速度还快不少。
1.3 一个很普遍的误解:加速器不是万能的
配置完加速器之后,拉docker.io官方库的镜像确实会快很多。但如果你拉的是gcr.io、ghcr.io、quay.io、k8s.gcr.io这些非 Docker Hub 的仓库,普通加速器基本管不到。因为 registry mirror 只对docker.io这个上游生效,其他仓库的流量还是走原本的地址。
所以你会看到有些人配置了加速器,但拉某个特定项目镜像时依然慢如蜗牛。这不是配置错了,是概念上没区分开。遇到这类镜像,通常要看项目方是否提供了对应的镜像地址,或者团队内部自行做中转缓存,这部分我在第五部分会详细讲。
2. 2026年9月这轮整理:筛选思路与实测可用列表
2.1 我是怎么筛选的
列出“可用”镜像源这件事,最怕的就是抄一份过期的列表。镜像源和软件一样会维护、会关闭、会针对某个地区限制流量。所以我从 9 月 10 号开始,把网上能搜到的加速源地址全部收集起来,做了一轮批量验证。
验证方法不复杂,但比较耗时间:先对每个地址做 HTTPS 握手测试,再实际执行docker pull拉取一个 50MB 左右的开源镜像,连续测三次,记录总体耗时和成功率。因为国内不同运营商、不同地域访问同一个镜像源的速度差异很大,我还尽量分地域多试了几轮,避免“我这通、你那不通”的偏差。
2.2 第一梯队:云厂商账号专属加速器
这轮测下来,最稳的依然是云厂商提供的容器镜像加速器。它们的特点是绑定个人账号,格式通常是https://<你的专属ID>.mirror.aliyuncs.com这类,各家控制台都有入口。
以阿里云为例,登录容器镜像服务控制台,左侧菜单里有“镜像加速器”,页面会直接显示你的专属加速地址和配置文档。腾讯云、华为云也有类似功能,入口都在各自的容器镜像服务控制台里。这类加速器因为部署节点多、带宽资源充足,是目前家里和办公网络环境下的首选。
提示:这类地址是账号绑定的,千万不要把别人文档里的完整地址直接抄走。同一家云厂商的加速器,不同账号的专属地址不一样,抄过来大概率是不生效的。
2.3 第二梯队:高校和开源社区维护的公共源
中科大、清华 TUNA、网易这些源在历史上都开放过 Docker 镜像加速服务,也帮助过大量用户。但这几年公共源面临的流量压力和维护成本越来越大,有的限制访问频率,有的只允许教育网访问,有的干脆停掉了 Docker 加速服务。我这轮挨个测下来,能稳定通过的越来越少,状态参差不齐。
所以我不建议再把这些公共源当成唯一方案。如果你所在的网络环境下云厂商加速器也表现一般,可以把公共源作为备选写进daemon.json的列表里,但一定要自己实测过,不要看着“曾经可用”就直接配置。
2.4 各类加速源的实测对比
| 加速源类型 | 稳定性 | 速度表现 | 适用场景 | 当前推荐度 |
|---|---|---|---|---|
| 云厂商账号专属加速器 | 高 | 快,地区差异小 | 个人开发机、服务器 | 强烈推荐 |
| 高校/社区公共源 | 中低 | 不稳定,时段性明显 | 备选、多源兜底 | 谨慎使用 |
| 自建 registry mirror | 取决于自身服务器 | 可接受,内网极快 | 团队共享、离线交付 | 推荐团队使用 |
| 来路不明的第三方公共地址 | 极低 | 时快时慢 | 不建议使用 | 不推荐 |
2.5 为什么不建议用“来路不明”的公开加速地址
网上一直流传着各种个人维护的加速地址,有些是临时搭的,挂着挂着就没了;有些则来历不明。把镜像源配置成一个不受信任的地址,等于把你每次拉取的镜像列表和机器信息都交给对方,一旦对方在返回镜像时动了手脚,代价远比你省下的几分钟要大。
我见过一些小团队图省事,直接用了别人文章里随手分享的地址,过了两个月源失效,整个 CI 流程全部卡住,排查了一下午才发现是加速源的问题。这种事一旦发生,省下的时间会加倍还回去。安全风险和稳定性风险都摆在那里,没必要赌。
3. 分平台配置实操:daemon.json、Docker Desktop、Windows 的坑
3.1 Linux 配置:写好 daemon.json,别让格式坑了你
Linux 上配置 Docker 镜像源基本就是改/etc/docker/daemon.json这一个文件。一份典型配置长这样:
{ "registry-mirrors": [ "https://<你的专属ID>.mirror.aliyuncs.com", "https://docker.mirrors.ustc.edu.cn" ] }改完之后需要重启 Docker 服务:
sudo systemctl daemon-reload sudo systemctl restart docker为什么先daemon-reload再restart?因为 systemd 需要重新读取 docker.service 的配置,虽然大多数场景下直接 restart 也能用,但养成先 reload 的习惯可以避免某些环境下的诡异问题。
这里最容易翻车的点在于 JSON 格式。daemon.json是严格的 JSON 文件,不能带注释,不能有多余的逗号。很多人从网上复制配置,把别人写在 JSON 里的# 注释也一起粘进去了,结果 Docker 服务直接起不来。修改后可以用下面这个命令快速校验:
python3 -m json.tool /etc/docker/daemon.json如果输出没有报错,再重启 Docker。我个人的习惯是改配置文件之前先备份一份,比如cp /etc/docker/daemon.json /etc/docker/daemon.json.bak,万一改坏了还能秒回滚。
3.2 Docker Desktop 上的配置路径和 Windows 虚拟化问题
Windows 和 macOS 用户安装 Docker Desktop 之后,配置界面和 Linux 不太一样。打开 Docker Desktop,进入Settings -> Docker Engine,在 JSON 编辑框里把registry-mirrors加上,点Apply & Restart即可。Docker Desktop 实际上是在一个虚拟机里运行 dockerd,你在这里改的配置最终会作用到虚拟机内的 Docker 引擎上。
很多 Windows 用户的痛点其实不在配置镜像源,而是 Docker Desktop 根本启动不了。最常见的一条报错是:
Docker Desktop failed to start because virtualisation support wasn't detected看到这个提示,先别急着重装 Docker。它大概率是系统虚拟化功能没打开。检查步骤如下:
- 打开任务管理器 -> 性能 -> CPU,看右下角“虚拟化”是否显示“已启用”。
- 如果显示“已禁用”,需要进 BIOS/UEFI 开启 Intel VT-x 或 AMD-V 选项,不同主板的菜单名称略有不同。
- 在 Windows 功能中勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”,重启电脑。
- 确认没有安装旧版 Docker Toolbox 与 Docker Desktop 冲突,尤其是那些用过早期版本又卸载不干净的情况。
还有一个高频报错是 Microsoft 官方技术支持里经常出现的:
failed to connect to the docker api at npipe:////./pipe/dockerDesktopLinux这个报错通常在 Docker Desktop 引擎还没就绪时出现。正确的处理方式不是去改什么环境变量,而是先看系统托盘里的 Docker 鲸鱼图标状态:灰色说明还在启动中,绿色说明已就绪,红色说明启动失败。等图标变绿后再执行 docker 命令,问题往往就消失了。如果一直是红色,点右键选择 Restart 重启引擎。
3.3 多源配置的顺序,不是越多越好
daemon.json里的registry-mirrors是一个数组,允许配置多个地址。Docker daemon 在拉取镜像时会按顺序依次尝试这些镜像源。配置多个确实能提高容错率,但这里有个容易忽略的细节:第一个源如果响应很慢但没超时,daemon 会一直等它,导致整体拉取体验反而更差。
所以我不建议把七八个地址全部塞进去,两到三个足够,而且要把最稳定的云厂商加速器放在第一位。公共源放在后面用作兜底,如果第一个源正常,它们基本不会被用到。
3.4 配置完怎么验证是真的生效了
重启 Docker 之后,先确认配置是否被引擎加载:
docker info在输出内容里找到Registry Mirrors一行,能看到你配置的地址列表。然后执行一次真实的镜像拉取:
time docker pull mysql:8.0记录第一次的总耗时。接着再执行一次同样的命令,如果配置的镜像源生效并且网络正常,第二次应该明显比第一次快,因为镜像源已经缓存了 layer。如果两次速度几乎一样慢,说明请求根本没有命中镜像源,需要回头检查配置格式和源地址是否填对。
4. 镜像源失灵后的完整排查链路:从报错到定位
4.1 先把报错分个类
配置完镜像源之后,最常遇到的现象不是“没效果”,而是“比以前更糟”。常见的报错可以分成几类:
| 报错表现 | 可能原因 |
|---|---|
timeout/TLS handshake timeout | 源地址失效、网络不通、源服务器限流 |
received unexpected HTTP status: 503/404 | 镜像源自身故障或该源不提供此镜像 |
| 某个 layer 反复下载失败 | 网络不稳定,镜像源回源拉取时链路中断 |
| docker 服务无法启动 | daemon.json 格式错误或配置了不可访问的地址 |
| 拉取成功但速度没变化 | 配置未生效、镜像源无缓存、请求走到了其他源 |
4.2 一个具体的排查过程
假设你现在docker pull一个镜像,一直卡在waiting或retrying,我会按下面的顺序排查:
先验证配置文件本身是否合法。执行python3 -m json.tool /etc/docker/daemon.json,这一步能过滤掉语法错误。然后看docker info的输出,确认Registry Mirrors显示的确实是刚才配置的几个地址,而不是旧的配置。
接下来直接探测镜像源地址通不通。在命令行执行:
curl -v https://你的镜像源地址/v2/正常情况下 registry 的/v2/接口会返回401或200。如果一直卡在连接阶段,说明网络层面就到达不了这个源,换一个源再说。
最后用排除法逐项隔离:先把daemon.json里的镜像源地址缩减到一个,重启 Docker,再拉镜像。如果单源正常,说明问题出在多个源的优先级或某个源拖后腿上。逐个加回,就能定位到是哪一条配置拖垮了整体。
4.3 配置错镜像源留下的“后遗症”
把镜像源地址配错导致的另一类问题比较隐蔽:Docker 服务能启动,拉镜像也不会报错,但拉到的镜像版本很旧。这是因为某些镜像源对上游的同步不是实时的,缓存里存了某个 latest 标签就长期不更新。解决方式很简单,生产环境不要依赖latest标签,尽量指定精确版本号,更严格的项目可以直接用镜像的 sha256 摘要来拉取。
还有一种更容易被忽略的情况:自建的 mirror 缓存磁盘满了,会导致所有走该源的拉取失败。如果你发现某个 mirror 平时好好的、某天突然集体超时,先上那台服务器看一眼df -h /var/lib/docker,很多时候就是磁盘满了。
4.4 别把所有问题都甩给镜像源
镜像拉取失败的原因不只是网络和源地址。磁盘空间不足时,docker pull会在下载完成后解压阶段报no space left on device,因为解压需要的临时空间往往是镜像本身的一倍以上。权限问题则表现为permission denied while trying to connect to the Docker daemon socket,需要把当前用户加入docker组或者调整 socket 权限。系统时间偏差过大也会导致 TLS 证书校验失败,镜像源地址越正规,越容易触发这个毛病。用date命令快速看一眼系统时间,如果和当前时间差了几分钟甚至更多,先把时间同步问题解决,再回过来排查网络。
排查这些问题时,一个比较实用的思路是:先把配置里的镜像源全部清掉,恢复官方源,确认同一个镜像能否正常拉取。如果官方源能拉,说明镜像本身没问题,再逐步加回镜像源配置。如果官方源也拉不了,那问题大概率不在镜像源配置上,而是网络、磁盘或 Docker 引擎本身的问题。
5. 更进一步:稳定派的自建镜像加速与离线分发
5.1 用 registry:2 自建 mirror,适合团队场景
如果你不是一个人干活,而是团队里有十几个人天天拉镜像,公共镜像源的稳定性很难满足需求。这时候可以考虑自建一个 registry mirror,也就是在团队内网部署一个 Docker Registry 的代理缓存节点。
服务端启动命令很简单,用官方镜像跑一个容器:
docker run -d \ --name mirror \ -p 5000:5000 \ -v /data/mirror:/var/lib/registry \ -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \ registry:2然后在客户端机器的/etc/docker/daemon.json里把registry-mirrors指向内网地址:
{ "registry-mirrors": [ "http://192.168.1.100:5000" ] }需要注意,Docker 默认对http://的 registry 是拒绝的。使用内网 HTTP 地址时,必须在客户端的daemon.json里额外配置insecure-registries:
{ "registry-mirrors": [ "http://192.168.1.100:5000" ], "insecure-registries": [ "192.168.1.100:5000" ] }当然,更规范的做法是给自建 registry 配 TLS 证书,不过在内网环境里大多数团队图省事,直接用 insecure 方案。这个方案提升的是“热镜像”的拉取速度:第一个同事拉完一个镜像,缓存到内网镜像源,后面所有人再拉同一镜像,走的就是内网带宽,快而且稳。但第一次拉取时,镜像源需要从上游拉一遍,速度取决于你部署镜像源的那台服务器的出口带宽,这一点要提前做好预期。
5.2 离线环境兜底:docker save 与 docker load
有些环境更极端,服务器根本没有外网。注册表代理这种方案也用不了,最靠谱的办法就是离线导入。
在一台有网络的机器上拉取好所需镜像,执行:
docker save -o mysql-8.0.tar mysql:8.0生成一个 tar 文件,拷贝到内网机器上再执行:
docker load -i mysql-8.0.tar多个镜像可以合并成一个文件:
docker save -o bundle.tar nginx:latest mysql:8.0 redis:7.2如果目标机器用的是容器运行时而不是传统 Docker,比如 containerd,可以考虑导出 OCI 格式:
docker save --format=oci -o image-oci.tar mysql:8.0离线导入这种方式虽然原始,但在很多政务云、内网隔离环境里反而是最保底的方案。配合镜像加速器,可以形成“有网时靠加速、无网时靠导入”的双保险策略。
5.3 配置好加速源再跑 docker compose 部署,顺序别搞反
现在很多开源项目都提供docker compose部署方式,像 GitLab、Dify、若依(ruoyi)、青龙面板这些,首次启动的关键步骤基本都是拉镜像。我见过不少人是直接把 compose 文件拿过来就docker compose up -d,结果卡在拉镜像环节,然后又回来怀疑项目配置有问题。
正确顺序是先确认镜像源配置生效,再执行 compose 项目。拉镜像这一步如果没解决好,后面所有依赖容器编排的操作都会被拖慢。热搜里经常有人问“Docker 安装 MySQL 8.0 并使用”“Docker 安装 Redis 主从”“Ubuntu 安装 Docker”,这些场景的第一步其实都是同一个问题:把镜像稳定地拉到本地。
举个例子,用 compose 跑 MySQL 8.0 时,镜像源加速只是前置条件,真正决定启动速度的是初始化脚本和卷挂载路径。首次启动如果还要初始化 SQL 文件,建议把初始化文件放到官方指定的/docker-entrypoint-initdb.d目录下,避免自己去覆盖 entrypoint。这些和镜像源是两码事,但经常被人混在一起排查,耗时又费神。
5.4 生产环境部署服务的额外提醒
聊到 compose 生产部署,顺便提一句:生产环境不要依赖latest标签,镜像源缓存导致版本不更新的问题在第二部分提到过,这个教训在 compose 项目里同样适用。compose 文件里应该固定镜像的具体版本,比如mysql:8.0.36而不是mysql:latest,一方面避免意外升级,另一方面也便于利用镜像源缓存加速。
另外,如果你的项目里直接写了完整仓库地址,比如image: ghcr.io/xxx/yyy:1.0.0,前面讲到过,这类地址不走 registry-mirror。团队内部如果经常要拉这类镜像,可以在自建镜像源时额外起一个 registry 实例,把REGISTRY_PROXY_REMOTEURL指向上游仓库即可,原理和代理 Docker Hub 完全一致。
我个人在实际操作中比较固定的组合是:个人开发机上用云厂商加速器打底,团队内网部署一个 registry mirror 做热镜像缓存,遇到离线环境再走 save/load。这三层下来,绝大多数“拉不动镜像”的场景都能覆盖。最后再强调一次,镜像源列表是有时效性的,这份整理代表的是 2026 年 9 月 13 日这轮验证的结果,配置完一定要自己跑一遍docker pull实测,别拿过期列表硬顶。