docker pull 走 VPN:守护进程有它自己的网络
拉取是在守护进程里执行的,不在你的 shell 里。先确认上下文,再给那个引擎单独的路径或代理,最后看清是哪一段 registry 交互中断了。
你的笔记本连着公司 VPN,curl 能访问内网 registry,可 docker pull 仍然以 EOF 失败。这并不矛盾。你输入的命令在你的 shell 里执行,但真正的传输发生在 Docker CLI 所选中的那个守护进程里,而那个守护进程可能根本在另一台主机上。必须打通的是它的网络路径,生效的是它的代理设置。
先确认是哪个引擎,而不是先看路由
运行 docker context show 和 docker version。版本输出会打印客户端部分和服务端部分,服务端那一段会告诉你应答的是谁:本地原生引擎、Docker Desktop 虚拟机,还是远程机器上的守护进程。若想更确定,docker context inspect 会显示所选上下文的端点地址,而这些命令都不会改动任何东西。
像 DOCKER_HOST 这样的环境变量,可能悄悄把 CLI 指向你以为并不存在的另一个引擎,这正是「笔记本明明在 VPN 里、拉取却跑到别处」最常见的解释。
守护进程有自己独立的网络身份
远程引擎需要自己获批的通路才能访问私有 registry。给笔记本挂上 VPN 客户端,只是给这台笔记本一条路由,并不会给实验室或云子网里的守护进程同样的私有地址。如果引擎是 Docker Desktop,拉取发生在其虚拟机内部,那台虚拟机有自己独立的网络与代理配置,与你 shell 的环境无关。
所以说,主机上 curl 成功只能证明主机本身,证明不了别的。
查清是哪一段 registry 交互中断了
拉取镜像是一串步骤:认证、取回 manifest,然后是常常被重定向到对象存储或 CDN 端点的 blob 传输。docker login 成功只证明第一步,令牌完全有效时,被重定向的 blob 主机仍可能从守护进程的网络不可达。在动手改动之前,先记下准确时间、镜像引用,以及守护进程或客户端日志里第一条有用的事件。
EOF 本身并不指明原因。它可能是连接被截断、代理丢弃了流、超时,或 MTU 问题;没有带时间戳的事件,就在这些可能之间猜测,正是人们把一台健康引擎拆了重装的由来。把客户端输出里的字节偏移当作数据看待,因为每次都停在同一个大小的传输,与从不开始的传输完全是两码事。把两种结果都记下来,并在多次尝试之间做对比。
配置真正执行传输的那个组件
对原生 Linux 引擎来说,代理属于服务环境,而不属于你的 shell。在 /etc/systemd/system/docker.service.d/ 下放一个 drop-in 文件,写入 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 条目,然后执行 systemctl daemon-reload 并重启,这就是官方文档给出的做法。Docker Desktop 通过自己的设置项暴露同样的值,改 shell 配置文件对两者都不起作用。
如果 registry 需要直接走 VPN 访问,守护进程需要的是解析器、路由,以及有意的代理排除,而不只是排除。NO_PROXY 匹配是对每个组件各自做字符串比对,缺少底层路由的例外只会制造出看起来像代理故障的报错。
当企业 TLS 检查位于获批路径上时,请通过引擎或 Desktop 的工作流安装其受信任根证书。把 registry 加进 insecure-registries 是另一回事,那会关闭校验,并不是信任库配置。
重复一次受控的拉取,并检查究竟变了什么
只改一处边界,重启拥有它的组件,再从同一个上下文重做同一次拉取。要核对产出的镜像引用和 digest,而不是「没有报错」,因为被缓存的层会让第二次尝试走过的路径远少于第一次。把真正发生过的传输留在工单里,因为它们是这次重试究竟测到了什么的唯一记录。
构建步骤和运行中的容器各有自己的网络上下文,所以等拉取本身跑通之后,要把它们当作独立的问题来看待。