先定位失败发生在哪一层
| 失败位置 | 真正发起请求的部分 | 应检查的配置 |
|---|---|---|
| docker pull 拉不下镜像 | Docker daemon 或对应构建后端 | Engine 守护进程 / Desktop 代理 |
| Dockerfile 的 RUN 下载失败 | 构建步骤所在环境 | 构建代理参数、构建网络 |
| 容器启动后访问 API 失败 | 容器内应用 | 容器环境或应用自身代理 |
| FROM 基础镜像下载失败 | 构建器获取镜像 | 构建器/daemon 出口,不只是 RUN 参数 |
先记录 Docker Desktop 还是原生 Docker Engine、版本、docker context show 的结果,以及失败的具体步骤。远程 context 或独立 BuildKit 的网络不一定在本机。不要因为本机 curl 成功,就推断远端守护进程也能连接 127.0.0.1。
第一层:镜像拉取走 daemon 或 Desktop 的设置
Docker Desktop 使用它自己的代理设置;官方文档明确指出 Desktop 会忽略 daemon.json 中的代理配置。原生 Docker Engine 则可按守护进程文档配置 daemon.json 或服务环境。先备份既有文件并合并 proxies 对象,不要覆盖其他存储、镜像和日志设置。下面演示的是支持这些字段的原生 Engine,不适用于 Desktop。
{
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890",
"no-proxy": "localhost,127.0.0.1"
}
}这里 https-proxy 的值仍可使用 http://,表示以 HTTP 代理建立 HTTPS 隧道,不表示把目标网站改成 HTTP。原生 Engine 的配置需按安装方式重启服务才生效;重启可能影响运行任务,应先保存工作并安排窗口。代理不在 daemon 所在主机时,127.0.0.1 必须更换。
第二层:构建步骤使用预定义代理参数
docker build \
--build-arg HTTP_PROXY=http://proxy.example.internal:7890 \
--build-arg HTTPS_PROXY=http://proxy.example.internal:7890 \
--build-arg NO_PROXY=localhost,127.0.0.1 \
-t local/network-check .proxy.example.internal 是占位地址,需换成真实可达的代理。Docker 提供的这些预定义参数无需在 Dockerfile 里额外声明。默认会从缓存和 docker history 中排除;若在 Dockerfile 中主动引用或打印它们,可能改变这一保护。不要用 ENV 把账号密码长期烘焙进镜像,也不要在排障日志里输出完整带凭据的代理 URL。
第三层:运行中容器的 localhost 是容器自己
Docker Desktop 可使用官方提供的 host.docker.internal 访问宿主服务,但服务的监听和防火墙仍须允许实际路径。原生 Linux Engine 不应默认假定这个名字可用,应按当前网络和 Engine 文档确认宿主入口。不要为了解决名字解析而给所有容器添加不必要的特权或 host 网络。
运行时可通过应用配置或 HTTP_PROXY、HTTPS_PROXY、NO_PROXY 等变量传入代理,但不是所有应用都采用相同变量规则。Docker 客户端的 ~/.docker/config.json 中 proxies 配置会给新容器和构建设置代理变量,不负责 Docker CLI 或 daemon 自身出站,也不会自动修改已运行的容器。
按三层分别验收与回退
- 先拉取一个体积适中的可信镜像,确认实际完成,区分网络错误、仓库认证错误和限流。
- 再运行原先失败的构建步骤,检查日志确实完成下载;缓存命中不能证明新配置的网络可用。
- 最后在目标容器里执行它本来要做的 API 或下载操作,确认应用自己使用了代理。不要只测宿主机浏览器。
- 失败时恢复对应层的旧配置,按需重启服务或重建容器,并撤销临时构建参数。持久数据留在原卷里,不需要删除全部镜像和数据卷。