适用:使用 systemd 的 Linux 服务器、常规 rootful Docker Engine;Compose 示例使用
docker composeV2。本文为教学故障场景,错误文本和结果为示意,具体输出以现场为准。
一、遭遇情况:服务器能访问网页,却拉不下镜像
部署前执行 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。真正有价值的结论应能解释“为何之前失败、为何现在成功”,而不是只留下“换了个地址好了”。