Docker 拉不动别急着换 DNS:国内镜像加速源挑选、配置与避坑全指南
先说结论
国内网络环境下,Docker 拉取镜像失败,往往不是镜像不存在,也不一定是 DNS 的锅。更常见的原因是:公共仓库的访问链路拥堵、某个加速源临时故障,或者配置文件改对了却没有重启 Docker。
我的建议是:先打开 status.anye.xyz,把它当作“镜像源天气预报”,看多个源最近是否可用;再根据自己的系统改对配置文件;改完先校验 JSON,再重启 Docker,最后用一个小镜像做真实拉取验证。
一、问题背景:为什么昨天能拉,今天就超时?
很多人第一次遇到这个问题,是在部署一个很普通的服务:nginx、redis、postgres,或者 NAS 上的媒体服务。命令可能只有一句:
docker pull nginx:alpine
但终端却出现了超时、context deadline exceeded、TLS handshake timeout、connection reset by peer,甚至长时间停在下载层。换一个镜像标签、重启路由器、修改本地 DNS,有时能暂时恢复,于是大家容易得出一个结论:Docker 太玄学。
其实 Docker 拉镜像像是“从仓库借书”:
- Docker 客户端先找到仓库地址;
- 再通过网络连接仓库;
- 仓库返回镜像清单;
- 客户端逐层下载内容;
- 最后校验每一层是否完整。
这条链路中任何一段堵住,都会表现为“拉不下来”。所以,镜像加速源不是魔法按钮,而是给这条路增加一条更顺畅的入口。
二、问题表现:不要只看网页能不能打开
一个镜像源网页能打开,不等于 Docker 一定能用。选择加速源时,至少要看四件事:
1. 地址是否真的可达
浏览器打开首页,只能证明首页响应了。Docker 还要访问 Registry API、鉴权接口和镜像层下载接口。网页正常、拉取失败,是完全可能的。
2. 是否支持完整的 Docker Hub 加速链路
有些地址只是一个网页代理或搜索页面,并不是 Docker Registry mirror。配置到 registry-mirrors 后,如果 docker info 看不到它,或者 docker pull 仍然直接访问默认仓库,就要怀疑它并非真正的加速服务。
3. 是否持续稳定,而不是刚好今天在线
镜像源很像城市道路:今天通车,不代表明天不施工。稳定性比某一次测速的峰值更重要。家用 NAS 可以接受偶尔切换,CI 构建和生产环境则应该准备备用方案。
4. 是否适合你的使用场景
个人电脑、NAS、家庭服务器、公司 CI 的要求不同。不要把一个“临时可用”的公共源当作生产供应链,也不要把未经确认的地址批量写入所有机器。
三、为什么推荐 status.anye.xyz?
我推荐把 status.anye.xyz 加入收藏,不是因为它承诺“永远最快”,而是因为它把多个 Docker 镜像源放到同一个页面,并进行定期可用性检查。你可以把它理解成车站的电子大屏:它不替你开车,但能告诉你哪条线路刚刚还在运行、哪条线路可能已经拥堵。

实际使用时,我建议按下面的顺序判断:
- 先看最近检查结果:不要只盯着某个源的名字,先看它最近是否持续有响应。
- 优先 HTTPS:没有特殊理由,不要主动选择 HTTP 源。
- 先用小镜像测试:例如
hello-world或alpine,确认链路后再拉几个 GB 的大镜像。 - 保留一个备用源:公共服务会维护、限流或变更,备用入口能减少临时救火。
- 定期复查:镜像源不是一次配置、终身有效;隔一段时间回到状态页复查。
这里有一个容易忽略的细节:状态站展示的是“监测视角”。你的宽带运营商、地区、IPv4/IPv6、代理和 DNS 都可能不同,所以最终结论仍然要以你自己的 docker pull 为准。
四、到底应该修改哪个文件?
Docker 的配置文件像“总电闸旁边的配电箱”:文件内容正确,Docker 才知道该去哪里找镜像;文件路径错了,改完不会有任何效果。
群晖 DSM 7.x:Container Manager
DSM 7.x 通常使用 Container Manager,配置文件是:
vim /var/packages/ContainerManager/etc/dockerd.json
一个常见的配置骨架如下。把 <可用镜像源地址> 替换成你从状态页筛选出的地址,不要机械照抄过时的静态列表:
{
"registry-mirrors": [
"https://<可用镜像源地址>"
]
}
保存后,重启 Container Manager 的 dockerd 服务:
systemctl restart pkg-ContainerManager-dockerd
如果你的 DSM 版本或套件名称不同,先查服务名:
systemctl list-units --type=service --all | grep -Ei 'docker|container'
群晖 DSM 6.x:Docker
DSM 6.x 的 Docker 套件配置文件是:
vim /var/packages/Docker/etc/dockerd.json
配置格式仍然是 JSON,例如:
{
"registry-mirrors": [
"https://<可用镜像源地址>"
]
}
重启 Docker 套件:
synoservice --restart pkgctl-Docker
部分版本也可以通过 DSM 的套件中心停止再启动 Docker;如果命令报“服务不存在”,使用下面的查询命令确认实际服务名:
synoservice --status | grep -Ei 'docker|container'
Ubuntu、Debian、飞牛 OS 等普通 Linux
大多数标准 Docker 安装使用:
vim /etc/docker/daemon.json
没有文件就创建它。示例:
{
"registry-mirrors": [
"https://<可用镜像源地址>"
]
}
校验 JSON:
jq . /etc/docker/daemon.json
如果系统没有 jq,也可以用 Python:
python3 -m json.tool /etc/docker/daemon.json >/dev/null
重启 Docker:
systemctl daemon-reload
systemctl restart docker
systemctl --no-pager --full status docker

五、为什么“改了配置”却没有生效?
最常见的根因有四类:
根因 1:JSON 多了一个逗号
JSON 比 YAML 更严格,最后一个字段后面不能多逗号。下面是错误写法:
{
"registry-mirrors": [
"https://<可用镜像源地址>",
]
}
保存后先执行 jq .,比直接重启更稳妥。Docker 因为配置解析失败而无法启动时,正在运行的容器也可能受到影响。
根因 2:把镜像源写进了错误的文件
群晖不是普通 Ubuntu。你在 /etc/docker/daemon.json 写得再正确,群晖套件也可能根本不读取它。一定要先确认当前 dockerd 的启动参数和套件版本。
根因 3:改完没有重启
Docker daemon 不会因为你保存了文本文件,就自动重新读取所有配置。就像你换了公交站牌,车辆不会瞬间知道新路线;需要重启服务,让它重新加载。
根因 4:把一个公共源配置成唯一依赖
公共源可能临时维护、限流或调整策略。如果只配置一个源,一旦它故障,所有新部署都会一起失败。更好的做法是:先用状态页筛选,保留少量可信候选,并定期复测。
六、registry-mirrors 与 insecure-registries 不是一回事
这是本文最重要的安全提醒。
registry-mirrors:公共仓库的加速入口
它回答的问题是:“我访问公共镜像仓库时,能不能走一个更近、更稳定的入口?”
{
"registry-mirrors": [
"https://<可用镜像源地址>"
]
}
insecure-registries:允许访问 HTTP 私有仓库
它回答的问题是:“我有一个没有 HTTPS 证书的内网私有仓库,Docker 是否允许连接?”
在之前的文章《Docker 镜像不求人:从 0 到 1 在自己家里搭一个私有仓库》中,我们介绍过如何自建 Registry。假设你的内网仓库使用 HTTP,配置可以写成:
{
"registry-mirrors": [
"https://<可用镜像源地址>"
],
"insecure-registries": [
"<你的私有仓库主机>:<端口>"
]
}
这里故意使用占位符,不把任何真实内网地址写进文章。实际部署时替换成你自己的私有仓库地址即可。
为什么叫 insecure?因为 HTTP 没有 TLS 加密和证书校验,链路上的内容可能被窃听或篡改。它像在小区内部允许“明文喊话”:内网测试环境可以接受,跨公网或生产环境不应该这样做。
所以请记住:
registry-mirrors不是给 HTTP 私有仓库放行的。insecure-registries也不是公共镜像加速器。- 私有仓库如果能配置 HTTPS,优先配置 HTTPS。
- 只有在明确知道风险、且网络边界可控时,才使用
insecure-registries。
七、一套更稳妥的验证流程
不要以“服务重启没有报错”作为唯一成功标准。建议按四步验证:
# 1. 查看 Docker 是否读取到了镜像源
docker info | sed -n '/Registry Mirrors/,+5p'
# 2. 查看 daemon 是否正常运行
systemctl --no-pager --full status docker
# 3. 拉取一个小镜像
docker pull hello-world
# 4. 查看镜像是否存在
docker image ls hello-world
群晖上可以使用:
docker info | grep -A5 -Ei 'Registry Mirrors|Insecure Registries'
docker pull hello-world
如果状态页显示可用,但你的 docker pull 失败,按顺序排查:
- 配置文件路径是否与系统版本匹配;
- JSON 是否能被
jq或 Python 解析; - Docker 服务是否真的重启成功;
docker info是否出现预期配置;- 当前网络是否经过代理、IPv6 或 DNS 劫持;
- 换另一个状态页上近期稳定的源复测。

八、Q&A
Q1:镜像源越多越好吗?
不是。配置项是候选入口,不是越多越快。过多、质量不明的地址会增加排查难度,甚至带来不一致行为。建议先选择少量、近期稳定、HTTPS 的候选,出现问题再替换。
Q2:为什么 docker info 里看不到 registry-mirrors?
优先检查三点:改错文件、JSON 无效、Docker 没重启。群晖还要额外确认你修改的是 Container Manager 或 Docker 套件实际使用的 dockerd.json。
Q3:我只在局域网使用,能不能一直开 insecure-registries?
能不能用和该不该长期用是两件事。实验室或隔离内网可以临时使用,但最好仍然给私有仓库配置 HTTPS;至少不要把 HTTP Registry 暴露到公网,也不要把真实内网地址写进公开配置和文章。
Q4:状态站显示可用,我这里还是拉不动怎么办?
状态站是参考,不是你的网络探针。先用 curl、docker info 和小镜像拉取做本地验证,再检查代理、IPv6、DNS、运营商链路和防火墙。必要时换备用源,不要在一条故障链路上反复重试。
Q5:重启 Docker 会不会让现有容器消失?
正常重启 daemon 不会删除容器和镜像,但会造成短暂服务中断。修改前先备份配置;生产环境先确认容器的自动重启策略、挂载目录和业务窗口,再操作。
九、写在最后:把“玄学换源”变成可验证的运维动作
Docker 镜像加速真正难的地方,不是复制一段 JSON,而是建立正确的判断顺序:先观察可用性,再选择 HTTPS 入口;先确认系统路径,再校验配置;先重启 daemon,再用真实拉取验证;遇到内网 HTTP 私有仓库时,单独理解 insecure-registries 的安全边界。
如果你只记住三句话:
- 先看 status.anye.xyz,不要迷信一份过时的镜像源清单。
- 改完配置一定要校验 JSON、重启 Docker、检查
docker info。 registry-mirrors是公共仓库加速,insecure-registries是内网 HTTP 放行,二者不要混用。
参考资料: