通 途

首页 › 镜像拉取超时

Docker在国内拉取镜像总是超时且连接被取消该如何排查

很多人发现,在浏览器里打开hub.docker.com一切正常,可一执行docker pull就卡住甚至直接报错,这不是网速问题,而是docker pull走的根本是另一条网络路径。

你看到的报错:浏览器能打开,docker pull却握手超时

典型场景是这样的:hub.docker.com在浏览器里点开毫无压力,图片、页面都能加载,可命令行里一敲docker pull,进度条卡在拉取某一层不动,过一会儿抛出TLS handshake timeout,或者干脆是net/http: request canceled while waiting for connection。有人会怀疑是不是账号没登录、是不是镜像名打错了,反复重试几次,结果一样超时。

把这两件事放在一起看才是关键的疑点:同一台机器,同一条网络线路,为什么浏览器行,命令行不行?

真正的原因:docker pull和浏览器根本不是同一个连接的发起者

浏览器访问hub.docker.com,走的是浏览器自己的网络栈,如果你系统里配置了代理或者浏览器插件在生效,浏览器会照着用。但docker pull不是浏览器发出去的请求,它是Docker Desktop背后那个守护进程(daemon)自己发起的一整套TCP连接、TLS握手、层级下载,这个进程默认根本不读取浏览器的代理设置,也不读取你在终端里临时设置的那个代理环境变量——因为拉取动作真正执行的地方,是那个常驻后台的守护进程,不是你敲命令的那个shell进程。

这就是为什么单开一个终端设代理、或者装个浏览器插件,对docker pull完全没用:代理配置根本没送到该去的地方,守护进程还是在裸连,连不上就是TLS handshake timeout,连上了半路被打断就是net/http: request canceled while waiting for connection——前者是握手阶段就没建立起来,后者是连接已经在排队等待,还没等到就被取消,两者都是传输层的问题,和账号密码、镜像名对不对没有关系。

半分钟判断:先分清是认证失败还是纯粹的传输超时

先看错误文本本身。如果日志里出现unauthorizedauthentication requireddenied: requested access to the resource is denied这类字样,说明连接其实是通的,问题出在登录凭证或者仓库权限上,和网络链路没关系,去检查docker login的账号状态就够了。反过来,如果看到的是TLS handshake timeoutnet/http: request canceled while waiting for connection,那是连接压根没稳定建立起来,是纯粹的传输层问题,换账号、重新登录都没有用。

十秒钟能做的一个对照测试:在同一台机器上用普通浏览器打开hub.docker.com,如果秒开,再试试docker pull hello-world这种官方基础镜像。如果官方基础镜像能拉下来,但你自己项目里那个私有仓库或者某个小众用户名下的镜像拉不下来,这就不是单纯的网络问题了,而是下一节要说的镜像来源问题。

为什么换成国内镜像仓库,有些镜像能拉,有些还是拉不动

很多排查文章第一条建议就是换成某个国内镜像加速地址。这个思路对一部分镜像确实有用,原理是这些加速服务提前把Docker官方仓库里的公共基础镜像(比如ubuntu、nginx、python这类官方镜像)同步了一份放在国内,你去拉的时候实际走的是国内节点,自然不会撞上前面说的连接问题。

但换了地址以后,还有两类镜像大概率照样拉不动。第一类是某个开发者或组织自己发布在自己用户名下的镜像,这类镜像分布零散、更新频繁,国内加速节点通常只同步官方仓库那一批,不会去同步每一个用户的每一个仓库,所以你要的那个冷门镜像,加速节点上根本没有,请求还是要回源到境外,一样超时。第二类是你公司自己搭的私有仓库,或者第三方付费的私有镜像托管服务,这类地址加速服务完全碰不到,换镜像地址这条路对它无效,该走的网络链路一段都没少。

所以看到换了镜像源还是拉不动不要急着怀疑配置写错了,先确认一下要拉的到底是官方基础镜像,还是某个用户名下的镜像或者私有仓库——这决定了换镜像源这条路能不能走通。

Windows上要让docker pull走得通,代理必须是系统级的

回到最开始的那个疑点:守护进程不认浏览器的代理,也不认某一个终端窗口临时设的代理变量。它在Windows上是作为后台服务常驻运行的,要让它的每一条出站连接都走同一条路径,代理就不能是某个程序自己单独配一下这种按进程配置的做法,而必须是系统级、机器级的,让所有进程(包括那个看不见的守护进程)默认都从同一层网络出口出去,不用逐个软件单独配置。

这也是命令行工具类问题一个共同的特点:它们各自读取代理的方式五花八门,有的认环境变量,有的认配置文件,有的干脆什么都不认,靠单独给每个工具配代理,迟早会漏掉一个。系统级的方案不用猜某个工具认不认代理,机器上所有联网的程序,包括docker的守护进程、包管理器、命令行工具,统一从同一条链路出去,终端和命令行工具因此天然被覆盖,不需要额外为每个工具单独设置代理。

动手顺序

  1. 先确认症状:错误文本里出现的是TLS handshake timeoutnet/http: request canceled while waiting for connection这类传输层错误,还是unauthorized/denied这类权限错误——两者的排查方向完全不同。
  2. docker pull hello-world之类的官方基础镜像做对照测试,确认基础连接能不能通。
  3. 如果官方基础镜像能拉、自己的私有仓库或某用户名下的镜像拉不动,问题在于该地址是不是被加速节点覆盖,而不是代理没配好。
  4. 如果连官方基础镜像都拉不动,检查网络出口是否覆盖了后台守护进程这一层,而不是只给浏览器或某个终端窗口配了代理。
  5. 确认好传输链路之后,再回头检查docker login状态和仓库访问权限,避免把认证问题和网络问题混在一起排查。

拉取动作是后台常驻的守护进程自己发出的,你在某个终端窗口里临时设的变量它读不到。Windows 端接管的是整台机器的出站流量,这类你看不见、也没法逐个配置的后台服务同样在覆盖范围内。

安卓与 Windows 客户端已上线,macOS 与 Linux 开发中。iPhone 暂无原生客户端。出口服务器的访问日志是关闭状态;会话记录表里没有目标地址、域名或 URL 字段。注册即可使用永久免费套餐,按月发放流量额度。客户端在连上之后会做一次真实探测,探测不通就不显示已连接。

取用远航极速客户端 下载安装包 备用线路

据 Docker 官方文档,守护进程的代理要单独配置在 daemon 那一侧,你在终端里设的环境变量只影响命令行客户端自己。

常见问题

为什么浏览器能打开hub.docker.com,docker pull还是超时?

因为docker pull的连接是由后台守护进程自己发起的,它默认不使用浏览器或某个终端窗口临时设置的代理,走的是完全独立的一条网络路径,浏览器能通并不代表守护进程那条路也能通。

TLS handshake timeout和net/http: request canceled while waiting for connection是同一个问题吗?

两者都是传输层没能正常完成的表现,前者是握手阶段一直没建立成功就超时,后者是连接还在排队等待建立就被取消,本质都是连接没稳定建立起来,而不是账号或镜像名的问题。

换成国内镜像仓库地址,是不是就能解决所有镜像拉取超时?

不是,加速节点通常只提前同步了官方公共基础镜像,像用户自己发布的镜像和公司私有仓库这类内容一般不在同步范围内,请求依然要回源到境外,该有的传输问题不会消失。

怎么快速判断是账号权限问题还是网络传输问题?

看错误文本,出现unauthorized或denied一类字样说明连接其实通了,是权限被拒绝;出现握手超时或连接被取消一类字样说明连接压根没稳定建立,是传输层的问题,两者排查方向不同。

为什么给终端单独设置代理变量,docker pull还是不生效?

因为真正发起拉取请求的是后台常驻的守护进程,不是你敲命令的那个终端会话,终端里临时设置的代理变量守护进程根本读不到,必须让代理在系统层面对所有进程统一生效。

命令行工具是不是只要配好代理环境变量就都能用了?

不一定,不同命令行工具读取代理的方式并不统一,有的认环境变量,有的完全不认,逐个单独配置容易漏掉某个工具,系统级的网络出口能让所有联网的进程统一从同一条链路出去,不用逐一配置。

继续阅读:首页 · 依赖装不上 · 推拉代码断流 · Python 装包超时