Administrator
Administrator
发布于 2026-10-28 / 0 阅读
0
0

Docker 故障排查(04):docker pull 超时:区分 DNS、代理、证书和仓库限流

适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用 docker compose V2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。

一、遭遇情况:服务器能访问网页,却拉不下镜像

部署前执行 docker pull nginx:stable-alpine,终端长时间等待后报错:

Error response from daemon: Get "https://registry-1.docker.io/v2/":
context deadline exceeded

有人把浏览器能打开网站作为网络正常的证据,也有人直接更换一个来历不明的镜像地址。本篇的案例设定是:公司网络要求通过代理访问镜像仓库,代理只设置在登录 shell 中,没有设置给 Docker daemon。

排查时不能预先认定一定是代理问题。名称解析、证书、认证和限流都可能导致“镜像下载失败”,但修复方式完全不同。

二、原因分析:真正下载镜像的是后台服务

在常规服务器 Docker Engine 场景中,CLI 向 daemon 发送拉取请求,由 daemon 访问仓库。你在 SSH 终端设置 HTTPS_PROXY,并不自动修改 systemd 启动的 daemon 环境。

如果 context 指向远程服务器,应在那台 daemon 所在机器检查出口网络。本机 curl 成功,不能证明远程服务器的网络也正常。

镜像拉取的分层排查图

三、排查思路:先按错误分类,再做测试

典型信息 先检查的方向
no such host、lookup ... daemon 所在主机的 DNS
i/o timeout、context deadline exceeded 出口、路由、代理、目标响应
x509: certificate signed by unknown authority 信任链、企业代理证书、系统时间
unauthorized、denied 仓库账号、令牌、镜像权限
429、toomanyrequests 拉取配额或请求频率
manifest unknown 镜像名、仓库路径、标签是否存在

1. 在 daemon 所在主机检查 DNS 与 HTTPS

以 Docker Hub 为例:

getent hosts registry-1.docker.io
getent hosts auth.docker.io
curl -I --connect-timeout 5 --max-time 15 https://registry-1.docker.io/v2/
date -Is
sudo journalctl -u docker --since '15 minutes ago' --no-pager

未携带认证信息访问 /v2/,收到 401 Unauthorized 和认证挑战通常说明 HTTPS 请求已经到达仓库入口,不等于拉取认证已完成。一次访问成功,也不能证明后续鉴权和镜像层下载涉及的全部地址都可达。

curl 默认也可能读取 shell 代理。记录它使用的网络路径,与 daemon 的配置对照。分享排查日志前检查代理 URL 是否带有账号密码,避免把认证信息带进工单。

2. 检查服务是否获得代理配置

sudo systemctl cat docker
sudo systemctl show docker --property=Environment

第二条可能显示敏感代理信息,仅在受控终端查看。若终端走代理、daemon 没有代理,而且网络明确要求代理,就形成了与本案例一致的证据。

四、修复实践:给正确的进程配置出口

下面是 systemd drop-in 的示意,代理主机和端口必须替换为组织已经批准的真实值。不要原样使用示例域名。

# /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.test:3128"
Environment="HTTPS_PROXY=http://proxy.example.test:3128"
Environment="NO_PROXY=localhost,127.0.0.1,.internal.example.test"

注意 HTTPS_PROXY 的 URL 可以是 http://,表示通过 HTTP CONNECT 代理访问 HTTPS 目标,具体以代理部署为准。NO_PROXY 用于需要直连的内部目标,不要把真实外部仓库误加进直连名单。

先保存现有 drop-in 和 daemon 配置,确认没有重复且冲突的代理来源;按官方说明编辑后,在维护窗口执行:

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl is-active docker
docker pull nginx:stable-alpine

这里重启的是整台服务器的 Docker 服务,可能影响现有业务,需结合维护安排。若使用 daemon.json 的代理配置方式,应按当前 Engine 版本文档合并并校验,不要同时维护两套不清楚优先级的来源。

五、其他错误不能靠“换代理”解决

证书错误应核对时间、目标域名、信任链和企业 CA 安装要求,不能把关闭 TLS 验证当作常规修复。私有仓库使用自签发证书时,应按仓库证书目录规则配置可信 CA。

认证错误应确认镜像路径及权限,再使用 docker login 登录对应仓库。429 应区分拉取配额和请求过频,减少重复拉取、合理缓存,并按账号策略处理;不要在循环里无限重试。

manifest unknown 则先确认标签是否存在。网络已经到达仓库,也不能下载一个不存在的标签。

六、验证与总结

验证包括:同一 daemon 能拉取预期镜像、镜像可在 docker image inspect 中读取、服务日志没有继续出现相关错误。不要只验证 shell 的 curl,也不要把拉取成功误当作业务容器已经通过健康检查。

排查链路是:确认 daemon 所在机器 → 按错误类型分层 → 用有限超时验证 → 修复对应层 → 再执行原来的 pull。真正有价值的结论应能解释“为何之前失败、为何现在成功”,而不是只留下“换了个地址好了”。

参考资料


上一篇 · 系列目录 · 下一篇


评论