前言:为什么 Docker Hub 总是拉取超时?
在开发环境中,docker pull 失败往往并不是镜像名称写错,而是 Docker 的网络请求没有经过你已经配置好的 Clash。浏览器能够打开 Docker Hub,并不代表 Docker 守护进程也能使用同一条代理链路。浏览器通常遵循系统代理设置,而 Docker daemon 是独立运行的后台服务,它可能使用自己的 DNS、网络命名空间和代理环境变量。
常见表现包括 i/o timeout、context deadline exceeded、TLS handshake timeout、connection reset by peer,或者卡在 Pulling from library 很长时间后失败。Docker Hub 的镜像拉取通常还会经过认证服务、镜像仓库、内容分发网络和分层文件地址,只放行一个域名,往往无法覆盖完整请求路径。
本文以 Clash 或 Mihomo 内核为例,重点讲解 Linux 主机上的 TUN/透明代理、Docker daemon 代理、DNS 解析与日志排查。目标不是简单地把所有流量强行代理,而是让 Docker 相关域名稳定走指定策略组,同时保留国内镜像、局域网服务和普通直连流量的清晰分流。
本文适用场景
适用于在 Windows、macOS 或 Linux 主机上运行 Docker Desktop,也适用于 Linux 原生 Docker Engine。不同发行版的服务管理命令可能略有区别,但排查思路基本一致。
1先搞清楚:Docker 流量到底经过哪里?
排查前最重要的是区分三类流量。第一类是宿主机上的浏览器或命令行请求;第二类是 Docker CLI 发给本地 daemon 的控制请求;第三类才是 daemon 代表你访问 Docker Hub 并下载镜像层的实际网络请求。很多人只给终端设置了 HTTP_PROXY,却忽略了第三类流量,所以浏览器和 curl 测试正常,docker pull 仍然失败。
| 请求来源 | 典型配置位置 | 常见问题 |
|---|---|---|
| 浏览器或普通应用 | 系统代理、Clash GUI、TUN | 看似正常,但不能证明 daemon 可用 |
| Docker CLI | 终端环境变量、用户配置 | 只影响客户端,不一定影响镜像下载 |
| Docker daemon | systemd drop-in、Docker Desktop 设置 | 最容易漏配,负责真正访问 Registry |
| 容器内部进程 | 容器环境变量、应用配置 | 与宿主机 daemon 代理不是一回事 |
Docker Hub 不只有一个域名
镜像拉取通常会涉及 registry-1.docker.io、auth.docker.io、hub.docker.com 以及由 Registry 返回的 CDN 地址。访问路径还可能因为镜像、地区、认证状态和 Docker Hub 的服务调整而变化。因此,规则应覆盖 Docker 官方域名族群,而不是只写一个精确域名。
判断原则
如果宿主机上的 curl 可以访问 Registry,但 daemon 日志仍然超时,优先检查 daemon 代理;如果 daemon 能连接但解析域名失败,则重点检查 Clash DNS、Docker DNS 和宿主机防火墙。
2Clash 透明代理与 Docker 分流规则
Clash 透明代理的作用,是在系统网络层接管那些没有主动读取代理变量的程序。对于 Linux,通常使用 Mihomo 的 TUN 模式;对于 Windows 和 macOS,Clash Verge Rev 等客户端也可以通过系统扩展或虚拟网卡完成接管。不过,TUN 并不能替代 daemon 代理配置:Docker 使用独立网络栈或 Desktop 虚拟机时,流量未必会按照宿主机预期进入 Clash。
建议先建立一个专用策略组,例如 Docker-Proxy,手动选择延迟稳定、支持 Docker Hub 的节点。不要直接把 Docker 流量绑定到频繁切换的自动测速组,因为下载镜像层时如果出口 IP 中途变化,可能触发 TLS 重连、认证失败或连接被重置。
上面的配置是逻辑示例,节点名称必须替换为你实际订阅中的名称。若使用的是 Clash.Meta 或 Mihomo,字段支持情况还会受到版本影响,导入前应在客户端中执行配置校验。对于企业内网,还应将公司网段、私有 Registry 域名和内部 DNS 放在 Docker 规则之前,避免把内部镜像仓库错误地发送到公网节点。
不要盲目使用全局模式
全局代理虽然便于验证问题,但可能让 Docker 访问局域网 Registry、公司 Git 服务或本地 DNS 时失败。确认问题后,应回到 Rule 模式并使用最小化规则。
3动手配置:为 Docker daemon 设置代理
这是解决 Docker Hub 超时最关键的一步。以下以 Linux 原生 Docker Engine 为例,假设 Clash 的 HTTP 代理监听在宿主机的 127.0.0.1:7890。需要注意,Docker daemon 如果运行在容器、虚拟机或 Docker Desktop 内部,那么其中的 127.0.0.1 指向的是它自己的环境,而不是宿主机。此时应改用宿主机可达地址,例如局域网 IP,或 Docker Desktop 提供的特殊主机名。
- 创建 Docker 服务的 drop-in 目录:
- 创建代理配置文件:
写入以下内容。若 Clash 只监听本机,使用 127.0.0.1;若 daemon 在其他网络命名空间中,请改成实际可访问的地址。
- 重新加载 systemd 并重启 Docker:
- 确认环境变量已被服务读取:
NO_PROXY 非常重要。它用于声明不应经过代理的地址,例如本机、局域网、公司私有 Registry 和内网域名。如果没有正确配置,Docker 可能无法访问内部镜像,甚至因为代理无法解析内部域名而出现看似随机的失败。
Docker Desktop 的配置方式
Docker Desktop 的 daemon 通常运行在独立的 Linux 虚拟环境中,不能简单照搬宿主机的 systemd 文件。打开 Docker Desktop 的设置页面,在 Resources、Proxies 或 Network 相关区域查找代理选项,填入 Clash 的 HTTP 代理地址,并确保 Clash 允许局域网连接。修改后重启 Docker Desktop,再执行 docker info 和 docker pull 验证。
代理协议提醒
Docker daemon 的 HTTP_PROXY 和 HTTPS_PROXY 常常都填写 HTTP 代理 URL,即便目标请求本身是 HTTPS。不要把 SOCKS5 地址直接写进 HTTPS_PROXY,除非当前 Docker 版本和代理链明确支持该写法。
4DNS、TUN 与容器网络的联合排查
Docker Hub 超时有时不是代理没有生效,而是域名解析到了不可达地址。Clash 开启了 fake-ip 后,宿主机应用和 Docker 容器是否使用 Clash DNS,取决于 TUN 路由、Docker DNS 转发和防火墙规则是否完整。部分环境中,容器仍然直接使用 Docker 内置 DNS 127.0.0.11,再由宿主机转发到运营商 DNS,最终造成污染或解析超时。
常用命令与判断方法
正常情况下,访问 Registry 的 /v2/ 可能返回 401 Unauthorized,这并不代表失败,反而说明 TCP、TLS 和 HTTP 请求已经抵达服务端。真正需要警惕的是连接建立前的 timeout、证书握手失败、无法解析主机名,以及被代理返回的 403 或 502。
如果宿主机解析正常但容器解析失败,可以临时为 Docker 指定可靠 DNS,作为定位手段:
修改后执行 sudo systemctl restart docker。生产环境中不要机械复制公共 DNS,应根据网络政策选择可访问的解析服务。如果企业要求使用内部 DNS,应优先保证内部域名解析,再通过 Clash 的 nameserver-policy 或规则区分国内、内网和外部域名。
关于 fake-ip
若某些程序不兼容 fake-ip,可针对域名加入 fake-ip-filter,或暂时切换 redir-host 做对照测试。不要在未确认原因时同时修改 DNS、TUN 和 daemon 代理,否则很难判断究竟是哪项设置解决了问题。
5TLS 与日志分析:定位到底是哪一层失败
当配置较复杂时,最有效的方法是同时观察 Docker 日志和 Clash 日志。Docker 日志可以说明 daemon 在哪个阶段失败,Clash 日志则能确认请求是否进入代理、匹配了哪条规则以及最终使用了哪个策略组。
| 错误表现 | 优先检查项目 | 处理方向 |
|---|---|---|
| proxyconnect tcp timeout | 代理地址、端口、路由 | 确认 daemon 能访问 Clash 监听地址 |
| no such host | DNS 与容器解析 | 检查 daemon DNS、fake-ip 和防火墙 |
| TLS handshake timeout | 节点质量、MTU、TLS 链路 | 更换稳定节点,检查 TUN MTU |
| 401 Unauthorized | 认证流程 | 通常属于正常 Registry 响应,不要误判为网络失败 |
| connection reset | 出口节点或中间设备 | 切换节点并检查代理协议兼容性 |
MTU、证书与中间代理
如果日志显示 TCP 已建立,但 TLS 握手长期停滞,可以尝试降低 TUN 接口 MTU,例如设置为 1400 或更低,再重新测试。某些宽带、虚拟机网卡和 IPv6 环境对大数据包处理不稳定,表现就是小请求成功、镜像大层下载失败。
不要随意关闭 TLS 证书校验,也不要在 Docker daemon.json 中加入没有明确含义的 insecure-registries。Docker Hub 使用 HTTPS,关闭验证不仅不能解决普通代理超时,还会降低供应链安全性。只有在你管理私有 Registry 且明确使用自签名证书时,才应按照企业证书方案配置 CA 或安全例外。
6稳定运行与安全实践
完成首次拉取后,还应验证重启、换网络和多架构镜像场景。建议先拉取一个体积较小的公共镜像,再测试实际项目镜像;观察多层并发下载时是否稳定。对于 CI/CD,不建议依赖开发者电脑上的 Clash,而应在构建节点、代理网关或镜像缓存层明确配置网络路径。
- 固定可用策略组:为 Docker 单独保留一个策略组,避免节点自动切换造成下载中断。
- 使用镜像缓存:团队可以部署 Registry mirror 或 Harbor,减少重复访问 Docker Hub,并降低外部网络波动的影响。
- 保护代理端口:开启
allow-lan后,务必限制监听地址、防火墙来源和访问密码,避免把代理端口暴露给整个公网。 - 保留内网直连:在规则和
NO_PROXY中明确公司域名、私有 Registry、数据库网段和 Kubernetes 内部地址。 - 记录修改内容:每次只改变一个变量,例如先测试 daemon 代理,再调整 DNS,最后处理 TUN,便于回滚和复现。
推荐验证顺序
先用 curl -I -v 验证代理链路,再用 docker run 验证容器解析,最后执行 docker pull 验证 daemon 的完整下载流程。三步都通过后,再恢复项目构建。
常见问题解答
浏览器能打开 Docker Hub,为什么 docker pull 还是超时?
因为浏览器通常读取系统代理,而镜像下载由 Docker daemon 发起。请优先为 daemon 配置 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY,然后重载服务。仅在终端执行 export HTTPS_PROXY=...,通常不能覆盖后台 daemon。
Clash 监听 127.0.0.1,Docker 为什么连接不上?
如果 Docker daemon 位于 Docker Desktop 虚拟机、容器或其他网络命名空间,那里看到的 127.0.0.1 不是宿主机。请改用宿主机可达 IP,开启 Clash 的局域网访问,并通过防火墙限制来源。
访问 /v2/ 返回 401,是不是代理配置失败?
通常不是。Docker Registry 在未携带认证令牌时返回 401 Unauthorized 属于正常流程,说明请求已经到达服务端。若随后拉取仍失败,再检查认证域名、代理日志和 Docker daemon 的完整错误信息。
已经开启 TUN,还需要设置 daemon 代理吗?
建议仍然设置。TUN 能接管部分系统流量,但 Docker Desktop、虚拟机网络、容器 DNS 和 daemon 的特殊路由可能绕过预期路径。daemon 代理属于应用层的明确配置,通常更容易验证,也更适合作为稳定方案。