问题现象

执行 docker build 构建镜像时,无法从私有 Harbor 仓库拉取基础镜像:

ERROR: failed to solve: 192.168.x.x:80/infra/alpine:3.23.2: 
failed to resolve source metadata: failed to do request: 
Head "https://192.168.x.x:80/v2/infra/alpine/manifests/3.23.2": EOF

尝试 docker login 同样失败:

Error response from daemon: Get "http://192.168.x.x:80/v2/": EOF

环境信息

  • Docker Desktop for Windows (WSL2 backend)
  • 私有 Harbor 仓库,HTTP 协议(非 HTTPS)
  • 已配置 Insecure Registries

排查过程

Step 1: 验证网络连通性

ping 192.168.x.x
# 结果: 正常响应,网络可达

Step 2: 验证 Registry 服务状态

curl -v http://192.168.x.x:80/v2/

返回结果:

HTTP/1.1 401 Unauthorized
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="http://192.168.x.x/service/token"
{"errors":[{"code":"UNAUTHORIZED","message":"unauthorized"}]}

关键发现: Registry 服务正常运行,返回 401 表示需要认证,这是预期行为。

Step 3: 检查 Docker 配置

docker info

确认 Insecure Registries 配置:

Insecure Registries:
  192.168.x.x:80
  127.0.0.0/8

配置正确,排除 HTTP/HTTPS 协议问题。

Step 4: 定位根因

继续检查 docker info 输出,发现代理配置:

HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
No Proxy: hubproxy.docker.internal

根因确认: Docker Desktop 配置了代理,但私有仓库地址未加入 No Proxy 列表,导致请求被代理拦截后返回 EOF。

解决方案

方法一:添加 No Proxy 例外(推荐)

  1. 打开 Docker Desktop → Settings
  2. 进入 Resources → Proxies
  3. Bypass proxy settings for these hosts & domains 添加私有仓库地址
  4. Apply & Restart

方法二:临时禁用代理

如果不需要代理,可直接关闭 Manual proxy configuration。

验证修复

# 登录测试
docker login 192.168.x.x:80

# 构建测试
docker build -f deployments/Dockerfile -t your-image:tag .

总结

现象 可能原因 排查方法
EOF 错误 代理拦截 检查 docker info 中的 Proxy 配置
EOF 错误 网络不通 ping / curl 测试连通性
401 Unauthorized 认证问题 正常现象,需要 docker login
HTTPS 证书错误 未配置 Insecure Registry 检查 docker info 中的 Insecure Registries

核心经验: 当 curl 能正常访问但 Docker 客户端返回 EOF 时,优先排查代理配置。


附录:构建阶段网络问题

问题现象

Registry 连接问题解决后,构建过程中 apk add 失败:

WARNING: fetching https://dl-cdn.alpinelinux.org/alpine/v3.23/main/x86_64/APKINDEX.tar.gz: Connection refused
ERROR: unable to select packages:
  ca-certificates (no such package)

原因分析

Docker Desktop 的代理配置影响容器内部网络。即使宿主机能访问外网,容器内的请求仍被代理拦截。

解决方案

方案一:关闭代理

Docker Desktop → Settings → Resources → Proxies → 关闭 Manual proxy configuration

方案二:优化 Dockerfile(推荐)

避免在构建时访问外网,利用基础镜像已有的资源:

# 原始写法(需要网络)
RUN apk --no-cache add ca-certificates tzdata

# 优化写法(无需网络)
# 基础镜像已包含 ca-certificates,时区通过环境变量设置
ENV TZ=Asia/Shanghai

如果代码使用 time.LoadLocation(),需要内嵌时区数据:

import _ "time/tzdata"  // Go 1.15+ 内嵌时区数据

最终 Dockerfile

FROM registry/golang:1.25-alpine AS builder
WORKDIR /app
ENV GOPROXY=https://goproxy.cn,direct
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags='-s -w' -o /api ./cmd/api

FROM registry/alpine:3.23.2
ENV TZ=Asia/Shanghai
WORKDIR /app
COPY --from=builder /api /app/api
COPY configs/config.prod.yaml /app/configs/config.yaml
EXPOSE 8080
ENTRYPOINT ["/app/api"]

附录总结

问题 解决方案
apk 无法访问外网 关闭代理 或 避免构建时下载
需要 ca-certificates 使用已包含证书的基础镜像
需要时区数据 ENV TZ=xxx 或 Go 内嵌 time/tzdata