症状复盘:镜像下载卡住、docker pull 报 TLS 握手超时
容器开发里最挫败的画面之一,是终端里一行 Pulling fs layer 之后进度条像被按下暂停键:镜像一直停在 pulling,几分钟后直接抛出 TLS handshake timeout,或笼统的 Docker Hub 拉取失败。有人会在同一台电脑上打开浏览器访问 Hub 网页版却一切正常,于是更困惑——「网络不是通的吗?」
这类问题的共同点是:问题往往出在 Docker 守护进程到注册表(registry)那条链路上,而不是你眼前这个浏览器标签页。TLS 在握手阶段卡住,说明 TCP 可能已建连但证书交换或 SNI 路径被中间设备干扰、路由进了错误出口,或解析得到的 IP 与规则预期不一致。下面我们会把它拆成可执行的排查顺序,并说明为什么 Clash TUN 往往是比「只勾选系统代理」更稳的容器开发代理方案。
合规前提:请在你有权使用的网络环境下操作,并遵守当地法规与用人单位策略。本文仅讨论客户端能力与通用排错思路,不涉及具体商业线路或绕审指导。
为什么「只开 Clash 系统代理」常常治不好 Docker Hub?
许多桌面客户端里的「系统代理」或 Mixed Port,本质是告诉遵守系统网络栈的应用去连本机某个 127.0.0.1:端口。浏览器、部分 GUI 应用会听话;但 docker pull 的流量由后台的 Docker Engine发起,它是否读取你当前 shell 里的 HTTP_PROXY,是否继承 macOS 的系统代理字典,是否走 Windows 上 WinHTTP 的例外列表——组合因平台与安装方式而异。结果就是:你看到「全局绿了」,守护进程仍在按宿主路由表直连,直奔一个对你当前网络不可达的 Hub 出口。
另有常见误区,把失败归为「Docker 坏了」而反复重装 Desktop。实际上更高效的切入点,是先回答三个问题:(1)这条 TLS client hello 实际从哪个本地源地址发出?(2)它命中了直连还是某个代理策略组?(3)DNS 解析是在 Clash 内侧完成还是在运营商递归上完成? 不清楚这三点就去改 daemon.json,往往像在雾里换轮胎。
Clash TUN 为何更适合这条场景?
TUN 模式会在操作系统里挂上一张虚拟网卡,并在路由层面把符合策略的流量交给 Clash(或 Mihomo 等兼容内核)。对 Docker Engine 来说,它仍然只是「发起一个普通的出站 TCP 连接」,不必额外理解 HTTP 代理协议;只要内核路由 + Clash 规则把前往 registry-1.docker.io、auth.docker.io 以及常见 CDN 主机名的流量送进正确的出站,TLS 握手就有机会恢复正常。
这不是说 TUN 一定优于「在 Docker Desktop 里填 HTTP 代理」——两种可以并存——而是当你已经为规则分流投入了一套 Clash 配置时,用 TUN 把「漏网之鱼」 systematic 收编,比在每台机器上维护多种代理形态要省心得多。尤其在团队场景里,新人入职只要导入同一份配置并打开 TUN,就不必先背一遍「哪些工具读环境变量、哪些不读」。
第一步:先证明 Clash 自己到 Docker Hub 侧是通畅的
在动 Docker 之前,用与 Hub 同类的 HTTPS 端点做烟测。你可以在启用系统代理或 TUN 任意一种能稳定工作的模式下,用终端执行(示例域名随官方变化请以实际为准):
# Smoke test: TLS to registry endpoint (adjust if your resolver differs)
curl -vI https://registry-1.docker.io/v2/
若这里已经在多次重试后出现 SSL_ERROR 或长时间挂起,则说明问题在 Clash 出站或本机到节点的链路,应先切换节点、检查 UDP 是否被拦、或核对订阅是否过期——不要急着怪 Docker。只有当 curl 在合理时间内返回 401 Unauthorized 一类响应(registry 对匿名访问返回未授权是正常的)才说明「TLS 已通、HTTP 层正常工作」,可以继续。
第二步:打开 TUN,并处理权限与路由冲突
在 Clash Verge Rev、FlClash、其他 Mihomo 系外壳中启用 TUN,本质是写配置里的 tun.enable: true 并让内核管理路由。平台侧请注意:
- Windows:首次通常需要管理员权限或安装 Wintun;若与公司安全软件冲突,可把客户端加入信任区并避免同时挂两张「抢默认路由」的虚拟网卡。
- macOS:在系统设置里同意网络扩展;若与另一路全局 VPN 并行,观察是谁在改默认路由。
- Linux:需具备创建 TUN 设备的权限;在远端服务器上跑 Docker 而你只在笔记本上开 TUN 时,要记住:TUN 只影响当前这台机器的路由,不会自动改变 SSH 远端的上游网络。
配置片段仅供参考,键名与默认值请对照你所用内核文档:
tun:
enable: true
stack: system
auto-route: true
strict-route: false
strict-route 过激进时,容易误伤局域网或公司内网段;若你发现「Hub 能拉,内网 registry 却爆了」,可以先把该项放宽,再在规则里精确放行 RFC1918 地址前缀。
第三步:对齐 Docker Desktop/Engine 的代理预期
即便启用了 TUN,若你曾经为 Docker 配过陈旧或错误的 HTTP 代理,仍可能出现守护进程坚持走一个已关掉的 127.0.0.1:旧端口。Docker Desktop 的图形界面里通常有「Resources → Proxies」或类似入口,核对与当前 Clash Mixed Port 一致;在 Linux systemd 场景下,则要检查 docker.service 的环境覆盖文件是否残留。
若你决定「完全信任 TUN、不在 Desktop 里写代理」,请确保清掉冲突项,避免形成「TUN 接管了包,守护进程又要把 HTTP 再二次转交给失效的前端」的超长链路。排错时可在拉取过程中打开 Clash 连接列表,观察源进程或目标域名是否出现,若列表里根本没有 Docker 相关流,说明流量仍未进到 Clash。
第四步:规则与 DNS,专治「看似随机」的 TLS 超时
Hub 拉镜像不是单一主机名而是一小簇域名协同工作:认证、manifest、层存储与 CDN可能分布在不同 FQDN 下。若你的规则只对某一个域名放行代理,而 CDN 仍直连撞上劣质 QoS,表现仍是镜像下载卡住。务实做法是:在规则靠前位置用 DOMAIN-SUFFIX 或规则集覆盖 Docker 官方公布的域名集合,并允许它们在需要时走代理策略组,国内镜像加速则显式直连以免绕远。
DNS 侧请记住:GEOIP 与域名规则往往依赖解析阶段拿到的地址。如果 Engine 仍然使用绕过 Clash 的解析路径,可能出现「浏览器命中规则 A、守护进程命中规则 B」的分裂行为。结合你配置里 fake-ip、redir-host、fake-ip-filter 的语义,核对 docker pull 时连接面板里的最终目标 IP 是否解释得通。
第五步:用分层命令验证,缩小故障面
建议按从外到内的顺序收集证据:
- 宿主 shell:
curl -vI https://registry-1.docker.io/v2/(确认 TLS 与 HTTP 行为)。 - 小镜像:
docker pull alpine:latest或任意体积小的官方库(观察层是否连续下载)。 - 若仍失败,记录完整错误栈(含末尾的 SDK 请求 ID 如有),对照 Clash 日志查看同一时间窗口的阻断、超时或直连命中。
这类分层方法能把「问题在节点」「问题在规则」「问题在 Desktop 残留代理」「问题在 DNS」快速分开,避免无效地反复重启 Docker。
可选:镜像加速与国内registry 作为工程兜底
在企业内网或个人学习环境里,除了修正出站,也常配合registry mirror 或私有代理缓存降低对公网 Hub 的依赖。注意镜像加速站的可用性随时间变化,不要把 mirror 配置成唯一退路却不监控健康;当 mirror 自身 TLS 异常时,症状与直连 Hub 失败几乎相同。若你同时使用 Clash 规则,请为 mirror 域名单写策略,避免它们被误送到不匹配的出口。
| 手段 | 优点 | 注意 |
|---|---|---|
| Clash TUN + 规则 | 对守护进程透明,统一分流语义 | 权限与路由冲突需处理 |
| Docker Desktop 代理 | 显式、易图形化操作 | 与 TUN 双开时需避免环路 |
| registry mirror | 减轻公网 Hub 压力 | 需持续验证证书与同步 |
常见问题速查
问:WSL2 里的 Docker 也要开 TUN 吗?
答:WSL2 有独立网络命名空间;常见做法是在 Windows 宿主侧让 Clash TUN 或桥接代理承担出口,再在 WSL 内配置与文档一致的上游,不要假设「宿主 TUN 自动穿透」永远成立。
问:docker login 正常,但 pull 仍然超时?
答:登录走认证域名,拉层数据可能走不同主机与 CDN;请对照连接日志分别核对两条路径上的规则。
问:能不能只靠公司 HTTP 代理不配 TUN?
答:可以,但你要接受「每台机器守护进程是否读代理」的差异;TUN 用路由统一收敛不确定性。
与「单点 SOCKS 工具」相比,为什么仍值得用 Clash 生态?
市面上也存在只为终端封装一层 SOCKS 的小工具,但它们往往没有成熟的规则 DSL,很难同时做到「npm 与 PyPI 走国内镜像、Hub 与 Git 走稳定出境、公司内网域名一律 DIRECT」这类日常开发真实需求;传统全局 VPN 又常把所有流量一桶端到端隧道,想只让容器相关走代理却要整网降速。Clash 系客户端把 TUN、系统代理与端口代理当作同一套策略引擎的不同「油门踏板」,配置文件可读、可版本控制、可归档到团队知识库——这正是高频「容器 + 代理」场景里降低心智负担的关键。
若你正在为自己或同事整理一条可复现的 Hub 拉取修复路径,与其在零散脚本与多款工具之间切换,不如把出站语义沉淀在一份维护良好的 Yaml 与仍在迭代的外壳里。相比每次重装系统都重新猜测「Docker 到底读了哪份代理」,把 Clash TUN 纳入标准开发环境,往往一次配置、长期受益。若你希望从可信来源获取跨平台客户端发行说明与下载聚合,可从本站入口省去甄别旧版安装包的时间成本: