Docker 拉取镜像时遇到 lease does not exist 怎么排查

先确认拉取是否与 image prune 重叠,再停止并发清理并串行化任务,避免把内容存储竞态误判为仓库或磁盘损坏

说明 Docker 拉取镜像时出现 lease does not exist、failed commit on ref 或内容摘要丢失,如何确认 image prune 并发、先止损、串行化并验证回退。

如果 docker pull 偶发出现 lease does not exist、failed commit on ref、content digest ... not found 或解压层时提示文件不存在,先不要删除 /var/lib/docker,也不要立即认定镜像仓库损坏。先检查报错时段是否有另一项任务执行 docker image prune。Moby 上游已记录一种仍在处理的竞态:使用 containerd 镜像存储时,拉取和镜像清理重叠,清理可能移除正在保护拉取内容的 lease,随后拉取在提交或解压阶段失败。

默认止损方案是暂停自动清理,让所有拉取结束,再把拉取、部署和清理改成同一把锁下串行执行。这个改动不会删除业务数据,但可能暂时增加镜像占用;清理本身会删除未使用镜像,恢复前必须确认回滚需要的镜像是否仍有容器引用或已在仓库保存。

先判断是不是同一个并发现场

本文只处理“同一台 Docker 主机上,拉取镜像与镜像清理重叠”的故障。如果错误稳定发生在所有机器、手工重试仍立即失败,或者仓库明确返回 401、403、manifest unknown,应分别检查登录权限、镜像名称和标签,可参考Docker pull access denied 排查。如果磁盘或 inode 已满,应先按Docker no space left on device 排查处理容量。

并发清理竞态通常同时满足三点:同一个标签手工重拉经常成功;失败时间与定时清理、部署脚本收尾或测试框架清理接近;daemon 日志中能看到 lease、提交引用、内容摘要或解压层丢失。过滤条件并不能证明安全,上游复现显示,即使 prune 的标签过滤最终匹配不到镜像,也可能影响同时进行的拉取。

第一步:只读确认镜像存储和磁盘状态

先记录 Docker 版本、存储驱动和当前空间。以下命令只读取状态,不会清理镜像。需要在 Docker 主机执行;没有权限时使用具备 Docker 读取权限的运维账号。

docker version
docker info --format 'driver={{.Driver}} driver_status={{json .DriverStatus}} docker_root={{.DockerRootDir}}'
docker system df -v
df -h /var/lib/docker
df -i /var/lib/docker

若 DriverStatus 或完整 docker info 显示 containerd snapshotter,且环境是 Docker Engine 28/29 系列,应继续核对并发清理。若磁盘 100% 或 inode 用尽,容量问题本身就足以解释写入失败,不能仅凭相似报错归因于竞态。docker system df -v 只是估算 Docker 对象占用,不会自动删除任何内容。

第二步:把拉取失败和清理时间对齐

先查 daemon 日志,不要把整份日志公开粘贴;其中可能包含私有仓库地址、镜像名和节点信息。把时间范围替换为实际故障窗口。

sudo journalctl -u docker \
  --since '2026-10-15 08:50:00' \
  --until '2026-10-15 09:10:00' \
  --no-pager | grep -Ei 'lease does not exist|failed commit on ref|content digest|failed to extract|prune|deleting lease'

如果同一分钟先出现 prune 或删除 lease,随后出现 failed commit on ref、rename ... no such file or directory、lease does not exist,并且无并发清理时手工拉取成功,这条证据链支持“清理与拉取竞态”。只有拉取错误而没有任何清理时间证据,还不能下结论。

再检查常见调度入口。以下查询不修改计划:

systemctl list-timers --all | grep -Ei 'docker|prune|cleanup'
sudo grep -RniE 'docker (image |system )?prune' /etc/cron.d /etc/cron.daily /etc/systemd/system 2>/dev/null
ps -ef | grep -E '[d]ocker (image |system )?prune|[d]ocker pull'

如果使用 CI runner、部署平台或测试框架,还要检查平台任务日志。清理不一定来自管理员写的 cron;测试会话结束、部署脚本的 finally 阶段也可能调用镜像清理。

第三步:先停止并发清理,不要动 Docker 数据目录

找到定时器后,先停止并禁用对应的清理 timer;把示例单元名替换为真实名称。停止 timer 不会删除镜像,也不会停止业务容器。不要直接停用陌生系统单元,先用 systemctl cat 核对内容。

systemctl cat docker-image-prune.timer
sudo systemctl disable --now docker-image-prune.timer

若清理写在 CI 或部署脚本中,先移除收尾阶段的 docker image prune -f,或暂停对应任务。不要通过反复 prune“修复”内容存储,也不要手工删除 containerd 的 lease、blob、ingest 目录;这些动作可能把可恢复的拉取失败扩大成现有镜像不可用。

第四步:让拉取、部署和清理串行执行

长期止损可以用主机文件锁保护所有会拉取或清理镜像的任务。锁文件路径只负责互斥,不存放业务数据。下面示例先等待锁,再拉取和部署;清理任务必须使用同一把锁。

flock -w 1800 /run/lock/docker-image-maintenance.lock \
  sh -c 'docker compose pull && docker compose up -d'

清理任务改为:

flock -w 1800 /run/lock/docker-image-maintenance.lock \
  docker image prune -f --filter 'until=168h'

-w 1800 表示最多等待 30 分钟,不代表清理超时。生产环境应按最长一次拉取和部署时间设置。Docker 官方说明 docker image prune 默认删除悬空镜像,增加 -a 会扩大到所有未被容器引用的镜像;没有明确回收目标时不要使用 -a。使用时间或标签过滤前,先用 docker image ls 检查候选,并保留最近可回滚版本。

第五步:验证止损是否有效

先确认没有清理进程,再对原来失败的镜像按完整标签或 digest 拉取。不要用 latest 代替故障时的实际版本。

pgrep -af 'docker (image |system )?prune' || true
docker pull REGISTRY/PROJECT/IMAGE:TAG
docker image inspect REGISTRY/PROJECT/IMAGE:TAG \
  --format 'id={{.Id}} digests={{json .RepoDigests}}'

把 REGISTRY/PROJECT/IMAGE:TAG 替换为真实地址。拉取成功后,还要启动一次非关键容器或让编排平台完成健康检查,确认镜像不只是登记成功。连续多个原故障窗口不再出现 lease/commit/extract 错误,且串行锁日志能证明 prune 没有与 pull 重叠,才能把止损记为有效。

不同结果走哪条分支

检查结果判断下一步
停用并发 prune 后拉取稳定成功高度支持并发竞态保留串行锁,关注 Moby Issue 与正式版本说明
磁盘或 inode 已满容量问题优先先定位大目录和日志,再在维护窗口做受控清理
仓库返回 401/403认证或授权问题核对登录域名、凭据作用域和仓库权限
同一 digest 在所有主机都失败仓库对象或发布链更可疑核对 push 结果、清单摘要与仓库日志
没有任何 prune 时间证据不能归因于本文竞态继续检查网络、磁盘、daemon 重启与仓库状态

费用、停机和数据风险

读取日志、查看空间和加文件锁本身通常不产生云资源费用。暂停清理会增加系统盘占用,可能需要临时扩容;费用以所用云平台账单为准。单纯停用 prune 不会停止容器,串行等待会延后部署。删除镜像通常不删除 volume 中的业务数据,但可能失去本地快速回滚镜像;docker system prune --volumes 风险更高,本文不建议用它处理本故障。

如何回退

若串行化后确认故障与 prune 无关,可以恢复原 timer,但不要恢复高频并发清理。先查看单元和下次触发时间,再启用:

systemctl cat docker-image-prune.timer
sudo systemctl enable --now docker-image-prune.timer
systemctl list-timers docker-image-prune.timer

如果文件锁导致部署等待过长,先停止新的清理任务,等待当前持锁任务自然结束,再调整等待时间或拆分维护窗口,不要删除正在使用的锁文件来强行并发。

与其他 Docker 故障怎么区分

镜像 push 阶段超时或摘要问题应参考Docker push timeout 排查;磁盘持续增长但未满,可结合Docker 日志占用排查。本文的独立判断点是:拉取与 prune 在同一 daemon 上重叠,并出现 lease 或内容提交链错误。

官方与上游来源

截至核验日,上游 Issue 和修复 PR 仍为开放状态。不要把社区补丁直接编译进生产,也不要声称某个正式 Docker 版本已经包含修复;发布前应再次核对 Issue、PR 和 Docker Engine release notes。

云服务器教程NGINX gRPC 上游空闲连接被 RST 重置怎么排查2026-10-14云服务器教程BuildKit prune 后 metadata_v2.db 还在变大怎么处理2026-10-13云服务器教程Docker Swarm 加密网络存在 VXLAN 注入漏洞怎么办2026-10-11

加入开发者交流社区

与全球开发者、运维和工作室一起交流技术、分享经验、配置、账号与最新优惠信息

  • 云平台使用交流
  • 资源优惠信息
  • 最新教程与资讯
  • 开发者经验分享
联系 Telegram 客服
加入开发者交流社区