Docker 部署方便,但在小盘 VPS 上也很容易把系统盘吃满。最常见的现场是:网站还在跑,df -h 却显示 / 已经 100%;或者 apt install、数据库写入、日志落盘全部失败,最后发现 /var/lib/docker 下面的 overlay2、容器日志、旧镜像和构建缓存占了几十 GB。
这类问题不要一上来就执行 rm -rf /var/lib/docker/overlay2。overlay2 是 Docker 的存储层,里面可能包含正在运行容器的可写层,直接删除很容易让容器状态损坏。正确做法是先确认空间去了哪里,再按风险从低到高清理。
先看系统盘使用率:
df -h
如果 / 或 /var 已满,再看 Docker 目录大小:
sudo du -h --max-depth=1 /var/lib/docker | sort -h
常见大户通常有这些:
/var/lib/docker/overlay2
/var/lib/docker/containers
/var/lib/docker/volumes
/var/lib/docker/buildkit
然后用 Docker 自带视角看空间分布:
docker system df
docker system df -v
docker system df 会把 images、containers、local volumes、build cache 分开显示,比只看 du 更安全。du 告诉你哪个目录大,Docker 命令告诉你这些空间属于什么对象。
Docker 官方文档也明确说:Docker 对未使用对象采取保守策略,镜像、容器、网络、volume 默认不会自动清理,除非你显式执行 prune。
先看停止容器:
docker ps -a
如果有大量已经退出的临时容器,可以清理停止容器:
docker container prune
再看镜像:
docker images
只清理悬空镜像:
docker image prune
清理没有被任何容器使用的旧镜像:
docker image prune -a
如果你不确定某个镜像是否还要回滚使用,先不要加 -a。生产环境里,image prune -a 可能会删掉当前没被容器引用、但你本来准备保留用于回滚的镜像。
经常在 VPS 上 docker build 的机器,构建缓存可能比镜像本身还大。检查:
docker builder du
清理构建缓存:
docker builder prune
如果你确认旧缓存都不要了,再考虑:
docker builder prune -a
更稳妥的做法是加时间过滤,例如只清理 7 天前的缓存:
docker builder prune --filter "until=168h"
这样比无脑全删更适合线上 VPS,因为它减少了下次构建时重新拉取和重新编译的冲击。
很多人只盯着 overlay2,但真正吃满磁盘的是容器日志。Docker 默认的 json-file 日志驱动会把 stdout 和 stderr 写入文件。如果应用不断打印错误日志,又没有日志轮转,单个容器日志可能长到几 GB。
查看容器日志文件大小:
sudo du -h /var/lib/docker/containers/*/*-json.log | sort -h
临时止血可以先定位异常容器:
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}"
docker logs --tail=100 容器名
不要直接用编辑器打开巨大的 json log。更重要的是修复日志来源:应用是否在循环报错、健康检查是否太频繁、反向代理是否不断重试。
长期方案是给 Docker 配置日志轮转。编辑:
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json
写入或合并以下配置:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
然后重启 Docker:
sudo systemctl restart docker
注意:这个配置通常只影响新创建的容器。已有容器可能需要重新创建才能使用新的日志选项。如果你使用 Docker Compose,建议执行:
docker compose down
docker compose up -d
前提是你已经确认 compose 文件和 volume 配置正确。
/var/lib/docker/volumes 可能很大,但它经常存的是数据库、上传文件、配置、队列数据。这个目录不能和镜像缓存混为一谈。
先看 volume 占用:
docker system df -v
列出 volume:
docker volume ls
如果你要判断某个 volume 是否还被容器使用:
docker ps -a --filter volume=卷名
Docker 提供了:
docker volume prune
但这条命令会删除未被容器使用的 volume。问题在于:有些业务停机维护时,数据库容器暂时不存在,但 volume 仍然是你唯一的数据。生产环境不要在没备份、没确认用途时执行 volume prune。
更安全的顺序是:
- 先备份重要 volume;
- 确认 compose 项目已经废弃;
- 确认 volume 名称不是数据库、对象存储、上传目录;
- 再按名称删除指定 volume。
docker volume rm 卷名
docker system prune 是快捷清理命令,会清理停止容器、未使用网络、悬空镜像和构建缓存。默认不会清理 volume。
相对安全的版本:
docker system prune
带时间过滤:
docker system prune --filter "until=168h"
高风险版本:
docker system prune -a --volumes
这条命令不适合当作新手教程里的“万能清理”。-a 会扩大镜像清理范围,--volumes 会把未使用 volume 也纳入清理。对于跑 WordPress、Nextcloud、Gitea、数据库的 VPS,一旦 volume 判断错,清理的可能就是业务数据。
不建议。overlay2 是 Docker overlay filesystem 的存储目录,不是普通缓存目录。它变大通常只是结果,原因可能是:
- 容器可写层不断写入临时文件;
- 应用把缓存、上传文件写进容器内部而不是 volume;
- 旧镜像和旧容器没清理;
- 构建缓存长期累积;
- 日志没有轮转。
先找可写层异常的容器:
docker ps -s
如果某个容器的 SIZE 很大,说明它的可写层在膨胀。常见原因是应用把缓存、上传文件、导出文件写在容器内部。修复方式不是删除 overlay2,而是把持久化目录挂载到 volume 或宿主机目录,并调整应用配置。
建议按这个顺序处理:
df -h确认哪个分区满;sudo du -h --max-depth=1 /var/lib/docker | sort -h找 Docker 大目录;docker system df -v判断 images、containers、volumes、build cache 占比;- 先清停止容器和悬空镜像;
- 再清构建缓存;
- 检查 json-file 日志并配置轮转;
- 最后才处理 volume;
- 不直接删除
overlay2。
如果你的 VPS 只有 20GB 或 30GB 系统盘,Docker 部署前就应该做三件事:
- 给 Docker 日志设置
max-size和max-file; - 把数据库、上传目录、业务数据放进明确命名的 volume 或独立数据盘;
- 定期执行只清理旧缓存的命令,例如:
docker system prune --filter "until=168h"
docker builder prune --filter "until=168h"
同时保留监控:
df -h
docker system df
如果你已经遇到磁盘写满,先不要重启一堆服务。磁盘 100% 时,数据库、日志服务、包管理器都可能写入失败。先释放一小部分安全空间,再逐项修复根因。
VPS 上 Docker 占满磁盘,表面看是 overlay2 太大,实际常常是旧镜像、停止容器、构建缓存、json-file 日志和 volume 管理混在一起。真正安全的处理方式不是删除 Docker 目录,而是先用 docker system df -v 分类,再按风险从低到高清理。
记住这条底线:镜像和缓存可以重新拉,停止容器通常可以清,日志可以轮转,但 volume 里可能是你的业务数据。清理前先确认,清理后再加日志轮转和定期维护规则,才不会过几周又被同一个问题打断。
