如果你使用 Docker 镜像代理站,可能会遇到一个让人困惑的问题:明明 docker pull
命令可以成功拉取镜像,但在使用 docker build
或 docker compose build
构建镜像时却会失败。这是什么原因导致的呢?
关于 Docker 镜像代理站搭建,可以参考我前面的文章《如何使用 Cloudflare Workers 自建 Docker 镜像代理》和《解决国内无法下载 Docker 镜像的问题》。
问题原因分析 {#问题原因分析}
从 Docker 19.03 版本开始,BuildKit 默认启用作为构建引擎。虽然镜像代理站能够加速镜像拉取,但它本质上只是一个代理层,镜像的 manifest 文件依然指向官方 Docker 地址。当 BuildKit 尝试读取 manifest 文件时,仍需向 auth.docker.io/token
请求匿名 token。然而,由于网络环境(如 GFW)的干扰,这个请求会被阻断,导致构建失败。
错误日志如下:
|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3
| Sending build context to Docker daemon 1.208GB Step 1/6 : FROM pytorch/torchserve:0.11.0-gpu as builder Get "https://registry-1.docker.io/v2/": read tcp 192.168.210.99:53042->54.236.113.205:443: read: connection reset by peer
|
解决方案 {#解决方案}
针对这个问题,有两种主要解决思路:
方法 1:禁用 BuildKit,使用传统构建方式 {#方法-1禁用-buildkit使用传统构建方式}
通过禁用 BuildKit,可以回退到传统的 Docker 构建方式。这种方法分为以下几种场景:
1.1 命令行临时禁用 BuildKit {#11-命令行临时禁用-buildkit}
在构建镜像之前,首先将 Dockerfile 中的基础镜像地址指向镜像代理站。例如:
|-----------|------------------------------------------------------------------------|
| 1
| FROM your-mirror-site/pytorch/torchserve:0.11.0-gpu as builder
|
然后,通过以下命令临时禁用 BuildKit,并使用传统构建方式:
|-----------|-----------------------------------------------------------------------------|
| 1
| DOCKER_BUILDKIT=0 docker build -f Dockerfile -t image-name:latest .
|
或者:
|-----------|------------------------------------------------|
| 1
| DOCKER_BUILDKIT=0 docker compose build
|
又或者直接使用 docker compose up -d
命令,它会拉取和构建镜像,然后启动容器。
1.2 临时环境变量禁用 BuildKit {#12-临时环境变量禁用-buildkit}
你也可以在当前终端会话中通过设置环境变量临时禁用 BuildKit,并在 Dockerfile 中的基础镜像地址指向镜像代理站。例如:
|-----------|------------------------------------------------------------------------|
| 1
| FROM your-mirror-site/pytorch/torchserve:0.11.0-gpu as builder
|
|-----------|----------------------------------|
| 1
| export DOCKER_BUILDKIT=0
|
然后执行构建命令:
|-----------|-----------------------------------------------------------|
| 1
| docker build -f Dockerfile -t image-name:latest .
|
或者:
|-----------|------------------------------|
| 1
| docker compose build
|
或者直接使用 docker compose up -d
命令,它会拉取和构建镜像,然后启动容器。
1.3 永久禁用 BuildKit(不推荐) {#13-永久禁用-buildkit不推荐}
修改 Docker 的环境变量配置文件,永久禁用 BuildKit。虽然方便,但并不建议这样做,因为 BuildKit 目前才是官方推荐的构建工具。
有文章说可以通过
"buildkit": false
配置永久禁用,尝试后发现并没有效果。
方法 2:为 BuildKit 配置代理 {#方法-2为-buildkit-配置代理}
如果已经有网络代理,可以直接为 BuildKit 配置代理,这样就不需要依赖 Docker 镜像代理站了,也就不存在这个问题。可以编辑 /etc/docker/daemon.json
文件,添加以下内容添加 Docker 的代理:
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7
| { "proxies": { "http-proxy": "socks5://192.168.208.55:10808", "https-proxy": "socks5://192.168.208.55:10808", "no-proxy": "127.0.0.0/8" } }
|
注意:Docker 支持配置镜像代理,也就是 mirror,同时也支持配置网络代理,也就是 proxy,这里的代理指的是 proxy。
保存后,重启 Docker 服务使配置生效:
|-----------|---------------------------------------|
| 1
| sudo systemctl restart docker
|
配置完成后,BuildKit 可以通过代理访问网络,从而避免因网络问题导致的构建失败。
总结 {#总结}
Docker 构建失败的问题主要与 BuildKit 的网络访问机制有关。通过禁用 BuildKit或者为其配置网络代理,都可以有效解决问题。如果你希望更灵活的解决方案,可以根据使用场景选择适合的方法:
- 临时禁用 BuildKit:适合短期构建任务;
- 为 BuildKit 配置代理:适合需要长期支持的场景。