不少VPS运行Docker一段时间后,会发现 /var/lib/docker/overlay2 占用越来越大。这里保存镜像层和容器可写层,目录大并不等于里面全是垃圾,也不能根据随机目录名判断哪些文件已经没用。
overlay2由Docker管理,直接rm目录可能让镜像、容器元数据与实际文件失去对应关系。 安全处理要先从Docker对象层面统计,再删除已经确认不用的对象。

先确认Docker实际使用哪种存储
不同Docker版本和安装方式可能使用overlay2、containerd image store或其他驱动。先查看真实配置:
docker info --format 'driver={{.Driver}} root={{.DockerRootDir}}'
docker system info | grep -E 'Storage Driver|Docker Root Dir'
Docker官方文档说明,Engine 29.0及以后新安装默认使用containerd image store,传统overlay2已属于旧式存储路径;升级后的主机也可能保留原设置。因此不能看到 /var/lib/docker 就假定所有版本布局一致。
切换存储驱动会让原驱动下的镜像和容器暂时不可见,不能把更换驱动当成清理空间的方法。
用Docker自己的统计找出大头
先查看镜像、容器、本地卷和构建缓存的占用及可回收量:
docker system df
docker system df -v
docker ps -a --size
RECLAIMABLE 表示Docker判断当前没有被使用的容量,但删除后可能需要重新拉取镜像或重建缓存。docker ps --size 可以发现可写层异常增长的容器。
再从文件系统层面做只读核对:
sudo du -xhd1 /var/lib/docker 2>/dev/null | sort -h
df -hT /var/lib/docker
df -i /var/lib/docker
Docker统计与du差距明显时,还要检查日志、已删除但仍被进程占用的文件,以及独立的containerd目录,不能只盯overlay2。
overlay2里究竟保存了什么
OverlayFS把只读镜像层作为lowerdir,把容器修改写入upperdir,再通过merged目录呈现组合后的文件系统。同一镜像层可以被多个容器共享,因此du逐目录相加容易重复计算。
容器在自身文件系统内下载数据、生成缓存、写数据库或解压大文件,都会让可写层增长。绑定挂载和命名卷通常不计入该容器可写层,JSON日志则常位于 /var/lib/docker/containers,也不是overlay2本身。
可以查看单个容器的存储信息:
docker inspect --format '{{json .GraphDriver.Data}}' container_name
docker diff container_name | head -100
这些路径用于定位,Docker官方明确警告不要直接操作 0 内部文件。
先清理停止容器和悬空镜像
确认停止容器不再需要后,可以逐个删除,或统一清理停止状态:
docker container prune
docker image prune
默认的 docker image prune 主要删除悬空镜像。加入 -a 会删除没有任何现存容器关联的镜像,范围明显更大:
docker image prune -a --filter 'until=168h'
执行前应先看提示中的对象范围,并确认回滚版本、离线镜像和停止容器是否仍要保留。镜像未被运行中容器使用,不代表业务以后不会再次启动它。
构建缓存可以单独处理
频繁执行Dockerfile或Compose构建时,BuildKit缓存可能持续增加。先查看详细占用,再按时间清理:
docker builder du
docker builder prune --filter 'until=168h'
docker system prune 会同时处理停止容器、未使用网络、悬空镜像和构建缓存,影响面更广。官方文档还说明,构建缓存始终属于该命令的可清理范围。
生产服务器更适合分对象处理并留下记录。不要为了省一次确认而直接使用 0 ,否则排障需要的旧镜像和构建缓存可能一起消失。
卷不能顺手一起删
数据库、上传文件和应用状态常放在Docker volume中。docker system prune 默认不会删除卷,使用 --volumes 后会把符合条件的匿名卷纳入清理;单独的 docker volume prune 也会删除未被容器引用的本地卷。
在删除前检查:
docker volume ls
docker volume inspect volume_name
docker ps -a --filter volume=volume_name
停止容器仍可能保留对卷的引用,而被Compose项目移除的卷也可能包含唯一数据。卷的未引用状态只是Docker关系判断,不等于数据已经完成备份。
运行中容器写层过大怎样治理
若 docker ps --size 显示单个容器可写层不断增长,应找到应用实际写入的目录,把需要持久化的大数据迁移到命名卷或绑定挂载,并为缓存设置生命周期。数据库目录不能在运行中直接搬动,应先备份、停机并按应用官方迁移流程操作。
容器日志增长则应配置日志轮转,例如daemon或Compose中的 max-size 与 max-file,而不是删除正在写入的日志文件。镜像构建还应使用 .dockerignore,避免把备份、依赖缓存和临时文件复制进每一层。
需要演练清理范围时,可以在 萤光云 复制同版本Docker环境,也能用 LightNode 建立临时容器测试机。测试环境应使用脱敏数据,并保留与生产一致的存储驱动。
清理完成后怎样验收
清理前后分别保存:
docker system df -v
docker ps -a
docker volume ls
df -hT /var/lib/docker
随后启动关键容器,检查健康状态、端口、数据文件和应用日志,并执行一次真实读写。若磁盘占用很快恢复,说明只是删除存量,应用写层、日志或构建流程仍在持续制造增长。
验收标准是Docker对象关系正常、业务数据完整、关键容器可重新创建,并且新增占用的来源已经可监控。
FAQ
可以停止Docker后直接删除overlay2吗?
不可以。目录与Docker元数据存在内部对应关系,手工删除可能造成镜像层缺失、容器无法启动和空间统计异常。
docker system prune会删除正在运行的容器吗?
不会删除运行中容器,但会清理多类未使用对象和构建缓存。执行前仍要逐项阅读提示,并谨慎使用 -a 与 --volumes。
为什么du看到的overlay2总量比Docker统计更大?
OverlayFS层可能共享,du的统计方式还会受挂载点影响。应以Docker对象统计结合文件系统使用量判断,不要把随机目录大小直接等同于可回收空间。
温馨提示
磁盘接近满载时先停止高写入任务并备份关键卷,再做有范围的清理。凡是绕过Docker直接操作数据根目录的做法,都应视为高风险,而不是快捷清理。


