执行了 docker rmi,为什么磁盘空间还是 100% 占用?记录了一次服务器磁盘爆满的排查过程,深度解析 Docker 分层存储与构建缓存,并分享真正有效的深度清理命令。
在日常开发和运维中,我习惯于用一个简单的命令来清理 Docker 镜像:
docker rmi <IMAGE_ID>
删除不再使用的镜像,释放磁盘空间,逻辑看似完美。直到有一天,我的服务器直接弹出令人绝望的红字:
No space left on device
我删光了所有能删的镜像,为什么磁盘还是满的?
1. 现象:镜像删了,空间没回?
当我意识到磁盘报警时,第一反应是检查 Docker 的占用情况:
docker images # 查看镜像列表
df -h # 查看系统磁盘状况
诡异的现象出现了:
docker images列表里只剩下几个业务镜像,加起来不到 2GB。- 但
/var/lib/docker目录依然占用了 40GB+。
这时候我才意识到:看到的“镜像”,并不代表 Docker 占用的全部空间。
2. 分析原因:为什么 docker rmi 会失效?
理解这个问题,必须看清 Docker 的底层存储机制。Docker 镜像并非一个独立的文件,而是像乐高积木一样层层堆叠的(Layer-based Filesystem)。
2.1 镜像层(Layers)的“幽灵”
当你用 docker rmi 删除一个镜像时,Docker 只会尝试删除该镜像特有的层。如果某些层被其他镜像引用,或者是构建过程中的中间层,它们就会留在磁盘上,变成无法通过 rmi 直接删除的“幽灵空间”。
2.2 虚悬镜像(Dangling Images)
在多次执行 docker build 后,旧的镜像会失去标签(Tag),变成 <none>:<none>。这些镜像往往不会出现在你常规的清理视线里,但依然实打实地占据空间。
2.3 构建缓存(Build Cache)
这是最隐形的“空间杀手”。特别是开启了 BuildKit 后,Docker 会产生大量的构建缓存。这些缓存完全不会显示在 docker images 列表中,却是磁盘爆满的元凶之一。
3. 真正救命的命令:docker image prune
当我发现手动删除(rmi)无能为力后,我使用了 Docker 官方提供的“深度清理”命令:
docker image prune -a
这条命令到底做了什么?
- 所有未被容器使用的镜像(即使它有 Tag)。
- 所有虚悬镜像(Dangling Images)。
- 所有孤立的镜像层。
⚠️ 安全提示: 只要你的业务容器正在运行,它所依赖的镜像就是安全的,不会被
prune误删。但对于已经停止(Exited)的容器,其对应的镜像可能会被判定为“未使用”而被清理。
执行后,我的服务器磁盘占用瞬间从 100% 降到了 15%。
4. 进阶技巧:如何精准定位与排查?
在盲目清理之前,我建议先用以下命令定位 Docker 的真实磁盘占用:
docker system df
输出会清晰地展示四类数据的占用分布:
- Images: 镜像
- Containers: 容器(包括日志和可写层)
- Local Volumes: 本地卷
- Build Cache: 构建缓存
如果 image prune 仍不足以释放空间,可以使用终极命令:
# 清理一切:停止的容器、未使用的网络、未使用的镜像和卷
docker system prune -a --volumes
发表回复