出现 docker buildx build 拉取基础镜像比传统 docker build 明显“卡”的情况,90 % 不是 BuildKit 本身变慢,而是默认路径被改变后,把镜像拉到了另一张网卡 / 另一颗 CPU / 另一个守护进程,结果过去配置好的加速器、代理、镜像仓库缓存瞬间失效。常见根因与对应加速办法如下:
- 驱动换了,加速器没同步
buildx 默认会起一个新的 BuildKit 容器(docker-container驱动),它里面走自己的/etc/buildkit/buildkitd.toml,不会继承宿主机/etc/docker/daemon.json里的"registry-mirrors"。
解决:建 builder 时就把加速器写进去docker buildx create \ --name cn \ --driver docker-container \ --driver-opt image=dockerpracticesig/buildkit:master \ --config - <<EOF [registry."docker.io"] mirrors = ["https://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com"] EOF docker buildx use cn
注意,我用的也算是这条路径上的办法,我是在容器上改的config toml文件,结果是下载可以,不会出现30秒的timeout,但是超慢,慢到20M的镜像要1个多小时。真难受
图中1400秒下了7M多,合每秒5KB, 并且它可能会在1小时后挂住,这速度让人抓狂。
-
多平台 = 多架构拉取
只要加--platform linux/amd64,linux/arm64等参数,BuildKit 会把每个架构的 manifest + 配置 + blob 全部拉一遍,体积成倍增加,国内网络下时间自然翻倍。
解决:- 只构建本机架构,去掉
--platform; - 或者先把外网机
docker pull --platform=xxx后docker save回来,再docker load到 buildx 所在机,BuildKit 会优先用本地镜像。
- 只构建本机架构,去掉
-
懒拉取(lazy-pull)失效
BuildKit ≥ 0.9 支持“先只拉 manifest,真正用到 blob 时再拉”,但如果你把输出改成--output type=oci,dest=xxx.tar或--output type=local…,它会一次性拉完所有层,于是“看起来”比docker build慢。
解决:CI 场景可以先--output type=image,name=reg.example.com/app:cache,push=true推到内网仓库,再另做一次docker pull导出。 -
代理没透传
公司环境常用http_proxy/https_proxy。BuildKit 容器里默认读不到宿主机代理变量,需要显式注入:docker buildx create \ --name proxy \ --driver docker-container \ --driver-opt env.http_proxy=http://proxy.xxx:7890 \ --driver-opt env.https_proxy=http://proxy.xxx:7890 docker buildx use proxy -
国内云厂商间歇性阻断 DockerHub
2024 年下半年开始,大批国内镜像站间歇屏蔽 DockerHub,导致无论 docker pull 还是 buildx 都会卡在 “retrying in 5s”。
解决:- 在能出海的节点先
docker pull / buildx imagetools create把基础镜像转存到阿里云 ACR / 腾讯云 TCR; - 在 Dockerfile 里把
FROM node:20-alpine换成FROM reg.example.com/library/node:20-alpine。
- 在能出海的节点先
-
缓存未命中,重复拉取
如果每次 CI 都起一个新的 builder 实例,旧的缓存卷被销毁,BuildKit 只能重新拉取所有层。
解决:- 固定一个 builder 并挂载持久化目录
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10485760 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10485760 - 或者把缓存推到远端仓库
--cache-to type=registry,ref=reg.example.com/app:cache,mode=max
--cache-from type=registry,ref=reg.example.com/app:cache
- 固定一个 builder 并挂载持久化目录
-
网络本身 MTU / DNS 问题
BuildKit 容器默认桥接网络 MTU 1500,在 PPPoE、VPN 场景下容易被拆包,导致 TLS 重传。
解决:docker buildx create \ --name mtu \ --driver docker-container \ --driver-opt network=host # 直接用宿主机网络
结论
docker build 只是跟你本机守护进程打交道,所有“加速器、代理、镜像缓存”继承得顺其自然;而 docker buildx 默认把活交给另一个容器里的 BuildKit,于是过去“调好的网络”瞬间失效,看起来就像“拉镜像突然变慢”。把 builder 的网络、镜像加速、代理、缓存四项一次性对齐,拉取速度就能回到甚至超过原来的水平。