Docker镜像拉取失败:按报错定位问题

同样是拉取失败,unauthorized、manifest unknown 和连接超时需要处理的地方并不一样。先保存最后一段完整报错、镜像全名和发生时间,再决定下一步;不要看到失败就删除本地镜像或重启所有容器。

本文以 Linux Docker Engine 为例。命令在有权限管理 Docker 的终端执行;registry.example.com/team/app:release 是演示名称,必须换成已确认可信的实际仓库、项目、镜像和标签。

第一步:确认连到的是哪台 Docker

docker context show
docker version
docker info --format 'OS={{.OSType}} ARCH={{.Architecture}}'

先看当前 context,并确认 docker version 能显示服务端信息。如果报“无法连接 Docker daemon”或访问 socket 被拒绝,尚未到镜像仓库阶段,应先查服务状态、当前连接目标和管理权限。不要把 socket 改成任何人都可写。

CLI 可以连接远端 Docker。真正下载镜像的是所连接的服务端;本机浏览器能打开网页,不能证明远端机器到镜像仓库的访问正常。第三条只查看服务端系统和架构,避免输出整份可能含代理信息的配置。

按错误内容选择排查方向

常见报错 优先检查
unauthorized、authentication required、denied 当前账户是否已登录正确仓库,令牌是否有效,是否拥有该项目的拉取权限;也核对仓库名称。
manifest unknown、not found 仓库路径和标签是否存在。不要只确认镜像名而漏看版本标签,也不要直接换成 latest。
no matching manifest 该标签是否提供服务端需要的系统与架构版本;强行指定另一架构不代表应用能运行。
no such host、timeout、connection refused 在实际 Docker 服务端检查 DNS、出口、代理以及仓库端口,不先修改业务容器里的 DNS。
x509、certificate has expired 系统时间、证书域名、有效期与信任链;私有仓库需按实际安装方式配置可信 CA。
429、toomanyrequests 阅读配额或重试提示,停止密集循环,核对授权账户及可用额度。
no space left on device Docker 数据所在文件系统的容量与 inode;先确认占用来源,不能直接清空数据目录。

网络、登录和证书要改在正确位置

使用代理时,终端设置的代理不一定传给已运行的 Docker 服务。应检查 daemon 实际采用的代理和绕过列表;不要把容器用的代理配置当成镜像拉取配置。修改前保存原配置,确认变更影响;需要重启 Docker 时安排维护窗口,不能默认其他业务完全不受影响。

如需重新登录,在管理该 Docker 的同一客户端执行 docker login 实际仓库地址,按提示使用获授权的账户。不要把密码写进命令参数,或把凭据文件贴到工单;同一台机器上换了操作系统用户,客户端凭据也可能不同。

证书问题按实际原因修复,不将仓库改成不安全连接,也不临时换到来路不明的镜像站。默认端口与自定义端口、系统级安装与 rootless 安装的证书位置可能不同,应和当前安装方式对应。

Docker 作为系统级 systemd 服务运行时,可在服务端查看近期日志;用户服务及其他安装方式应改查对应日志入口:

journalctl -u docker.service -b -n 80 --no-pager

日志只在本机检查,转交前删去令牌、代理凭据、私有地址和业务路径。末尾日志没有覆盖故障时间时,再按时间范围查询。

同一目标拉取成功后,核对结果

修复一项原因后,对原来那个镜像重试一次。下面的第二条仅在拉取成功后执行,避免把旧的本地镜像误当作本次下载结果:

docker pull registry.example.com/team/app:release &&
docker image inspect registry.example.com/team/app:release --format '{{json .RepoDigests}}'

确认命令成功退出,并把输出的仓库摘要与可信发布记录核对。标签可以被重新指向其他内容;有固定摘要要求时使用已确认的摘要。拉取成功只说明镜像取得成功,后续启动与业务验证另做,不能顺手重建全部服务。

延伸阅读:Ubuntu安装Docker Engine与Compose;Docker应用更新失败,怎样退回原来的版本;Linux磁盘满了:容量与inode检查。