使用Docker部署网站、数据库或自托管应用时,可能遇到镜像一直下载不动、反复重试,或者执行docker pull后直接报错。
这些问题不一定都由镜像源引起。域名解析、网络连接、仓库权限、拉取额度和磁盘空间,都可能影响镜像下载。
本文以使用systemd管理的常规Linux Docker Engine环境为例。Docker Desktop、Rootless Docker和远程Docker环境,需要在对应环境中检查配置。
1. 先根据报错判断排查方向
保留完整错误信息,尤其是报错中的域名、镜像名称和状态码。
| 常见报错 | 优先检查方向 |
|---|---|
no such host、Temporary failure in name resolution |
域名解析 |
i/o timeout、Client.Timeout exceeded |
网络连接、出口规则、代理 |
TLS handshake timeout |
TLS握手阶段的网络或代理问题 |
x509: certificate signed by unknown authority |
证书信任、代理证书 |
429、toomanyrequests |
仓库拉取额度或请求频率限制 |
unauthorized、denied |
登录状态、访问令牌和仓库权限 |
manifest unknown |
镜像名称或标签不存在 |
no matching manifest |
镜像不支持当前系统或CPU架构 |
no space left on device |
存储空间或inode不足 |
如果报错是Cannot connect to the Docker daemon,应先检查Docker服务或连接目标,而不是直接更换镜像源:
docker context ls
docker version
sudo systemctl status docker --no-pager -l
使用远程Docker时,镜像通常由远端Docker服务下载。后续网络与存储检查应在实际运行该服务的服务器上执行。
2. 检查镜像仓库域名能否解析
以Docker Hub为例:
getent ahosts registry-1.docker.io
getent ahosts auth.docker.io
两个域名分别涉及镜像仓库访问和认证流程。
如果无法返回地址,先检查服务器的DNS配置:
cat /etc/resolv.conf
使用systemd-resolved的系统,还可以执行:
resolvectl status
重点确认DNS服务器是否可达,以及当前网络接口是否使用了正确的解析配置。
如果/etc/resolv.conf由系统服务自动维护,应通过对应的网络管理工具修改,避免文件被重新生成后覆盖设置。
不要把Docker容器的DNS配置与Docker服务自身的域名解析混淆。 在daemon.json中添加"dns"主要用于容器DNS,并不等于修复宿主机拉取镜像时的解析故障。
3. 检查HTTPS连接,正确理解401响应

在允许服务器直接访问公网的环境中,可以执行:
curl --noproxy '*' -sS --connect-timeout 10 --max-time 20 \
-o /dev/null -D - https://registry-1.docker.io/v2/
这条命令测试直连路径,跳过curl的代理设置,并显示响应头。
如果返回:
HTTP/2 401
或者:
HTTP/1.1 401 Unauthorized
对于未携带认证信息的Docker Hub /v2/ 请求,这可以是正常的认证提示。
它说明此次请求已经到达仓库接口并收到响应,不能直接判断为账号密码错误,也不能据此认定整个镜像下载流程都正常。
还可以检查认证接口:
curl --noproxy '*' -sS --connect-timeout 10 --max-time 20 \
-o /dev/null -w 'HTTP %{http_code}\n' \
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/hello-world:pull'
该公开镜像的匿名令牌请求通常应返回HTTP 200。
根据结果继续处理:
-
解析失败: 返回第2节检查DNS。
-
连接超时: 检查服务器出站规则、路由和实际报错域名。
-
证书错误: 检查系统时间、CA证书及HTTPS代理配置。
-
接口正常但镜像层下载失败: 继续检查下载域名、代理和存储空间。
如果网络要求必须经过代理,直连测试失败可能符合预期,需要改为检查代理路径。主机上的curl测试也不能代替Docker服务实际使用的代理配置。
镜像下载还可能访问其他存储或分发域名,因此只放行registry-1.docker.io不一定足够。
4. 处理登录失败、权限不足和429限流

如果错误涉及Docker Hub认证,可以使用实际账号重新登录:
docker login -u YOUR_DOCKER_ID
将YOUR_DOCKER_ID替换为Docker账号,在Password提示处输入有效的个人访问令牌。
登录成功后,先尝试拉取一个小镜像:
docker pull hello-world:latest
注意登录与拉取应使用相同的用户环境。普通用户执行的docker login,与通过sudo docker运行命令时读取的凭据配置可能不同。
对于私有仓库,还需要确认:
-
登录的是正确的仓库地址。
-
账号具有目标镜像的读取权限。
-
访问令牌没有过期,且权限范围正确。
-
镜像名称、命名空间和标签填写无误。
如果出现429,需要区分两类情况:
| 报错类型 | 处理方法 |
|---|---|
| 明确提示达到镜像拉取额度 | 核对账号和额度,等待恢复或调整账号方案 |
| 提示请求过多 | 减少并发请求,检查循环重试和自动化任务 |
登录不能保证消除所有限流。自动化脚本应采用逐步延长间隔的重试方式,避免短时间内连续发送大量请求。
5. 正确配置镜像加速或Docker服务代理
只有确认问题与访问路径有关时,再调整镜像加速或代理配置。
常规Linux Docker Engine的配置文件通常是:
/etc/docker/daemon.json
如果已有该文件,修改前先备份:
sudo cp -a /etc/docker/daemon.json \
"/etc/docker/daemon.json.bak.$(date +%Y%m%d-%H%M%S)"
文件不存在时,无需执行备份命令,可以创建目录后编辑:
sudo mkdir -p /etc/docker
sudoedit /etc/docker/daemon.json
配置镜像加速
已取得可信、可用的Docker Hub镜像加速地址时,可以添加:
{
"registry-mirrors": [
"https://mirror.example.com"
]
}
mirror.example.com仅为格式示例,必须替换为实际服务地址。
已有其他配置时,应把registry-mirrors合并到原来的JSON对象中,保留原有日志、网络、存储和运行时设置。
需要注意:
-
Docker Engine的
registry-mirrors主要用于Docker Hub。 -
它不会自动加速
ghcr.io等其他镜像仓库。 -
加速服务可能有来源网络、账号、镜像范围或使用额度限制。
-
配置被加载,不代表加速地址一定可用。
配置Docker服务代理
如果服务器需要通过已有的HTTP代理访问仓库,应配置Docker服务本身。
Docker Engine 23.0及以上版本可以在daemon.json中添加:
{
"proxies": {
"http-proxy": "http://proxy.example.com:3128",
"https-proxy": "http://proxy.example.com:3128",
"no-proxy": "localhost,127.0.0.1,::1"
}
}
示例地址同样需要替换。内部仓库需要直连时,应按实际情况加入no-proxy。
仅在当前SSH终端执行export HTTPS_PROXY=...,通常不会改变已经由systemd启动的Docker服务环境。
不需要代理的服务器,不必添加这段配置。
6. 验证配置后再应用修改

修改完成后,先检查配置:
sudo dockerd --validate --config-file /etc/docker/daemon.json
正常情况下会输出:
configuration OK
这个检查不会启动第二个Docker服务,但也不会验证镜像加速地址是否可访问。
还应检查服务启动参数,避免同一个选项同时出现在启动参数和配置文件中:
sudo systemctl cat docker
仅修改镜像加速设置,且当前服务支持重新加载时,可以执行:
sudo systemctl reload docker
如果修改了需要重启才能生效的代理配置,应先确认业务能够接受中断,再在维护窗口执行:
sudo systemctl restart docker
Docker服务重启可能影响正在运行的容器,不应默认认为已有容器一定不会中断。
应用后检查:
sudo systemctl is-active docker
docker info --format '{{json .RegistryConfig.Mirrors}}'
如果服务没有恢复,查看日志:
sudo journalctl -u docker -n 80 --no-pager
根据错误修正配置,必要时恢复刚才的备份。不要反复重启代替检查。
7. 镜像下载到一半失败,检查哪些项目?
如果镜像清单已经获取成功,但某个镜像层反复重试,应检查完整错误中的下载地址,同时确认磁盘空间。
执行:
docker info --format '{{.DockerRootDir}}'
df -h
df -i
docker system df
需要确认镜像存储所在文件系统有足够的容量和inode,而不是只看服务器总剩余空间。
使用containerd镜像存储时,镜像内容可能位于独立的containerd目录,常见路径为/var/lib/containerd。只修改Docker的data-root,不一定会同步改变这部分数据的位置。
此外,镜像层下载后还需要解压,所需空间可能大于网络下载大小。
如果存储正常,再检查:
-
是否只有大镜像容易中断。
-
是否同时运行了大量拉取任务。
-
代理是否对长连接或大文件设置了限制。
-
下载域名是否受到出站规则限制。
-
故障时间是否与带宽拥塞或网络波动一致。
不要为了释放空间直接删除Docker或containerd的数据目录,也不要把清空全部镜像和数据卷作为通用修复步骤。
8. 如何确认镜像拉取已经恢复?
先测试小镜像:
docker pull hello-world:latest
docker image inspect hello-world:latest --format '{{.Id}}'
然后重新拉取原来失败的业务镜像,确认目标仓库、标签和镜像层都能够正常获取。
如果使用Docker Compose,可以在对应项目目录执行:
docker compose pull
该命令用于拉取服务镜像,本身不会重新创建正在运行的容器。
验证时需要区分:
-
小镜像成功,不代表大镜像下载一定稳定。
-
Docker Hub成功,不代表其他仓库也能访问。
-
本地镜像层已存在时,拉取可能复用缓存,不能据此证明完整下载链路都经过测试。
-
镜像下载成功,不代表应用配置和容器启动一定正常。
9. 常见问题
更换镜像加速地址后为什么仍然失败?
可能是地址不可用、服务限制了使用范围、配置没有加载,或者目标镜像来自Docker Hub以外的仓库。应先确认实际报错域名,再核对配置。
manifest unknown需要修改DNS吗?
通常应先核对镜像名称与标签。标签不存在时,更换DNS或加速地址不能解决问题。
出现no matching manifest怎么办?
确认服务器架构与镜像支持的平台是否一致。不要在不确认运行兼容性的情况下直接强制指定其他架构。
证书错误可以通过关闭校验解决吗?
应修复系统时间、证书链或可信CA配置。对于企业代理和私有仓库,使用管理员提供的可信证书,不要把关闭TLS校验作为常规方案。
Docker Desktop和Rootless Docker也修改同一个文件吗?
不一定。Rootless Docker通常使用用户目录中的配置;Docker Desktop的代理应在其设置界面配置。先确认实际运行环境,再修改对应位置。
10. 排查后仍无法解决怎么办?
Docker镜像拉取失败,建议按照“错误分类—域名解析—连接与认证—镜像加速或代理—存储空间”的顺序逐项检查。
如果需要联系莱卡云技术支持,建议提供:
-
服务器标识和故障发生时间。
-
完整镜像名称及标签。
-
完整错误信息。
-
Docker服务端版本。
-
是否使用代理、镜像加速或远程Docker。
-
脱敏后的相关配置与日志。
提供资料时,请隐藏账号密码、访问令牌和代理认证信息,便于在保护凭据的同时定位问题。