问题现象
构建 Docker 镜像时执行:
| |
构建刚开始便失败:
| |
错误发生在:
| |
说明 Docker 甚至还没有开始执行 Dockerfile 中的任何指令。
排查过程
检查 Docker Daemon 代理
Docker 已配置 systemd 代理:
| |
输出:
| |
说明 Docker Daemon 已正确加载代理配置。
检查代理是否可用
使用 curl 直接通过代理访问 Docker Hub:
| |
返回:
| |
其中:
- HTTP/1.1 200 Connection established 表示 HTTP CONNECT 建立成功
- HTTP/2 405 是因为使用了 HEAD 请求,而接口只允许 GET/POST
说明:
- HTTP Proxy 正常
- Docker Hub 可以正常访问
- 网络没有问题
因此可以排除:
- DNS 问题
- 代理失效
- Docker Hub 无法访问
关闭 BuildKit
执行:
| |
镜像立即构建成功。
至此可以确定:
问题仅发生在 BuildKit。
原因分析
Docker Build 实际上有两套实现。
Legacy Builder(传统 Builder)
docker build
│
dockerd
│
读取 systemd 环境变量
│
HTTP_PROXY / HTTPS_PROXY
│
访问 Docker Hub
所有操作均由 dockerd 完成,因此能够正常继承 systemd 中配置的代理。
BuildKit
docker build
│
BuildKit
│
解析 Dockerfile
│
拉取基础镜像
│
访问 auth.docker.io
BuildKit 是独立的构建引擎。
它拥有:
- 独立网络实现
- 并行下载
- Build Cache
- 多平台构建(buildx)
- Rootless 支持
因此代理、DNS、网络配置与 Legacy Builder 并不完全一致。
在某些 Docker 版本(尤其 20.x 左右)以及部分 Linux 发行版中,BuildKit 对代理环境变量、镜像加速器的继承存在兼容性问题。
最终导致:
| |
虽然:
- curl 能访问
- docker pull 能访问(部分环境)
- Legacy Builder 能访问
但 BuildKit 自己访问 Docker Hub 却超时。
为什么关闭 BuildKit 就恢复正常?
关闭 BuildKit 后:
| |
Docker 会退回使用 Legacy Builder。
整个流程重新交给 dockerd:
dockerd
│
读取 systemd 代理
│
HTTP_PROXY
HTTPS_PROXY
│
Docker Hub
由于代理能够正确继承,因此基础镜像能够正常下载。
解决方案
方法一:临时关闭 BuildKit(推荐)
| |
适用于偶尔构建镜像。
方法二:永久关闭 BuildKit
用户配置:
| |
| |
或者:
| |
写入:
| |
方法三:升级 Docker
较新的 Docker(24.x、25.x、26.x)对 BuildKit 的代理继承进行了大量修复。
如果环境允许,建议升级 Docker Engine。
方法四:为 BuildKit 单独配置代理
对于必须使用 BuildKit 或 buildx 的环境,可以为 BuildKit 配置专用代理,而不是仅依赖 dockerd 的 systemd 环境变量。
这种方式适用于 CI/CD、多平台镜像构建等场景,但配置相对复杂。
总结
本次问题最终定位如下:
| 检查项 | 结果 |
|---|---|
| Dockerfile | 正常 |
| Docker Daemon | 正常 |
| HTTP Proxy | 正常 |
| curl 访问 Docker Hub | 正常 |
| Legacy Builder | 正常 |
| BuildKit | 异常 |
根本原因并不是代理配置错误,而是当前 Docker 版本下 BuildKit 与代理环境之间存在兼容性问题。
关闭 BuildKit 后,构建重新由 dockerd 接管,能够正确继承 systemd 配置的代理,因此镜像可以正常拉取并完成构建。