上周五下午,同事丢过来一条报错:docker pull卡了十分钟,最后是一句net/http: TLS handshake timeout。我瞟了一眼他那台刚装好的 Ubuntu,第一句话就问:“daemon.json 里配镜像源了吗?” 他愣了半天:“镜像源?不是装完 Docker 直接 pull 就行吗?”
这话我太熟了。国内玩 Docker 的人,几乎都要经历“装好 Docker → 拉个 nginx 卡半天 → 搜国内镜像源 → 配置完秒拉”的循环。问题在于,镜像源这种东西寿命不稳定,去年收藏的配置可能今年已经 404,今天能用的地址明天可能就被限流。所以这才有了这篇内容:把我 9 月 8 日重新实测过的可用镜像源、配置方法、验证手段和排错思路一次性整理出来。不管你是刚入坑的新手,还是帮团队搭环境的运维,照着抄作业就能少踩几个坑。
1. pull 卡在 TLS handshake:镜像源机制到底做了什么
1.1 一条 docker pull 命令背后的完整链路
很多人以为docker pull nginx:latest就是“从网上下载一个文件”,其实它背后是一套相当繁琐的协议流程。Docker 客户端发起拉取后,会经历:
- 解析镜像名:
nginx:latest实际是docker.io/library/nginx:latest的简写; - 请求 Docker Hub 的认证服务换取 token;
- 用 token 获取镜像 manifest(元数据),里面记录了这个镜像包含哪些 layer、什么操作系统和架构;
- 根据 manifest 逐个从 registry 下载 layer 数据;
- 下载完成后解压、组装,生成可运行的容器镜像。
问题就出在步骤 2 到步骤 4:每一步都在和位于海外的服务器通信。国内网络访问 Docker Hub 的认证服务和 CDN 节点,晚高峰时丢包率会明显上升,TCP 拥塞控制一启动,速度直接掉到几十 KB。你看到的现象就是“进度条卡在 downloading 不动”,最后超时。
1.2 镜像源的本质:一个 cache 服务
国内镜像源(registry mirror)干的事情本质上就是“代理缓存”。你在 daemon.json 里配好 mirror 地址后,Docker daemon 拉取镜像时不再直接访问 Docker Hub,而是先访问你配置的镜像源。镜像源如果已经有缓存,就直接把数据吐给你;如果没有缓存,它再去 Docker Hub 回源拉取,然后缓存下来供后续请求使用。
这个机制的关键点有两个:第一,镜像源只能加速 Docker Hub 上的镜像,gcr.io、quay.io、ghcr.io这些第三方仓库它管不着;第二,它是“首次回源、后续命中”的逻辑,所以一个冷门 tag 第一次拉取时,镜像源自己也要去 Docker Hub 拖数据,速度未必快。很多教程没讲清这一点,导致不少人配置完发现“第一次还是慢”就以为配置失败了,其实多用两次就快了。
1.3 为什么镜像源列表需要反复更新
“2026 年最新可用列表”这个说法,本身就暗示了一个现实:没有一份列表是永久有效的。镜像源是纯成本项目,带宽和存储都是钱,运营方一旦停止维护或者被恶意刷流量,随时会关。这些年在国内陆续出现过不少知名源,如今大多已经无法访问。
所以你在网上看到老教程里的docker-cn.com、某些高校源,十有八九已经失效。这也解释了为什么每次 Docker 变慢,大家第一反应都是“去搜一份更新鲜的镜像源列表”——因为旧地址真的会死。收藏一份列表不如掌握验证方法,后面第 4 章我会专门写排查和验证流程。
2. 9月8日下线实测:2026 年还能用的镜像源与废弃名单
2.1 实测可用的镜像源
我这次测试的方法很简单:每个源都直接请求它的/v2/版本端点,能返回200或401的说明服务活着;再分别拉取alpine:latest、nginx:latest、mysql:8.0三个镜像,能正常完成 pull 的列入可用名单。以下是整理结果:
| 镜像源 | 地址 | 类型 | 实测说明 |
|---|---|---|---|
| DaoCloud | https://docker.m.daocloud.io | 公共源 | 存活时间较长,多个云原生项目在用,推荐优先尝试 |
| 1Panel | https://docker.1panel.live | 公共源 | 社区运营,可用性有波动,建议作为备选 |
| 腾讯云内网 | https://mirror.ccs.tencentyun.com | 云内网 | 只在腾讯云服务器内网可达,非腾讯云机器不要用它 |
| 阿里云加速器 | https://<个人ID>.mirror.aliyuncs.com | 云厂商源 | 需登录容器镜像服务控制台获取专属地址 |
| 上海交大 | https://docker.mirrors.sjtug.sjtu.edu.cn | 高校源 | 政策可能调整,需自行确认可达性 |
| 中科大 | https://docker.mirrors.ustc.edu.cn | 高校源 | 长期存在,但对来源 IP 有策略限制,实测时有时不稳 |
上面这几个是我这次测试中表现比较好的。需要强调的是,公共源的状态变化很快,我无法向你保证它们到你手里时还活着,但至少它们是目前存活概率最高的那一批。云厂商源相对最稳,因为它们有商业资源背书,但阿里云需要你有账号,腾讯云内网源则只对自家服务器友好。
2.2 名单之外:这些曾经的名字大概率已经凉了
对照一下也能帮大家避坑。下面这些源在历史教程中出现频率极高,但这次测试基本全部失败,或者返回了异常数据:
https://docker.mirrors.ustc.edu.cn之外的不少高校源:很多高校已经关闭了对校外的镜像服务;- 一些早年很火的公共源:域名直接解析失败,或者证书过期,连 HTTPS 握手都完成不了;
- 某些只提供 HTTP 的源:Docker daemon 默认用 HTTPS 访问 mirror,纯 HTTP 源即使服务活着也连不上。
所以看到“某篇老文章推荐了一个源”时,别急着复制进 daemon.json,先用第 4 章的 curl 命令验一下,10 秒钟的事。
2.3 配置时如何正确选择镜像源
我的建议是不要只配置一个源,也尽量不要学某些教程那样把源地址铺满十几个。Docker 对多个 mirror 的处理是从前往后依次尝试,第一个失败了才用第二个,列太多只会让拉取超时的时间更长。实践中保留三到四个足够了,并且把最快的放在最前面。
3. Linux / Docker Desktop / WSL2 三种配置路径
3.1 Linux 下改 daemon.json:最通用的方案
在 Linux 上,Docker daemon 的配置文件默认是/etc/docker/daemon.json。如果文件不存在就新建一个:
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.1panel.live" ] } EOF然后重启 Docker 服务:
sudo systemctl daemon-reload sudo systemctl restart docker这里有两个容易踩的细节。第一,daemon.json是严格的 JSON 格式,不能包含注释,不能有多余的逗号,否则 Docker 服务可能直接起不来。改完先跑一句sudo dockerd --validate检查,或者直接看systemctl status docker。第二,很多教程会让你在配置多个源时用逗号分隔,但最后一个元素后面不能跟逗号,这个语法错误我见过太多次了。
想确认配置有没有生效,执行:
docker info | grep -A 4 "Registry Mirrors"如果列出了你填的地址,说明 daemon 已经读取成功。
3.2 Docker Desktop 图形化配置:macOS 和 Windows 通用
用 Docker Desktop 的机器不需要去命令行里翻配置文件。打开 Docker Desktop,进入Settings→Docker Engine,右侧就是一个可视化的 JSON 编辑框。把 registry-mirrors 加进去:
{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.1panel.live" ] }点击Apply & Restart,等它重启完成就生效了。
不过这里有个和 Linux 不同的地方:Docker Desktop 在 Windows 上普遍使用 WSL2 后端,如果你本来就在 WSL2 发行版里用apt install docker.io装了独立的 Docker Engine,那 Desktop 的配置和 WSL2 里的配置是两套,谁生效取决于你当前正在用哪套 daemon。如果发现改了 Docker Desktop 的设置后在 WSL2 里拉镜像还是慢,检查一下 WSL2 里是否有一套独立的/etc/docker/daemon.json。
另外,Windows 上如果 Docker Desktop 启动时报 “Virtualization support not detected” 这类错误,问题一般不在镜像源,而是 BIOS 里的虚拟化开关没打开,或者 Hyper-V / Windows Hypervisor Platform 没有被启用。先解决虚拟化问题,再来处理镜像源,顺序别搞反。
3.3 配置 Dockerfile 构建阶段的网络问题
光配 host 上的 daemon.json 还不够。很多人的痛点在于docker build时,Dockerfile 里执行apt-get、pip install、npm install照样卡死。这个问题和 registry mirror 是两回事——构建时容器访问的是系统包仓库,不是镜像仓库。
Dockerfile 里可以顺手把 APT 源和 pip 源也换成国内镜像:
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list \ && apt-get update这类操作能让构建稳定不少。镜像源解决了“下载 Docker 镜像”的问题,但构建过程本身的下载速度需要单独处理。
4. 配置完不生效?一套完整的从 curl 到 docker pull 的排查链路
配置镜像源不是改完文件就万事大吉。我见过太多人配置完之后拉镜像依旧超时,最后发现是源本身已经死了。下面这条排查链路我每次都会用,你也可以当模板存下来。
4.1 第一步:用 curl 验证镜像源是否活着
不要直接拿 docker pull 测试,先用 curl 请求镜像源的版本端点:
curl -I https://docker.m.daocloud.io/v2/返回200 OK或者401 Unauthorized都算正常——401说明服务在,只是要求认证,而/v2/端点通常不需要认证。如果返回000、连接超时、SSL 握手失败,那这个源大概率已经废了。
我习惯同时测多个源,然后挑响应最快的那个放到 daemon.json 最前面。
4.2 第二步:确认 docker info 里的 Registry Mirrors 已生效
docker info | grep -A 4 "Registry Mirrors"如果这里没有列出你配置的地址,说明 daemon 根本没读取到配置。原因无非三种:
- daemon.json 路径不对;
- JSON 语法错误导致 daemon 直接忽略了整个文件;
- 改完没有重启 Docker 服务。
4.3 第三步:常见报错的排查对照
| 报错关键字 | 大概率原因 | 处理方式 |
|---|---|---|
x509: certificate signed by unknown authority | 镜像源证书链有问题或被人替换 | 换一个 HTTPS 源,不要关证书校验 |
http: server gave HTTP response to HTTPS client | 源只提供 HTTP,地址却写成了 HTTPS | 要么换源,要么在insecure-registries里指定该域名(不推荐) |
net/http: TLS handshake timeout | 网络到镜像源完全不通,或源回源卡死 | 换源,或在非高峰时段重试 |
manifest unknown或manifest for ... not found | 镜像源没有缓存这个 tag 或架构 | --platform指定架构,或换源 |
toomanyrequests | 镜像源自身被 Docker Hub 限流了 | 换源,稍后再试 |
dial tcp ... i/o timeout且指向registry-1.docker.io | registry-mirrors 没生效,绕过了镜像源直接走 Docker Hub | 回到第二步检查配置 |
4.4 第四步:实际拉取并记录耗时
排障到最后,还是要落到一次实际拉取上:
time docker pull alpine:latest如果alpine都是秒拉,说明配置没问题;如果alpine都拉不动,那问题大概率在源本身。这时候把 daemon.json 里的源换掉,再重复一次验证。
5. 别把镜像源当万能药:回源缓存、多架构与非 Hub 仓库
5.1 镜像源的“首次回源”机制
很多人配置完镜像源后,第一次去拉mysql:8.0发现还是等了半天,立刻怀疑源有问题。实际上这是 pull-through cache 的正常现象:当镜像源里没有对应镜像时,它需要自己去 Docker Hub 拉取,拉完存起来再给你。所以“第一次慢、第二次快”才是正常规律。想让第一次也快,最好选那些热门的、镜像源大概率有缓存的镜像。
5.2 多架构镜像在镜像源上的表现
nginx:latest这类镜像通常同时支持amd64和arm64,manifest 里会包含一个平台列表。你拉取时 Docker 会根据本机 CPU 架构自动选择对应的 platform。问题是,有些镜像源只缓存了amd64的 layer,你在树莓派这类 ARM 设备上拉取时,它就得重新回源去 Docker Hub 拿arm64的 layer,速度自然慢。
ARM 设备用户如果拉取很慢,可以尝试显式指定平台:
docker pull --platform linux/arm64 nginx:latest虽然指定平台也需要镜像源回源,但可以减少 manifest 解析的一些分叉请求。
5.3 非 Docker Hub 镜像怎么办
registry-mirrors只作用于docker.io仓库。实际生产里经常碰到gcr.io、quay.io、ghcr.io上的镜像,这些配置镜像源解决不了。常规思路是:一是看云厂商是否提供了这些仓库的镜像同步能力;二是通过 Docker 的docker save在能访问的机器上把镜像导出成 tar 包,再拷贝到目标机器docker load。后者在内网离线场景里尤其好用:
# 在下载镜像没问题的机器上 docker pull nginx:1.27 docker save nginx:1.27 -o nginx-1.27.tar # 拷贝到目标机器后 docker load -i nginx-1.27.tar5.4 拉大镜像时的额外技巧
GitLab、PyTorch、TensorFlow 这类体积动辄几个 GB 的镜像,即使有镜像源也不建议直接在慢速网络上硬拉。docker save/docker load组合是团队内部常用的方式。另外,如果你只是要在内网批量分发同一个镜像,可以起一个私有的 Registry 服务,把镜像 push 到内网 Registry,其他机器从内网 Registry 拉取,速度比外网拉快几个数量级。
6. 顺手把 Ollama、Hugging Face、pip 和 conda 也加速了
镜像源解决的问题不止 Docker。我搜了下这两年的热搜词,ollama 国内镜像源、huggingface 国内镜像源、conda 国内镜像源出现频率非常高。模型文件和 Python 包体积同样巨大,既然都配置了 Docker,不如把周边生态一并处理。
6.1 Ollama 模型下载慢的处理经验
Ollama 做本地大模型推理很方便,但ollama pull qwen2.5:7b动辄几个 GB 的模型文件,下载源还在海外,很多时候进度条就是不动。官方目前没有提供像 Docker registry-mirror 一样直接可配的镜像源字段,所以我的做法是绕道:
- 从国内模型站(比如 ModelScope 魔搭社区)下载对应的 GGUF 格式模型文件;
- 写一个 Modelfile,用
FROM指向本地 GGUF 文件路径; - 执行
ollama create从本地文件构建模型。
举一个例子,假设你下载了qwen2.5-7b-instruct-q4_k_m.gguf:
FROM ./qwen2.5-7b-instruct-q4_k_m.gguf TEMPLATE """{{ if .System }}<|im_start|>system {{ .System }}<|im_end|> {{ end }}<|im_start|>user {{ .Prompt }}<|im_end|> <|im_start|>assistant """然后执行:
ollama create my-qwen2.5 -f Modelfile这样绕开了海外的模型下载链路,速度能稳定很多。
6.2 Hugging Face 下载加速
Hugging Face 上托管的模型文件经常好几个 GB,国内直连时容易中断。好在社区有成熟的镜像服务,设置环境变量即可:
export HF_ENDPOINT=https://hf-mirror.com之后不管是huggingface-cli download还是 Python 里的from_pretrained,都会自动走镜像地址,速度提升非常明显,而且不用反复重试。
6.3 pip 和 conda:给 Python 生态也配上镜像
Docker 镜像里跑 Python 应用时,构建阶段大量时间都花在pip install上。与其在 Dockerfile 里碰运气,不如直接把 pip 源固定为国内镜像:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package想永久生效,在~/.pip/pip.conf或/etc/pip.conf里写:
[global] index-url = https://pypi.tuna.tsinghua.edu.cn/simpleconda 用户则修改~/.condarc:
channels: - defaults show_channel_urls: true default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main配置方式和 Docker 镜像源是同一个思路:把访问路径换到国内节点,降低首跳的延迟和丢包概率。
7. 附:一个自动检测源存活状态的小脚本
镜像源列表的特性决定了它需要不断维护。与其每次卡到超时才想起去搜新源,不如把检测动作自动化。下面这个脚本是我一直在用的,遍历你配置的所有镜像源,检查/v2/端点并打印耗时:
#!/usr/bin/env bash mirrors=( "https://docker.m.daocloud.io" "https://docker.1panel.live" "https://docker.mirrors.ustc.edu.cn" ) for m in "${mirrors[@]}"; do code=$(curl -s -o /dev/null -w "%{http_code} %{time_total}s" --connect-timeout 5 -m 8 "$m/v2/") echo "$code $m" done我自己的习惯是每周跑一遍,把输出结果里响应时间最短的源提到 daemon.json 的第一位。镜像源的“最新可用列表”从来都不是静态的,而是一个需要持续观察的动态集合。掌握验证方法、理解回源机制、保持配置可切换,比收藏任何一份所谓“永久可用”的名单都更实际。