Docker 磁盘空间不足?从排查到根治的完整方案
No space left on device 是 Docker 用户最常遇到的错误之一。但很多时候,df -h 显示磁盘还有空间,错误却照报不误。本文从根因分析到解决方案,覆盖手动清理、自动脚本、磁盘扩容三个层次,帮你彻底解决这个问题。
问题复现与根因分析
典型报错场景
当你执行 docker build、docker pull 或 docker run 时,突然遇到:
Error: No space left on device
但运行 df -h 却发现磁盘使用率并不高(例如只有 60%)。这时问题往往不在磁盘块空间,而在 inode 耗尽。
根因一:inode 耗尽
Docker 的构建缓存和 overlay2 存储层会产生大量小文件。每个文件占用一个 inode,当 inode 数量达到上限时,即使磁盘还有剩余空间,也无法创建新文件。
排查命令:
BASHdf -i
如果 IUsed 列接近 IFree 的总和(使用率 100%),说明 inode 已耗尽。
根因二:Docker 存储驱动配额限制
某些存储驱动(如 devicemapper)有独立的存储池配额。即使宿主机文件系统有空闲空间,Docker 的存储池也可能已满。
根因三:Docker 守护进程文件锁定
在 Docker 守护进程繁忙时(如正在执行 docker commit 或 docker save),清理操作可能因文件锁定而失败。这属于偶发问题,重启 Docker 服务通常可解决。
安全清理:分层策略
不要一上来就执行 docker system prune -a --volumes,这会删除所有未使用的容器、镜像、网络和卷,可能导致构建缓存丢失,增加后续构建时间,甚至误删重要数据。
第一层:查看空间使用情况
BASHdocker system df
该命令会显示镜像、容器、本地卷和构建缓存分别占用了多少空间。
第二层:定向清理(推荐)
| 清理目标 | 命令 | 说明 |
|---|---|---|
| 停止超过 24 小时的容器 | docker container prune --filter until=24h | 保留最近停止的容器,方便回滚 |
| 悬空镜像(无标签且无关联容器) | docker image prune --filter dangling=true | 安全,不会误删正在使用的镜像 |
| 构建缓存(保留指定大小) | docker builder prune --keep-storage 5GB | 在释放空间和保持构建速度之间取得平衡 |
| 未使用的卷 | docker volume prune | 谨慎使用,卷可能包含持久化数据 |
最佳实践组合:
BASH# 安全清理脚本(适合生产环境) docker container prune --filter until=24h -f docker image prune --filter dangling=true -f docker builder prune --keep-storage 5GB -f
第三层:激进清理(仅用于本地开发环境)
BASH# 删除所有未使用的容器、网络、镜像和卷 docker system prune -a --volumes -f
风险提示: 此命令会删除所有未被运行中容器使用的镜像和卷,可能导致后续构建需要重新下载所有基础镜像。
根治方案:磁盘扩容
如果清理后空间仍然不足,或者你希望从根本上解决问题,最推荐的做法是扩展底层块设备的大小。
云服务器磁盘扩容步骤
-
在云控制台扩展磁盘(例如从 20GB 扩展到 50GB),具体操作请以云服务商文档为准。
-
登录服务器,扩展分区:
BASH# 安装 growpart(如果未安装) sudo apt-get install cloud-guest-utils # Ubuntu/Debian sudo yum install cloud-utils-growpart # CentOS/RHEL # 扩展分区(假设磁盘为 /dev/sda,分区号为 1) sudo growpart /dev/sda 1 -
扩展文件系统:
BASHsudo resize2fs /dev/sda1 -
验证结果:
BASHdf -h
注意事项:
- 如果
growpart报错partition is busy,需要先卸载分区:sudo umount /dev/sda1(如果无法卸载,可能需要重启进入单用户模式)。 - 磁盘扩容操作前必须备份数据。
- 此方法无需修改 Docker 配置,且能从根本上解决空间不足问题。
常见报错与排查
报错 1:df -h 显示有空间,但 Docker 报错
排查步骤:
- 检查 inode:
df -i - 如果 inode 耗尽,执行
docker builder prune清理构建缓存中的大量小文件 - 检查 Docker 存储驱动配额:
docker info | grep -i "storage"
报错 2:docker system prune -a 后构建变慢
原因: 所有构建缓存被删除,后续构建需要重新下载和编译。
解决方案: 使用 docker builder prune --keep-storage 10GB 替代,保留最近 10GB 的缓存。
报错 3:docker rm $(docker ps -a -q) 报错
You cannot remove a running container
解决方案: 先停止所有容器,再删除:
BASHdocker stop $(docker ps -a -q) docker rm $(docker ps -a -q)
或者强制删除:
BASHdocker rm -f $(docker ps -a -q)
常见问题 FAQ
Q: 为什么 df -h 显示磁盘还有空间,但 Docker 仍然报 'No space left on device'?
A: 最常见的原因是 inode 耗尽。首先检查 df -i。如果 inode 使用率达到 100%,即使磁盘块有剩余空间也无法创建新文件。另一个原因是 Docker 的存储池(如 devicemapper)已满,但文件系统层面仍有空间。解决方案是清理 Docker 的构建缓存和未使用的镜像/容器。
Q: 如何在不影响生产服务的情况下安全地清理 Docker 空间?
A: 安全清理策略:
- 使用
docker system df先查看空间使用情况。 - 使用
docker container prune --filter until=24h只删除 24 小时前停止的容器。 - 使用
docker image prune --filter dangling=true只删除悬空镜像。 - 使用
docker builder prune --keep-storage 5GB保留 5GB 的构建缓存。 - 避免使用
docker system prune -a --volumes,因为它会删除所有未使用的卷,可能导致数据丢失。
Q: 在云服务器上,最推荐的永久性解决方案是什么?
A: 最推荐的永久性解决方案是扩展底层块设备的大小。具体步骤:1. 在云控制台扩展磁盘大小(如从 20GB 扩展到 50GB)。2. 登录服务器,使用 growpart 扩展分区(如 growpart /dev/sda 1)。3. 使用 resize2fs 扩展文件系统(如 resize2fs /dev/sda1)。此方法无需修改 Docker 配置,且能从根本上解决空间不足问题。
参考链接: