为什么浏览器能上,docker pull 还会卡死
在桌面上你已经用 Clash 跑通订阅、分流,浏览器访问 Docker Hub 或国内镜像站似乎「能打开」,但终端里 docker pull、docker build 却频繁 Connection timed out 或极慢。最常见的误解是:「系统能翻墙,所以 Docker 也自动会」。实际上,docker 命令绝大多数情况下对话的是本机的 Docker 守护进程(dockerd),真正发起 HTTPS 去拉镜像层、访问 registry 的,是 守护进程所在网络环境,而不是你浏览器里已经勾上的「使用系统代理」或 Clash 的 TUN/系统代理。另一方面,TUN/路由级透明代理能覆盖很多进程,但 Docker 的虚拟网段、docker0 桥与命名空间,往往会让「是否走了你期望的那条出口」变得不直观。本文刻意落在可复制的路径上:在宿主机上为 Clash 打开一个 显式 HTTP 代理端口,再让 Docker 的客户端与/或守护进程,通过 HTTP_PROXY / HTTPS_PROXY 指过去——这与本站 WSL2 里让 apt 走宿主机 Clash 是平行场景:一个管 Linux 子系统里的命令行,一个管 容器运行时与 image registry 的流量,两者可以并存。
若你希望「机器上所有进程都不用手写环境变量」,那是 TUN 模式 与系统路由的故事;在 Docker 场景里,TUN 有时能减轻配置量,但排障时「显式代理 + 可观测端口」仍是最稳定的学习曲线。本文以 HTTP 代理到宿主机 为主线,和「仅靠镜像加速站」的攻略区分开:你仍然可以在配好出口之后,再叠加 Docker Desktop 镜像、registry 镜像 以减轻公网时延,二者不互斥。
host.docker.internal」;NO_PROXY 能避开不该进隧道的内网与大陆镜像;最后能用一条 docker pull 验证全链路。
宿主机上 Clash:端口、允许局域网与防火墙
和 WSL2 那篇同样,第一步永远是:你的 Clash 入站不能只绑在 127.0.0.1 却指望「来自别的网络命名空间」的连接能碰到它。图形客户端中请打开 允许局域网 / Allow LAN 一类开关,或保证 mixed-port/HTTP 绑定在可对外可见的地址(具体菜单因 Clash Verge Rev 等客户端而异,语义与「监听 0.0.0.0」类同)。把端口记作 7890 仅作示例,你若改过 mixed-port,全文替换成自己的值;若 7890 被占用,可先对照 7890 端口与 mixed-port 排查 把端口理顺。
在 Windows 上,即使开了 Allow LAN,也建议在「防火墙入站规则」里为 Clash 使用的可执行文件或对应 TCP 端口放行,否则常见现象是:宿主机上 curl -x 成功,而来自 Hyper-V/WSL/ Docker 子网的连接被静默丢弃。若你不确定 Clash 是否真的收到了 Docker 的 CONNECT,可打开 连接日志与规则命中,看请求是否进入内核、命中哪条规则,这比盲目改 DNS 更有效。
容器视角下的「宿主机」地址怎么写
在 Docker Desktop(macOS / Windows) 上,最省心的是 host.docker.internal:在容器和 LinuxKit 里它会被解析为可达宿主机,用来填 http://host.docker.internal:7890 一类代理 URL 通常行得通。若你遇到解析或证书相关的边缘问题,可再查阅当前版本的 Desktop 文档中关于 host 网关的说明。
在 原生 Linux / rootful Docker 上,一般没有 host.docker.internal 的默认等同物;更稳妥的是取到宿主机在 docker0 桥或默认路由上那一侧的地址(常见为类似 172.17.0.1 的网桥网关,以你本机 ip route / ip -4 addr 实际输出为准),再与 Clash 的入站地址对齐。若你的 Docker 以 rootless 或自定义网段方式运行,请以官方文档的「宿主机 from 容器」为准,但思路不变:代理 URL 的 host 部分必须是「从容器或守护进程能路由到的宿主机侧 IP」,而不是你浏览器里的「127.0.0.1」心照不宣的等同。
方式一:Docker Desktop 的 Proxies 界面(最直观)
打开 Docker Desktop 设置中的 Resources → Proxies(或相近名称),在 Manual proxy 中填入 Web Server (HTTP) 与 Secure Web Server (HTTPS),例如 http://host.docker.internal:7890,并在下方「绕过」列表中写入不必走代理的地址:至少包含 localhost、127.0.0.1、*.local,以及你计划使用的 国内 registry 与镜像站 域名。保存后让 Docker 重启服务,再试 docker pull。这个入口的好处是 同时照顾守护进程与部分客户端 的期望,和下文配置文件二选一或合并使用前,以你当前 Desktop 版本文档为准,避免双份冲突。
方式二:~/.docker/config.json 的 proxies 与 default
在命令行与 CI 中更可复制的方式,是编辑用户主目录下 Docker 的 config.json,为 default 或特定 registry 写 httpProxy / httpsProxy / noProxy。以下示例中端口与 host 请按上节替换成你的环境(HTTP 与 HTTPS 常指向同一代理即可):
{
"proxies": {
"default": {
"httpProxy": "http://host.docker.internal:7890",
"httpsProxy": "http://host.docker.internal:7890",
"noProxy": "localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
}
}
}
在纯 Linux 上,把 host.docker.internal 换成上节得到的网关 IP。若你只为个别 registry 开代理、其余直连,可以把 default 换成以 registry 域名为 key 的块(以 Docker 当前文档的 schema 为准)。BuildKit 构建时拉基础镜像、访问网络资源,会尊重这套代理配置,便于与团队共享同一 config.json 或 CI 注入。
方式三:为 dockerd 配置环境变量(Linux 上更常见)
如果守护进程是 systemd 管理,可以单独 drop-in 一个 Environment=HTTP_PROXY=... 片段,对 docker.service 重载。注意这会影响该主机上所有 由该守护进程执行的拉取与元数据请求,与「仅用户级 config」的适用范围不同。rootless Docker 的 unit 名与路径不同,务必按发行版与官方文档落盘,不要直接复制不匹配的示例路径。修改后 systemctl daemon-reload 并 restart docker,再观察 journalctl -u docker 是否仍有直连超时。
docker build 与 --build-arg
有些 Dockerfile 在 RUN apt-get 或 curl 阶段需要出网。除全局 config 与 daemon 环境外,你也可以在构建时传入:
docker build \
--build-arg HTTP_PROXY=http://host.docker.internal:7890 \
--build-arg HTTPS_PROXY=http://host.docker.internal:7890 \
.
在 Dockerfile 里用 ARG HTTP_PROXY 接收并在需要 RUN 的层中生效;具体写法以目标基础镜像和包管理器为准。若你使用 docker compose,可在 compose 文件里为 build 段声明 args,避免在 shell 里每次手敲。
NO_PROXY 与国内镜像、Docker Hub 加速
把大陆已能较稳定访问的 registry 镜像、院校与公司内网 写进 noProxy,可以避免本不必出国的流量再绕节点,既省带宽也降低延迟。若你同时在 Docker Desktop 里配置了 registry mirrors 或 镜像加速 地址,请把对应主机名也纳入 noProxy 策略中统筹考虑。关键词「Docker Desktop 镜像加速」的多数教程是在讲 registry mirror,与「为守护进程加 HTTP 代理」解决的是不同层面的瓶颈:前者拉国内缓存,后者解决「到源站/Registry 的跨境链路」问题,实践中经常同时需要。
最小验证顺序
建议先在同一台机器、同一宿主机上,用 curl -x http://host.docker.internal:7890(或你的网关 IP)打一条到公网的 HTTPS 请求,确认 Clash 日志里能看到入站。然后再 docker pull 一个体积小的测试镜像。若 curl 成而 docker 不成,把怀疑放在「config 没生效、Desktop 没重启、或守护进程没吃到变量」上,而不是立刻改容器的 DNS。
与 WSL2、TUN 的边界怎么记
在 Windows 上,你可能同时有 Docker Desktop 的 WSL2 后端 与日常开发用 WSL2 发行版。本文聚焦「Docker 拉镜像与 build」;若你要让 发行版里 apt、git 走宿主机 Clash,仍请回到 WSL2 与宿主机 Clash 的环境变量 分步做,二者命令空间不同、不要混为同一组 export。若你尚未安装桌面端 Clash,可先从 Clash Verge Rev on Windows 教程 把基础订阅与入站设稳,再打开本文的 Docker 侧步骤。
相比在镜像内再跑一套带内核的 Clash,把 代理的单一事实来源 放在宿主机、用显式 HTTP_PROXY 把 Docker 挂上去,长期维护与排障都更简单。把规则与策略组只维护一份在 Clash 里,也更容易和站点其他教程对齐。想换客户端或新机器时,从本站 Clash 客户端下载页 取各平台包,配合 使用文档 对字段做一次核对即可。相比在容器里东拼西凑,让本机上的 Clash 做稳定出口、Docker 只负责声明「往哪里指」,日常开发往往更省心。→ 立即免费下载 Clash,开启流畅上网新体验