跳到主要内容
DevOps2026-09-086 分钟阅读

Docker no space left on device 磁盘爆满:清理命令从安全到激进的完整阶梯

现象:build 到一半 / pull 到一半,突然没空间了

# 构建时
failed to solve: ... write /var/lib/docker/tmp/...: no space left on device

# 拉镜像时
failed to register layer: Error processing tar file(no space left on device)

# 运行中容器写日志
Error response from daemon: ... no space left on device

一行结论:宿主机放 /var/lib/docker 的那块盘满了。Docker 用「写时复制」层叠镜像,每一次 build、pull、run 都在往同一个目录堆东西——而其中大部分是可再生成的垃圾。

这类报错也会伪装成别的症状:容器莫名 OOM 后立刻起不来、compose up 某一服务卡在 Creating、CI 机器「昨天还能跑今天全红」。先别急着加盘,按下面顺序看清楚是谁吃掉了空间。

先看清楚:空间被谁吃了

df -h /var/lib/docker        # 盘还剩多少
docker system df             # Docker 视角的四类占用
docker system df -v          # 每个镜像/容器/卷的细账

docker system df 的输出对应四个清理维度:

类别是什么可清理性
Images镜像(含 dangling 悬空层)多数可再生
Containers停止的容器占着的可写层看业务
Local Cachebuild cache可再生
Volumes持久化数据⚠️ 数据,默认不动

加 -v 能看到每个镜像/容器的具体体积,先定位再动手,不要上来就 prune -a。

两个人对「谁把盘打满了」争论不休时,再补两条取证命令:

# inode 与字节分开看——「有空间却报满」多半是 inode
df -i /var/lib/docker

# 真实目录体积(-x 不跨文件系统,避免挂载点把数字搅乱)
du -xh --max-depth=1 /var/lib/docker | sort -rh | head

清理阶梯:从安全到激进,逐级执行

# 第一级:只清已停止的容器(docker ps -a 里非 Up 的)
docker container prune

# 第二级:清 dangling 镜像(<none>:<none> 的悬空层,build 失败的残留)
docker image prune

# 第三级:清所有「没有被任何容器引用」的镜像——含旧版本 tag
docker image prune -a

# 第四级:清 build cache
docker builder prune

# 组合拳:上面几样一起来(不含 volume)
docker system prune

大多数「磁盘爆满」到二三级就解决了。每条命令都会列出将删除的对象和可回收空间,看一眼再按 y。

需要更大回收空间、且确认没有「只想保留旧 tag」需求时,再用:

docker system prune -a          # 含未被容器引用的全部镜像
docker builder prune -af        # 强制清 build cache(BuildKit 机器常要这一步)

纯 CI 构建机可以把 -af 写进定时任务;开发本机和生产节点不要默认 -a,否则昨天刚拉的基础镜像今天又要重下。

最危险的开关:--volumes

docker system prune --volumes   # ⚠️ 会删除「未被引用」的 volume

数据库容器重建后原 volume 不再被引用?--volumes 会把它连同数据一起删掉。除非你明确知道自己在干什么,否则不要加这个参数。生产环境删 volume 前先备份,或至少:

docker volume ls
docker volume inspect <name>    # 看 Mountpoint,确认不是还在用的库

也别直接 rm -rf /var/lib/docker/*——绕过 Docker 元数据,注册表和实际文件对不上,之后所有镜像操作都会出诡异错误。清空间永远用 docker 自己的命令。

三个「清了还会满」的根因

1. 容器日志无上限增长

json-file 日志驱动默认不限大小,一个疯狂打日志的容器能把盘写满:

du -sh /var/lib/docker/containers/*/*-json.log | sort -rh | head -5

彻底解决:/etc/docker/daemon.json 配日志轮转(对新容器生效,旧容器需重建):

{
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "3" }
}

改完 sudo systemctl restart docker。单容器也可以在 docker run --log-opt max-size=50m 指定。已经胀破的旧日志,可在确认业务可丢弃后截断:

truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log

2. 磁盘其实没满,inode 满了

df -h 显示还有空间却仍报 no space?查 inode:

df -i /var/lib/docker
# IUse% 100% ← 小文件(overlay 层、cache)把 inode 耗尽了

解法同样是 prune——层叠文件系统里一个 inode 泄漏源头能造出海量小文件。若 prune 后 inode 仍满,用 du -xh 找异常目录(常见于错误挂载的 hostPath、未清理的临时层)。

3. BuildKit cache 与多架构镜像层

开启 BuildKit 后,docker builder prune 与 docker image prune 清的不是同一堆东西。多架构 manifest(--platform linux/amd64,linux/arm64)会在本机留下多份层;开发机反复 buildx build 却从不 prune cache,几周后「Images 不大、Cache 占了几十 GB」很常见。CI 里每次 job 结束执行 docker builder prune -af 比盲目加盘更划算。

overlay2 与 rootfs:别只盯 Images 一行

docker system df 的 Images 不等于 /var/lib/docker 的全部。可写层(容器内写了大量临时文件)、未清理的 tmp、以及部分存储驱动的内部元数据,都会出现在 du 里但不在 Images RECLAIMABLE 里。排查顺序建议固定为:

  1. df -h + df -i —— 字节还是 inode
  2. docker system df -v —— Docker 自己认账的部分
  3. du -xh --max-depth=1 /var/lib/docker —— 对不上账时下钻到 overlay2 / containers / buildkit
  4. 再决定 prune 哪一级,而不是反过来先 prune 再猜

预防

  1. CI/CD 构建机加定时任务:每天 docker system prune -af(纯构建机没有 volume 顾虑);BuildKit 机器再加 docker builder prune -af;
  2. daemon.json 配好日志轮转(见上),这是最多人漏掉的一条;
  3. 监控 /var/lib/docker 所在分区,告警阈值 80%;同时监控 inode 使用率;
  4. 生产把 /var/lib/docker 挂独立分区,爆了不影响系统日志和数据库;
  5. 本机开发:定期清掉不用的旧 tag,而不是等「盘满了再一次性 prune -a」。

写 Dockerfile 时尽量减少无意义的层与巨型 build context(无关文件进 context 会膨胀 cache)。可用本站 Dockerfile 生成器 核对基础镜像与多阶段结构,再用 docker run 转 compose 固化可复现的运行参数。估算镜像体积时,字节单位换算 能避免把 GiB 和 GB 搞混。

排查清单

  1. df -h /var/lib/docker + docker system df — 空间和占比一目了然
  2. 按阶梯执行:container prune → image prune → builder prune
  3. --volumes 不到万不得已不加;rm -rf /var/lib/docker 永远不用
  4. 清完没多久又满?查容器日志大小 du -sh .../*-json.log
  5. df -h 有空间仍报错?df -i 查 inode
  6. daemon.json 日志轮转配置了吗?BuildKit cache 清了吗?
  7. du 与 system df 对不上时,下钻 overlay2 / buildkit 目录

排查注记

清理命令排成阶梯而不是直接给 system prune -a,是因为文中判断大多数爆满到二三级(清停容器、dangling 镜像)就解决,且每级都会列出将删除的对象——先定位再动手。「三个清了还会满」一节专门收录 df -h 有空间仍报错的 inode 场景,以及 du 和 system df 对不上账的 overlay2 可写层——system df 只算 Docker 自己认账的部分。--volumes 单独拉出一节标成最危险,依据是数据库容器重建后原 volume 不再被引用、会被连数据一起删掉。


本文出自 ToolVault 工具匣。相关工具:Dockerfile 生成器、docker run 转 compose、字节单位换算、Linux 命令速查。相关阅读:Docker daemon 连不上排查、端口被占用 EADDRINUSE、executable file not found。访问 首页 查看更多开发者工具。