Docker 提示 no space left on device 时,先核对数据根目录、容量与 inode,再区分镜像、缓存、容器和卷,安全清理、扩容并验证业务。
先别执行 docker system prune -a --volumes:Docker 在拉取镜像、构建或启动容器时提示 no space left on device,先通过 SSH 进入服务器,依次确认 Docker 实际数据目录、该目录所在文件系统的容量和 inode,再用 docker system df -v 区分镜像、容器、卷和构建缓存。只读检查通常不额外收费;扩容云盘会收费。误删卷、停止容器的可写层或回滚镜像,可能永久丢失数据库、上传文件和回退能力。
默认选择:先停止异常构建或持续写入,保留正在运行的容器和所有未确认用途的卷,只清理已经核对过的构建缓存、悬空镜像或废弃对象。如果正常业务数据已经占满磁盘,应扩容或迁移存储,而不是反复清缓存。
先确认报错发生在哪一步
ENOSPC 表示某个文件系统无法继续分配空间,但报错位置不一定是系统根分区。Docker 镜像、容器写入层、卷、BuildKit 缓存和日志可能位于不同目录;绑定挂载还可能落在另一块数据盘。先保存完整报错、发生时间、命令和容器名,不要只截取最后一句。
| 出现位置 | 优先检查 | 常见误判 |
|---|---|---|
docker pull 解压层失败 | Docker 根目录、containerd 镜像存储、inode | 以为删除应用日志一定有效 |
docker build 或 Compose 构建失败 | BuildKit 缓存、构建上下文、临时目录 | 直接删除全部线上镜像 |
| 容器启动或重启失败 | 容器写入层、日志、卷和宿主机挂载点 | 把卷当成可再生成缓存 |
| 应用在容器内写文件失败 | 目标卷或绑定目录、inode、应用配额 | 只看宿主机根分区还有多少空间 |
mkdir 失败但 df -h 未满 | df -i、只读挂载、配额 | 只增加磁盘 GB 数 |
第一轮只读检查怎么做
下面命令适用于 Linux 上的 Docker Engine。它们只读取状态;如果使用宝塔,可先在“终端”进入服务器执行。不要把包含私有镜像名、挂载路径或业务目录的完整输出发到公开论坛。
docker info --format 'Root={{.DockerRootDir}} Driver={{.Driver}} Logging={{.LoggingDriver}}'
docker system df -v
df -Th
df -ih
findmnt -T /var/lib/docker
findmnt -T /var/lib/containerd
DockerRootDir 显示 Docker 守护进程的数据根目录。传统存储驱动常把数据放在 /var/lib/docker;Docker 官方说明,新安装的 Docker Engine 29.0 及以后版本若使用 containerd 镜像存储,镜像内容和容器快照还可能位于 /var/lib/containerd。因此不能只检查一个固定目录,更不能手工删除里面的层文件。
df -Th 看容量,df -ih 看 inode。容量还有余量但 inode 为 100% 时,大量小文件同样会触发 no space left on device。docker system df -v 的 RECLAIMABLE 是 Docker 认为当前可回收的估算,不等于可以不经核对就删除。
Docker 统计和宿主机统计对不上怎么办
先把 Docker 数据根目录替换到下面命令中,只在该文件系统内逐层查看。命令可能扫描大量目录,应在业务低峰执行,并从一层深度开始。
sudo du -xhd1 /var/lib/docker
sudo du -xhd1 /var/lib/containerd
sudo lsof +L1
如果 df 很满而 du 合计明显偏小,常见原因是进程仍占用已经删除的文件。lsof +L1 会列出链接数为零但仍打开的文件。应确认进程和文件用途,再让对应服务正常重开日志或安排受控重启;不要直接写入或删除 /proc/进程号/fd 下的对象。
如果 Docker 统计不大,继续检查宿主机日志、数据库目录、备份和绑定挂载。现有的Linux 磁盘满排查解释了容量、inode、已删除文件和挂载点的通用分流;不要为了让问题“看起来属于 Docker”而忽略真实占用目录。
镜像、缓存、容器和卷分别代表什么
- 镜像:用于创建容器。删除未运行镜像可能影响快速回滚或离线重建,但通常不删除独立卷中的数据。
- 构建缓存:用于复用 Dockerfile 构建步骤。清理后一般可以重新生成,但下一次构建会更慢,也可能需要重新下载依赖。
- 停止的容器:它的可写层可能包含没有放进卷的文件。删除容器前必须确认这些文件是否需要保留。
- 卷:常用于数据库、上传文件和持久化配置。卷即使显示“未使用”,也可能是暂时停机服务唯一的数据副本。
- 绑定挂载:实际数据在宿主机指定目录,Docker 的汇总未必能说明该目录的完整用途。
Docker 官方的卷文档说明,卷由 Docker 管理并独立于容器生命周期;这正是不能把 volume prune 当作常规腾空间命令的原因。先从 Compose 文件、容器检查结果和备份记录确认每个数据目录的责任。
怎样做最小范围清理
清理前先保留部署文件、当前镜像摘要、容器检查结果和卷备份。下面命令先列出对象,不会删除:
docker ps -a --size
docker image ls --digests
docker volume ls
docker buildx du 2>/dev/null || true
确认构建缓存超过预期且旧缓存可以重新生成时,可以执行带时间过滤的交互式清理。示例中的 168 小时只是审核起点,应按发布和回滚周期调整;不要加 --force 跳过确认。
docker builder prune --filter 'until=168h'
docker image prune
docker image prune 默认只处理悬空镜像,仍可能删除某次回滚准备使用但没有标签的层。执行前阅读终端列出的对象和预计空间。构建服务器若反复占满磁盘,应按 Docker 官方的 BuildKit 垃圾回收策略设置保留空间和缓存年龄,而不是在故障时临时删除所有缓存。
不要把下面这些动作组合成“一键修复”:docker system prune -a --volumes、手工删除 /var/lib/docker、手工删除 /var/lib/containerd、对 Docker 目录递归改权限。Docker 官方说明,docker system prune 会处理多类未使用对象;加上 --volumes 后还会触及卷。对生产服务器,这些动作必须逐项审计。
如果是日志或容器写入层过大
日志占用应转到Docker 日志轮转与磁盘治理处理。Docker 官方提醒,json-file 日志文件应由 Docker 管理,不应由外部工具直接修改;为守护进程新增 max-size 与 max-file 后,只会自动应用到新建容器,现有容器需要经过可回退的重建流程。
容器可写层持续增长时,先用 docker ps --size 找到对象,再检查应用是否把上传、缓存、数据库或编译结果写到了镜像层。应把必须持久化的数据迁入明确的卷或绑定目录,并为临时数据设置应用级保留策略。不要只清空当前容器;如果写入路径没改,磁盘会再次占满。
什么时候应该扩容或迁移 Docker 数据目录
如果镜像、卷和缓存都有明确用途,清理后仍无法保留安全余量,扩容通常比继续删除更稳妥。云盘扩容会产生费用,且完成控制台扩容后通常还要扩展分区和文件系统,可参考对应云平台的云盘扩容教程。
迁移 data-root 不是在线修改一个路径:需要停止业务写入和 Docker,确认存储驱动与 containerd 模式,完整复制权限、扩展属性和硬链接,修改守护进程配置,再逐个验证容器、网络和卷。Docker 官方还明确要求不同守护进程使用独立目录。没有维护窗口和已验证备份时,不要用网络共享目录或直接移动活动中的数据根目录救急。
清理或扩容后怎样验收
- 再次运行
df -Th与df -ih,确认实际 Docker 数据文件系统恢复了安全余量。 - 运行
docker system df -v,记录镜像、缓存、容器和卷的变化,确认没有删除仍需使用的对象。 - 重新执行原来失败的拉取、构建或启动动作,只验证目标项目,不立即批量重建所有服务。
- 检查
docker ps、Compose 状态、健康检查、应用读写、数据库和上传目录。 - 安排一次受控重启验证挂载和启动顺序;若容器显示
unhealthy,按Docker Compose unhealthy 排查处理,不要继续清空间。 - 观察磁盘增长一段完整业务周期,配置容量与 inode 告警、日志轮转和构建缓存保留策略。
失败时怎样回退
如果删除缓存后构建失败,保留当前运行容器,从固定镜像摘要或制品仓库恢复,不要在生产主机临时改变大量依赖。误删镜像但容器仍运行时,先保持容器不重启并导出必要配置;不要假设所有镜像都能从外网重新拉取。
误删容器可写层或卷时,应立即停止新写入,避免覆盖可恢复空间,再从已验证的卷备份、数据库备份或云盘快照恢复。没有备份的卷不能靠创建同名卷恢复内容。处理完成后应记录删除对象、释放空间、恢复来源和业务验收结果。

