直接答案:/var/lib/docker/overlay2 变大时,先用 docker system df -v 区分镜像、停止容器、可写层和构建缓存,再检查容器 json-file 日志与 volumes。不要直接 rm -rf overlay2:Docker 维护层、快照和元数据映射,手删可能让容器和镜像不可恢复。短期只清理已确认不用的对象;长期为日志设置 max-size/max-file、让业务数据进入 volume/对象存储,并为构建缓存和镜像保留制定策略。
本文适合 Docker 主目录所在分区接近满、overlay2目录占用大或拉取/启动失败。若数据主要在 named volume、bind mount 或数据库目录,清理镜像不会释放那部分;若 inode 耗尽,也要单独统计小文件数量。
本文按 2026 年 9 月可查的官方文档核对。示例命令以只读取证为主;凡涉及删除、覆盖、重启、权限、网络或数据库参数的动作,都应先确认操作对象、备份、维护窗口和带外恢复入口。不同发行版与软件版本的路径可能不同,必须先查询实际配置再改。
先用证据判断故障在哪一层
| 现象或检查点 | 它能说明什么 | 直接证据 | 不要误判为 |
|---|---|---|---|
| Images/Reclaimable很大 | 存在未被容器使用的镜像或层 | docker system df -v与容器引用 | 所有镜像都可删 |
| Build cache很大 | CI或频繁构建累积缓存 | builder df与构建时间线 | 容器运行数据 |
| 某容器Size持续增长 | 业务写入容器可写层 | docker ps --size与路径映射 | 镜像本身变大 |
| *-json.log巨大 | 默认日志未轮转或应用刷屏 | inspect日志路径与日志速率 | overlay层文件 |
| Volumes很大 | 持久数据、数据库或遗留卷 | volume inspect、挂载与责任人 | 可直接prune |
这张表的用法不是“看到一个关键词就改一个参数”,而是把客户端、DNS或边缘、Web 代理、应用、数据层依次分开。至少保留故障时间、完整 URL、状态码、关键响应头、同一时刻的服务日志和一份正常样本。只有时间能够对齐,才能判断两个现象是否属于同一次故障。
六步排查与修复顺序
1. 先确认空间还是 inode
记录 df -h、df -i、Docker Root Dir、存储驱动和首次告警时间。分区 100% 时先保护数据库和日志写入,停止非关键构建;不要在容量危急时运行会产生大量临时数据的扫描。
2. 用 Docker 视角分解占用
执行 docker system df -v、容器 size、builder df 和 volume 列表,将每项关联到应用、版本和负责人。Reclaimable 是候选,不等于业务无依赖;停止容器仍可能是待回滚版本。
3. 识别容器可写层异常
查看哪些容器 Size 随时间增长,检查应用是否把上传、缓存、数据库或临时文件写进镜像层。把持久数据迁到明确 volume/bind mount 前先做一致备份和恢复演练。
4. 检查日志而不手改活动文件
Docker 默认 json-file 日志可无限增长。读取 logging driver、LogPath 和应用错误频率;按官方配置新容器的 max-size/max-file。不要用外部工具直接操作 Docker 正在管理的日志文件。
5. 按对象精确清理
优先删除已确认不用的构建缓存、悬空镜像和过期停止容器。执行 prune 前查看其将影响的对象和 volumes 选项;volume 默认不随 system prune 删除是重要保护,不能为了多释放空间盲加 --volumes。
6. 建立持续容量与恢复验收
修复后重建或重启目标容器,确认数据、端口和健康。观察一次构建和日志高峰,配置磁盘/ inode 告警、日志轮转、镜像保留和备份恢复;Docker 版本升级后还要核对存储后端变化。
可复制的只读取证命令
以下命令中的域名、服务名、路径和时间范围要替换为自己的真实值。先执行查询命令并保存原始输出;不要把“命令能运行”误当成“业务已恢复”。
text
docker info --format '{{.DockerRootDir}} {{.Driver}}'
docker system df -v
docker ps -a --size --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Size}}'
docker inspect --format '{{.Name}} {{.HostConfig.LogConfig.Type}} {{.LogPath}}' $(docker ps -q)
docker builder prune --filter 'until=168h'
docker info --format '{{.DockerRootDir}} {{.Driver}}':确认Docker根目录与存储驱动docker system df -v:按镜像、容器、volume和缓存查看Docker认识的占用docker ps -a --size --format 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Size}}':查找可写层异常增长的容器docker inspect --format '{{.Name}} {{.HostConfig.LogConfig.Type}} {{.LogPath}}' $(docker ps -q):列出运行容器日志驱动与路径;容器很多时分批执行docker builder prune --filter 'until=168h':清理一周前未使用构建缓存的交互示例;执行前必须核对构建与回滚需求
如命令输出包含公网 IP、用户名、Cookie、令牌、数据库连接串或客户数据,分享工单前先脱敏。对比时保留时间戳、时区和命令本身,否则后来无法复现同一观察条件。
五个最容易扩大故障的误区
- 直接删除 overlay2 目录:会破坏Docker元数据与层引用,可能导致容器无法启动。
- docker system prune -a --volumes 一把梭:可能删除回滚镜像、停止容器和匿名卷中的唯一数据。
- 只清镜像不查日志:json-file或应用可写层会继续把磁盘占满。
- 把数据库放容器可写层:重建容器可能丢数据,也难以独立备份。
- 只看GB不看inode:大量小文件会在容量仍有剩余时耗尽inode。
变更、回滚与数据边界
清理动作通常难以原地回滚,因此必须先列出精确对象、确认镜像可重新拉取、保存 Compose/配置,并对 volumes 做应用一致备份。不要删除仍用于回滚的 tag/digest。若日志策略变更导致排障信息不足,恢复旧配置只对新建容器生效与否要按 Docker 文档验证;已删除的日志和缓存不能恢复。
如果只能先恢复服务、还不能确认根因,应把措施标记为“临时缓解”,例如限流、摘除单节点、切回上一配置或临时绕过一层代理。恢复后仍要在受控环境复现原因,并验证同类故障不会在下一次重启、发布或高峰重新出现。
统一验收清单
- [ ] Docker Root Dir与文件系统已确认
- [ ] 空间和inode均有基线
- [ ] 镜像、构建缓存、可写层、日志和volume占用已分开
- [ ] 删除对象均有责任人确认
- [ ] 未直接操作overlay2内部文件
- [ ] 日志轮转对新容器已验证
- [ ] 持久数据有独立恢复演练
- [ ] 跨过一次构建与流量高峰磁盘仍稳定
验收必须同时覆盖机器内部和真实外部路径。首页返回 200 不能证明上传、长连接、登录、数据库写入或移动端都正常;同样,控制台显示“运行中”也不能证明应用已能处理请求。至少选一个正常请求、一个边界请求和一个失败请求,记录预期与实际结果。
相关内容与隔离测试入口
建议先阅读服务器磁盘满清理、Docker Compose生产部署、快照和备份区别,把本问题放回完整请求链路。若生产环境不适合直接试验,可查看美国弹性云服务器的当前规格与库存,搭建与生产隔离的复现环境;测试机不能替代生产备份,价格、库存和可选配置以实时产品页为准。
常见问题
overlay2目录可以手动删旧文件夹吗?
不可以按目录时间猜测。Docker层可能被镜像或容器引用,应使用Docker命令管理。
docker system prune 会删volume吗?
默认不会删除 volumes;加特定选项才扩大范围。执行前阅读当前版本提示并确认数据边界。
为什么删除镜像后空间没有马上下降?
层可能仍被其他镜像/容器引用,或实际大户是日志、volume、已删除但仍打开的文件。
json-file 日志能直接 truncate 吗?
官方警告外部工具操作这些文件可能干扰Docker。应配置日志轮转并在维护方案中处理现有日志。
迁移 Docker Root Dir 能解决吗?
能扩展容量但不解决无界日志和错误写入。迁移涉及停机、权限、存储驱动和回滚,应单独规划。