新闻详情

新闻详情

首页 / 资讯中心 / 详情

Overlay2 目录占满磁盘?从定位到清理的 Docker 存储空间治理指南

发布时间:2026/9/16 22:05:38来源:尧图网络
Overlay2 目录占满磁盘?从定位到清理的 Docker 存储空间治理指南
和很多跑过容器的朋友一样我第一次被 overlay2 目录搞到怀疑人生是在一台连续跑了半年的开发机上。当时df -h一看/var/lib/docker/overlay2 已经占了快 40GB整个系统盘只剩不到 2GB连 ssh 登录都要卡几秒。那阵子网上搜来搜去全是“一键清理”脚本试了几个有的直接把镜像全删了有的执行完空间还是没回来。后来花了一个周末把 Overlay2 的存储结构、日志机制、构建缓存这些挨个理了一遍才终于明白磁盘占用这件事靠“一把刀切”是解决不了的得先知道空间去哪了再决定怎么回收。这篇文章就把我多次踩坑后沉淀下来的这套排查和清理方法完整拆出来。不管你是自己玩 Docker Desktop还是管理一群生产服务器只要遇到 overlay2 占空间、磁盘告警、日志无限增长这类问题文里的思路和命令基本都能直接拿来用。1. Overlay2 是怎么把磁盘空间吃掉的1.1 先看懂 overlay2 的目录结构很多教程会直接告诉你“overlay2 就是镜像层的叠加”但真到排障的时候这个说法帮不了太大忙。实际落到磁盘上/var/lib/docker/overlay2 下是这样一套结构l/目录存放一些短链接用来解决 overlayfs 挂载路径过长的问题一堆以哈希命名的目录每个目录代表一个镜像层或容器可写层在这些目录内部常见的是diff/、merged/、work/等子目录。diff/才是真正保存文件内容的地方merged/是容器运行时合并后的视图。理解这几点之后你再去看du -sh /var/lib/docker/overlay2/*的输出就不会对着几十个哈希目录发懵。那些几百MB甚至几个GB的目录多半是某个镜像层也可能是运行中容器仍在写入的可写层。重点要区分的是镜像层是只读的清理它会影响所有引用该层的容器容器可写层则只属于某一个容器这个容器删掉对应的那部分空间通常就能回收。1.2 空间的主要去向容器、日志、构建缓存根据我排查过的很多机器overlay2 目录膨胀来源大致可以分成四类容器可写层容器运行时产生的临时文件、缓存、PID文件等只要容器不删upper 层就一直占着。尤其是一些长时间不重启的应用可写层可能悄悄涨到几个GB。容器日志很多人忽略的一点。Docker 默认的 json-file 日志驱动会让容器的标准输出日志全部落到宿主机/var/lib/docker/containers/容器ID/容器ID-json.log。我的经验是日志膨胀的速度远比镜像本身快而且它虽然不直接写在 overlay2 里却常常和 overlay2 一起把整块盘塞满。悬空镜像与中间层镜像反复docker build尤其是每次没有打新 tag 就直接构建命令结束之后会产生大量none悬空镜像多阶段构建没清理中间产物时也一样。构建缓存每次构建时Docker 会把不满足缓存失效条件的中间层保留下来。虽然新版 Docker 有了 BuildKit 缓存管理但老机器上如果不定期清理缓存也能堆到几个GB。1.3 先用 df 和 du 把“是谁满的”搞清楚动手清理之前建议先花两分钟把现状摸清楚。我在处理自己的服务器时一般按这个顺序来df -h df -h /var/lib/docker du -sh /var/lib/docker/* | sort -rh | head -20第一行看整块磁盘的使用率第二行确认 Docker 数据目录所在的挂载点第三行看看到底是 overlay2、containers 还是 volumes 占大头。如果df -h显示可用空间不多但/var/lib/docker也没占多少那问题往往在别的地方比如系统日志、临时目录甚至是虚拟机的虚拟磁盘文件本身。盲目去清理 Docker 是没用的这也是为什么我一直强调“先定位再清理”而不是看到磁盘告警就无脑跑 prune。2. 精准定位哪个容器在偷偷吞磁盘2.1 先跑 docker system df 看统计Docker 官方其实已经很贴心地提供了统计命令很多时候我们只依赖 du 去手动扫目录反而忽略了它docker system df输出里会分类显示 Images、Containers、Local Volumes、Build Cache 的总大小和 RECLAIMABLE可回收空间。我一般还会加-v参数看详细列表这样能直接看到每个镜像、每个容器的可回收空间。第一次见到这个输出的人容易误以为只要是 RECLAIMABLE 就都可以立刻回收。这里要提醒一句RECLAIMABLE 只是表示“当前没有被正在使用的东西引用”不代表这些数据对你一定没用。比如某个镜像虽然当前没有容器在使用但你可能明天就要拿来重新部署贸然删掉之后需要重新拉取。所以docker system df -v的价值在于“知道哪些东西是回收成本低的”真正的取舍还要结合业务情况判断。比如线上在跑的服务连镜像带容器最好整体保留不应该因为当前 pod 临时没运行就随手 prune。2.2 按大小排查 overlay2 里的大块头如果docker system df已经确认 Images 或 Containers 很肥我通常会接着执行du -sh /var/lib/docker/overlay2/* | sort -rh | head这一步能看到每个层的真实大小。这里有个经验那些正在写入的可写层体积往往和容器当前的挂载状态相关。如果你发现某个哈希目录异常大而机器上容器不多可以用下面这个方法反查它属于哪个容器docker ps -q | xargs -I {} sh -c echo {}; docker inspect -f {{.GraphDriver.Data.UpperDir}} {}拿到 UpperDir 路径后再和 du 的结果比对就能快速定位“是这个容器占了几个GB”。如果目录对应的容器已经被删掉了空间却还没释放多数是进程句柄的问题后面常见问题部分我再展开。2.3 日志才是很多场景的“隐形刺客”我在处理孤立的问题容器时经常会碰到镜像本身不大但磁盘一路飙红的情况。这时候十有八九是日志。可以先用这个命令看每个容器的日志文件大小find /var/lib/docker/containers -name *-json.log -exec ls -lh {} \; | sort -k5 -rh | head结合docker ps -a的输出往往能看到某个业务容器一条日志每天涨几十MB有些网关和数据库容器甚至一天能涨1GB以上。定位到这个“罪魁祸首”之后最直接的办法是截断日志文件而不是直接重启容器因为容器重启之后旧文件句柄被释放才可能真正回收空间。后面第3章会给出具体命令。要注意的是数据库类容器如果日志文件本身也在被大量写还需要考虑是不是慢SQL、长事务等业务问题不光是容器层能解决的。3. 高效清理一套可以直接落地的命令组合3.1 最稳妥的一键清理docker system prune如果你只是想安全地回收一部分空间用 Docker 官方提供的 prune 是最不容易出错的选择docker system prune它会提示你删除已停止的容器、未被使用的网络、悬空镜像和构建缓存。这里要注意docker system prune默认不会删除所有未使用的镜像也不会删除卷。要删所有未被容器引用的镜像需要加-a要连卷一起清理需要加--volumes。我的建议是开发机和 CI 机器可以跑docker system prune -af因为镜像随时可以从镜像仓库拉回来开发环境重建成本低。但生产环境我基本只用docker system prune -f --filter until24h也就是只清理24小时前产生的悬空数据给“误操作回滚”留点余地。3.2 带过滤器的精准清理prune 命令支持--filter参数这个在很多教程里容易被忽略。我常用的几个docker image prune -a -f --filter until24h docker container prune -f --filter until24h docker builder prune -f --filter until24h解释一下until24h表示只清理创建时间超过24小时的对象。这样做的原因是某些 CI 或测试流程在最近几小时创建的镜像可能还在被测试脚本引用直接全删容易影响正在进行的任务。用docker image prune -a配合时间过滤比无脑docker system prune -a要稳得多。还有一个很实用的做法是单独清构建缓存。像我们平时从源码反复 build 镜像构建缓存堆积非常快而它又不影响运行中的容器所以可以放心清理docker builder prune -f如果构建缓存特别大、路径很多加-a可以连同 BuildKit 的更多缓存一起清理。在 CI 机器上这个操作尤其有效因为每次代码提交都可能触发新的构建旧缓存基本用不上。3.3 日志清理的两种姿势先说应急方案。当你已经确认某个容器日志特别大想要立刻释放空间可以这样操作# 先用 truncate 清空日志文件注意容器不用重启 truncate -s 0 /var/lib/docker/containers/容器ID/容器ID-json.log为什么用 truncate 而不是rm -rf因为容器进程还持有这个日志文件的文件句柄直接删掉文件后磁盘空间不会立即释放直到容器重启或 Docker 重启才行。而 truncate 是把文件内容清空原句柄依然有效空间立刻就能回收容器也不会受影响。如果你想保留最近一段时间日志也可以先用cp备份后再 truncate。再讲治本方案。等应急结束后我会建议给 Docker 配置日志上限。在/etc/docker/daemon.json里加上{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }然后执行systemctl restart dockerLinux 系统或者通过 Docker Desktop 的 Settings 重启。这样每个容器日志文件最多10MB保留3个文件。对于绝大多数业务容器这个量级足够排查问题了同时也避免了日志无限增长。有一点需要特别强调这个配置只对之后新建的容器生效老容器如果没有删除重建依然会按老配置继续涨日志。所以改完配置之后最好把那些日志大户容器逐个重建一遍才能真正把新配置生效到所有容器。3.4 卷清理的特殊说明很多人对docker volume prune掉以轻心其实卷才是更容易造成数据丢失的地方。像 MySQL、GitLab、Redis 这类有状态服务数据都存在挂载卷里。一旦执行了docker system prune --volumes没有被容器引用的卷会被全部删除如果里面有重要数据又没有在其它地方备份那基本就找不回来了。所以我自己的原则是--volumes参数只在自己非常确定当前没有重要数据时才会加。平时要清理卷我会先看哪些卷是没用的docker volume ls -f danglingtrue通过这种方式列出的悬空卷通常可以安全删除对于业务数据库、缓存数据卷绝对不要一刀切。GitLab 这种应用动辄几十GB里面全是代码仓库数据手动清理时更要加倍小心。如果确实需要删除某个数据卷建议先确认容器已经停止并删除再执行docker volume rm 卷名。4. 根治优化让 overlay2 不再轻易膨胀4.1 日志限量与统一纳管上一章已经提过 daemon.json 配置这里我把完整的推荐配置再展开一点。除了日志上限我还会在配置里关闭 Docker 的调试开关保持默认的 json-file 驱动即可。如果机器上同时跑着很多容器日志文件轮转可能造成一定 IO 压力但现代服务器通常扛得住关键还是别让日志无限制写。对于 Spring Boot 这类应用还有个更细的做法应用自身日志可以挂到卷里或者写到 stdout 交给 Docker 轮转。不要在同一时间开“双写”否则即使用 Docker 限制了 stdout 日志应用日志还是会把磁盘吃满。我见过不少项目Docker 日志轮转配得好好的但应用自己的 access log 却写在容器可写层最终一样把 overlay2 涨爆。4.2 镜像瘦身从构建源头减少占层数overlay2 的特点是一层叠一层镜像层数越多最终占用的空间往往越高虽然不同层可能有文件覆盖但层数多会增加元数据和清理开销。多阶段构建是减少层数的利器比如 Java 应用可以先在 maven 镜像里跑编译再用 jre 基础镜像拷贝产物最终镜像会小一个数量级。另外构建时把多个 RUN 合并成一条并清理临时缓存RUN apt-get update apt-get install -y curl \ curl -fsSL https://example.com/package.tar.gz -o /tmp/package.tar.gz \ tar -xzf /tmp/package.tar.gz -C /usr/local \ rm -f /tmp/package.tar.gz \ apt-get remove -y curl \ apt-get clean这样镜像层数少、体积小push/pull 也快。别小看这个习惯长期下来几百个镜像的机器上差距能有几十GB。事实上当你通过 Docker Hub 或私有仓库拉取镜像时每一层都要单独下载层数越多网络传输也越慢这也是一个隐形开销。4.3 业务数据统一挂卷容器可写层之所以涨得快往往因为应用在容器里写文件日志、缓存、临时文件、数据库数据。要想根治最直接的是让这些文件不要进入 overlay2 可写层而是挂载到宿主机目录或卷中。比如 MySQL 容器的数据目录用-v /data/mysql:/var/lib/mysql挂载能避免数据写入可写层Redis 的持久化文件也同理。这样即使容器重建数据还在overlay2 目录也不会因为是持久化数据而膨胀。这个习惯一定要养成容器是“一次性”的数据是“持久化”的。凡是需要长期保留的文件都要明确挂到卷或宿主目录上而不是丢在容器可写层里。我见过不少人为了省事把所有文件都写在容器里结果某天磁盘爆了想清理却不敢动任何容器因为里面全是没备份的数据最后只能把整台机器停机处理相当被动。4.4 自动化定时清理与监控解决了当前的问题还要防止下次再爆。我一般会在每台服务器上放一个清理脚本内容大致是这样#!/bin/bash docker system prune -af --filter until48h docker builder prune -f --filter until48h然后用 cron 每天凌晨执行一次。这里要再强调一句生产环境如果对容器依赖很大建议先跑docker system df看清可回收量并且谨慎考虑是否需要-a。开发机和测试环境可以激进生产环境保守一点不是坏事。监控也比清理更重要。磁盘使用率到 80% 就该收到告警等到 95% 才处理很多服务可能已经被写挂了。用现成的 node exporter Prometheus或者写个简单脚本定时 curl 到企业微信/钉钉/邮件都能起到“提前发现”的效果。实际运维时我还经常看df -h和df -i同时监控因为 inode 耗尽同样会让应用出现诡异报错这个坑我稍后单独讲。5. 常见问题与避坑实录5.1 清理了还是满多半是句柄没释放有一种很典型的情况是明明docker system prune -af跑得很顺利可df -h一看空间一点没多出来。这时候先别怀疑命令没用先检查是不是有容器进程还占着已删除文件的句柄。最简单粗暴的验证办法lsof L1 | grep -i deleted | grep docker如果能看到大量 docker 相关的 deleted 文件被进程持有重启对应容器或重启 Docker 服务后空间就会真正释放。这个过程不需要重新拉镜像影响相对小但重启服务前还是最好确认没有正在跑的迁移或离线任务。另外如果你删了容器但卷还在空间也不会回到系统里。所以“清理后磁盘仍满”时要回头看看docker volume ls -f danglingtrue是否存在大量悬空卷。我遇到过几次这样的情况都是前几周测试时创建的临时数据卷容器删了之后卷一直留着账面看起来不大加起来却很可观。5.2 别手滑删 overlay2 下的目录我在早期维护服务器时曾经干过一件蠢事为了省空间直接对/var/lib/docker/overlay2/下面某个看起来很大的哈希目录执行了rm -rf。结果容器运行到一半报出一堆文件无法访问的错误。后来才明白overlay2 的层是依赖底层镜像层的哪怕你删的是很小一层 cache也可能导致整个镜像损坏。正确的姿势永远是通过docker system prune或docker image prune、docker container prune这类官方命令去清理。实在要通过目录层操作也只能删除已经被删除容器对应的孤立目录而且要确保相关容器已经停掉、没有还在拉取或构建的任务。更安全的做法是写脚本先列出可疑目录依次确认没有对应容器后再归档或删除。5.3 有空间却报 No space left on device这也是很隐蔽的坑。有时候df -h看着还有几十GB但容器启动或创建时报no space left on device。这时候去看一下 inodedf -i /var/lib/docker如果 inode 使用率已经是100%那说明文件数量太多小文件把 inode 占满了。镜像层和构建缓存里经常会有大量小文件尤其是一些极端场景比如前端 node_modules、Java 的 target 目录、Python 的 cache都会产生成千上万的小文件。处理办法还是通过 prune 清理镜像和缓存如果还不行可能需要检查是不是容器内应用疯狂创建小文件。这个问题也解释了一个现象为什么有时候明明只删了几个镜像磁盘可用空间却突然多出好几个GB。因为删除的镜像包含大量小文件释放的 inode 数量远大于文件总字节数。所以当你排查“No space left on device”时记得不只盯df -h还要盯df -i双管齐下才能确认症结。5.4 不同场景的清理策略速查场景推荐的清理方式频率开发机docker system prune -af必要时清理全部镜像每周一次或磁盘告警时CI 构建机docker builder prune -f镜像只保留最近24h每天一次生产服务器docker system prune -f --filter until48h谨慎 -a绝不加 --volumes每周一次 磁盘监控有状态服务较多重点看日志轮转和卷管理容器 prune 频率不要太高按需处理这个表是根据我自己不同环境的使用经验整理的不是死规则但它至少提供了一个思路开发环境追求空间最大化生产环境优先保证稳定性和可用性。另外我也在 Docker Desktop 上遇到过同样的问题Windows/macOS 上 Docker 会把数据放到虚拟机磁盘里虽然你在桌面端不方便直接进 overlay2 目录看但可以用docker system df快速定位再通过 Docker Desktop 的“清理”按钮或者命令行 prune 处理道理完全一致。最后再说一个我实际用下来的经验。现在每次新装 Docker我会第一时间写好 daemon.json把日志大小限制掉每部署一个有状态容器第一件事就是把数据目录挂到卷每次 build 完正式用途的镜像都会顺手跑一次docker image prune -f。这些习惯叠加在一起才让我后来很少再遇到 overlay2 把磁盘塞满的深夜告警。如果你现在正被这个问题折腾按照上面的定位和清理顺序走一遍大概率能在十几分钟内把空间找回来也会对 Docker 的存储机制有个更直观的理解。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C#远程桌面实时监控源码解析:屏幕采集与Socket传输实战 2026/9/16 22:38:49

C#远程桌面实时监控源码解析:屏幕采集与Socket传输实战

简介:一份C#远程桌面实时监控完整源码包,适合需要实现远程桌面控制、屏幕实时查看与监控的.NET开发者,或学习Socket通信、桌面捕获、客户端/服务端架构的C#中级学习者。资源由客户端、服务端与封装类库三个项目组成,核心实例类封装…

阅读更多 →
Codex生态插件化爆发:设计、浏览器、视频、支付四大入口争夺战 2026/9/16 22:38:49

Codex生态插件化爆发:设计、浏览器、视频、支付四大入口争夺战

最近我把Codex生态里能翻到的开源项目、技术帖和产品公告都过了一遍,发现一个很明显的变化:Codex已经从单一的AI编程助手,慢慢长成了一张插件网络。你打开GitHub Trending或者国内的开发者社区,会看到越来越多项目不再强调“我多会…

阅读更多 →
2026年AI大模型应用专家成长指南 2026/9/16 22:38:49

2026年AI大模型应用专家成长指南

1. 为什么2026年AI大模型应用专家会成为黄金职业?三年前GPT-3的横空出世,让所有人第一次意识到大模型的潜力。而今天,当GPT-4、Claude、Llama等模型已经能够编写代码、分析财报、创作剧本时,一个全新的职业赛道正在形成——AI大模…

阅读更多 →
Android Studio打包全流程解析:Gradle配置、签名与自动化构建 2026/9/16 22:38:49

Android Studio打包全流程解析:Gradle配置、签名与自动化构建

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
硬件面试电路分析三大核心能力:节点建模、工作区判据与小信号模型选择 2026/9/16 22:38:49

硬件面试电路分析三大核心能力:节点建模、工作区判据与小信号模型选择

1. 这不是题库搬运,而是电路分析能力的现场还原“硬件笔试面试2026年通关秘籍:电路分析核心问题深度剖析”——这个标题里藏着一个被绝大多数求职者严重低估的事实:用人单位从不考你背过多少道题,他们只考你面对一张陌生电路图时&…

阅读更多 →
es-toolkit 的 isWeakMap 类型守卫:从 compat 用法到 instanceof 源码实现 2026/9/16 22:35:48

es-toolkit 的 isWeakMap 类型守卫:从 compat 用法到 instanceof 源码实现

es-toolkit 的 isWeakMap 类型守卫:从 compat 用法到 instanceof 源码实现 【免费下载链接】es-toolkit A modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash. 项目地址: https://gitcode.com/GitHub_…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞