Docker 磁盘占用过高清理实战:overlay2、容器日志与悬空镜像

    发布时间:2026-09-12 04:35 更新时间:2026-09-12 04:35 阅读量:0

    跑了一段时间的 Docker 主机,常常会遇到根分区悄悄变满:df -h 显示 / 已用 90% 以上,但业务量并没有明显增长。多数情况下,占空间的不是镜像数量,而是容器日志无限追加、镜像层里的悬空中间层,以及构建缓存叠加出来的结果。这篇文章按“先定位、再限制、后回收”的顺序,把 overlay2 存储层的占用来源和几条常用清理命令的适用边界讲清楚,动手前请务必确认命令会删掉什么。

    一、定位:占用到底在 overlay2 的哪一层

    Docker 默认使用 overlay2 存储驱动,镜像的每一层都会在 /var/lib/docker/overlay2 下生成一个以随机 ID 命名的目录,目录里的 diff 子目录存放该层的实际文件内容,link 存放短链接名,而 merged 是把若干层叠加后给容器看到的挂载视图。merged 本身不额外占用磁盘,但它是一个挂载点,直接用 du 统计整个目录会把同一份数据重复算进去,得出的数字往往虚高。

    df -h /var/lib/docker
    docker system df -v
    du -shx /var/lib/docker/overlay2
    du -hx --max-depth=1 /var/lib/docker | sort -h

    docker system df -v 会把镜像、容器、本地卷、构建缓存四类分别列出,还能看到每个镜像的虚拟大小和共享层大小,判断“是镜像多还是日志大”这一步就够了。du 命令加上 -x 参数表示不跨越文件系统边界,能避开 merged 挂载点带来的重复统计。如果 du 结果和 docker system df 差距很大,优先怀疑日志和卷。

    二、把容器日志关进笼子

    默认的 json-file 日志驱动没有大小上限,容器持续输出就会被写到 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log,一个日志文件涨到几十 GB 并不罕见。限制方式是在守护进程配置里统一设置轮转策略。

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

    改完 /etc/docker/daemon.json 后需要重载并重启 Docker,例如 systemctl reload docker 或 systemctl restart docker,具体以官方文档和实际环境为准。要特别留意:log-opts 只对新创建的容器生效,已经跑着的容器不会自动套用新策略,需要停止后用等价参数重新创建。运行中的容器若只是想把现有日志先压下去,可以用 truncate 截断:

    truncate -s 0 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log

    这里有个常见坑:直接 rm 掉日志文件并不会立刻释放磁盘空间,因为写入方仍然持有该文件的句柄,空间要等进程关闭句柄或容器重建后才回收,inode 也一直占着。truncate -s 0 是把文件长度截断为 0,句柄继续有效,空间立即回收,是更稳妥的做法。清空前建议确认该容器日志没有合规留存要求。

    三、镜像、构建缓存与卷:回收命令删的是什么

    docker image prune 默认只删除悬空镜像,也就是打过新标签后失去标签、且没有容器引用的层;docker image prune -a 则会删除所有没有被任何容器使用的镜像,包括还带着标签、但当前没有容器在跑的基础镜像。两者差别很大,生产机上盲目执行 -a,下次启动服务时可能触发重新拉取,遇到网络不通或私有仓库凭证失效就会直接起不来。

    docker image prune
    docker image prune -a
    docker builder prune
    docker volume prune
    docker system prune

    这几条命令的边界可以这样记:image prune 影响的是可重新拉取的镜像,风险相对可控;builder prune 清的是构建缓存,清理后下次构建会变慢但不会丢数据;volume prune 删除的是没有被容器引用的本地卷,而数据卷里通常放着数据库文件和业务上传目录,一旦删除无法通过重新拉取镜像恢复,必须确认过没有在用再执行;docker system prune 是前面几项的合集,加 --volumes 时会连卷一起删,属于高风险操作,建议只在可控的测试环境使用。容器被删除后,它的可写层 diff 会随之释放,但容器创建时产生的匿名卷默认不会跟着删除,这也是磁盘不降反升的常见原因之一。

    更稳妥的长期做法是把清理拆成两步:日常用 docker system df 和 du 做观察,只在明确知道删什么的时候才执行具体的 prune 子命令;同时把日志轮转作为标准配置下发到所有节点,让日志不再成为变量。回收完记得再跑一次 df -h 与 docker system df 对比,确认释放量符合预期,而不是只看命令返回的数字。对于有合规要求的环境,删除镜像和卷之前最好保留一份操作记录,方便回溯。

    继续阅读

    📑 📅
    Nginx 502/504 排查实战:从 upstream 超时到 php-fpm 进程池 2026-09-12
    MySQL 出现 Too many connections 怎么办:定位、连接池与超时调优 2026-09-11
    Linux用户与权限管理实战:sudoers、SUID/SGID与最小权限 2026-09-10
    systemd服务管理实战:从Unit编写到开机自启与自动重启 2026-09-10
    网站服务器迁移完整流程:数据同步、解析切换与验证 2026-09-09
    Let's Encrypt 证书自动续期失败排查:日志、80端口校验与 reload 钩子 2026-09-13
    Nginx 日志按天切割与过期清理:logrotate 实战 2026-09-15
    Docker Compose 部署多容器应用实战:环境变量、数据卷与重启策略配置要点 2026-09-15
    MySQL慢查询日志开启与优化入门 2026-09-15
    服务器定时任务实战:crontab 语法与不生效排查 2026-09-15