大型 Docker 开发镜像磁盘排查:containerd、缓存与容量规划
摘要:给出大型开发镜像的磁盘排查顺序,区分 containerd 镜像数据、snapshot、BuildKit cache、导出归档和源码构建输出。
文章目录
- 大型 Docker 开发镜像磁盘排查:containerd、缓存与容量规划
- 1. 第一层先看文件系统
- 2. 第二层看宿主机真实目录
- 3. 第三层看 Docker 逻辑对象
- 4. 构建过大镜像以后单独看 BuildKit cache
- 5. 为什么 builder prune 不会把 50 GiB 镜像变成 27 GiB
- 6. inactive 不等于“不需要”
- 7. image prune 和 system prune 的范围不同
- 8. 不要直接删除 `/var/lib/containerd`
- 9. 导出归档经常是被忽略的一大块
- 10. 源码 build 目录也可能很大
- 11.>大型开发镜像 containerd content unpacked snapshot BuildKit cache 源码 build 输出 镜像导出归档
这时如果只看到:
/dev/sdaX 90%然后立刻运行
docker system prune -a,很容易删掉重新构建代价很高的开发镜像。更好的方式是先回答:
空间到底被哪一类数据占用了?
1. 第一层先看文件系统
df-h/它回答的是:
整个根文件系统还剩多少空间?它不会告诉你 Docker 哪个对象在占空间。
如果镜像归档放在其他分区,还要分别看:
df-h/path/to/archive大型镜像导出时,Docker 数据和归档文件可能位于不同文件系统,不能只检查一个路径。
2. 第二层看宿主机真实目录
containerd image store 环境下,至少检查:
sudodu-sh/var/lib/containerd /var/lib/docker这回答的是宿主机目录实际占用。
Docker 当前文档说明,containerd image store 下的 image contents 和 container snapshots 默认在:
/var/lib/containerd所以新 Docker 环境中只看
/var/lib/docker已经不够。3. 第三层看 Docker 逻辑对象
dockersystemdf需要更详细时:
dockersystemdf-v它让你从 Docker 对象视角看:
Images Containers Local Volumes Build Cachedu和docker system df不要求数字完全一致。一个是文件系统目录视角,一个是 Docker 对象和共享关系视角。
4. 构建过大镜像以后单独看 BuildKit cache
如果刚执行过大型
docker buildx build,再看:dockerbuildxdu大型 SDK 构建经常产生很大的 BuildKit cache。
它和“最终镜像本身”不是同一个对象:
Build Cache 构建阶段复用 Final Image docker run 使用如果 cache 明确可回收,可以:
dockerbuilder prune这通常是大型镜像构建完成后的第一类清理对象。
5. 为什么 builder prune 不会把 50 GiB 镜像变成 27 GiB
如果当前 containerd image store 需要同时保存:
image content unpacked snapshot那么它们属于最终镜像运行体系。
执行:
dockerbuilder prune只会处理 BuildKit cache。
所以即使清掉 20 GiB 构建缓存,最终镜像相关的几十 GiB 仍然可能存在。
这不是 prune 失败,而是你清理的是不同对象。
6. inactive 不等于“不需要”
大型开发镜像有一个危险特点:平时不一定有常驻容器。
所以 Docker 可能显示:
ACTIVE 0但这只说明现在没有容器使用它,不代表镜像应该删除。
一个 20+ GiB 开发镜像可能构建几个小时,甚至需要重新复制大型 SDK。
因此看到 inactive 后不要直接:
dockersystem prune-a更合理的是先确定:
这个镜像是否是正式开发环境? 是否已经有可靠离线备份? 是否能快速重新构建?7. image prune 和 system prune 的范围不同
较温和:
dockerimage prune更激进:
dockerimage prune-a范围更广:
dockersystem prune-a越往后,自动判断“未使用”的对象范围越大。
对于普通 CI 临时环境,这可能很方便;对于手工制作的大型 SDK 镜像,应该更保守。
建议先:
dockersystemdf-v确认对象,再做针对性清理。
8. 不要直接删除
/var/lib/containerd即使:
sudodu-sh/var/lib/containerd显示几十 GiB,也不要执行:
sudorm-rf/var/lib/containerd/*containerd 的 content、metadata 和 snapshot 之间存在引用关系。
绕过 Docker/containerd 管理层手工删除,可能导致:
镜像 metadata 仍然存在 底层 blob 已损坏 snapshot 引用不一致 容器无法启动底层目录不是普通“缓存目录”。
清理应优先通过 Docker CLI 或明确的官方迁移流程完成。
9. 导出归档经常是被忽略的一大块
例如你为了迁移镜像,在:
~/images/放了:
cross-dev.tar cross-dev.tar.zst如果原始 TAR 没删,可能同时多占:
20+ GiB TAR + 10+ GiB 压缩归档它们完全不属于 Docker,因此:
dockersystemdf不会显示。
这就是为什么排查不能只看 Docker CLI。
可以检查:
du-sh~/imagesfind~/images-maxdepth1-typef-size+1G-ls大型镜像场景里,“导出文件忘了删”非常常见。
10. 源码 build 目录也可能很大
如果开发容器使用 bind mount:
宿主机源码 -> /workspace那么容器生成的:
build/ *.o *.a *.so 打包产物都可能实际写在宿主机项目目录。
这些也不属于 Docker image store。
所以完整排查还应该看:
du-sh~/work/demo-appdu-sh~/work/demo-app/build不要看到“是容器编译产生的”就认为一定在
/var/lib/docker。11.>{"data-root":"/mnt/docker-data"}
但 Docker 当前官方文档明确说明:在 containerd image store 下,
data-root不会自动改变 containerd image contents 和 snapshots 的位置。于是可能变成:
/mnt/docker-data Docker 其他数据 /var/lib/containerd 镜像内容和 snapshot如果你的目标是彻底把大型镜像数据迁出根分区,就必须把 containerd 数据位置也纳入设计,而不是只修改 Docker
data-root。这类存储迁移涉及 daemon 停止、数据复制和配置一致性,不建议在磁盘快满时临时手工移动目录;应按 Docker/containerd 官方数据目录配置方式操作。
12. 一个 80 GiB 根分区为什么很容易不够
假设:
系统自身 15 GiB 开发镜像相关数据 45~55 GiB BuildKit cache 10 GiB 源码和 build 5 GiB总量已经可能达到:
75~85 GiB如果这时还在根分区导出:
cross-dev.tar.zst 10+ GiB很容易直接失败。
因此对超大型开发镜像,磁盘规划应该比“镜像 SIZE + 5 GiB”保守得多。
13. 更实用的容量规划方式
可以按几类数据分别估算:
A. 操作系统和普通工具 B. containerd image content C. unpacked snapshots D. BuildKit cache 峰值 E. 源码和构建产物 F. 镜像导出归档其中 F 最适合放到另一块盘或网络存储,因为它只在迁移时需要。
如果这台机器长期维护大 SDK 镜像,更合理的硬件布局是:
系统根分区 放 OS 和普通工具 大容量数据分区 放 Docker/containerd 数据 或至少放离线镜像归档14. 推荐的排查顺序
以后遇到 Docker 把磁盘吃满,可以按下面顺序:
对应命令:
df-h/sudodu-sh/var/lib/containerd /var/lib/dockerdockersystemdf-vdockerbuildxdudu-sh~/images ~/work/demo-app/build2>/dev/null这五步基本能把“大空间去哪了”分成明确类别。
15. 最后再决定处理策略
如果主要是 BuildKit cache:
dockerbuilder prune如果是明确不需要的旧镜像:
dockerimagerm<image>如果是离线归档:
转移到移动硬盘 / NAS 或确认备份后删除本地副本如果是 containerd image store 的最终镜像本身:
它不是“垃圾缓存”此时真正的解决方式可能是扩大数据分区、迁移 containerd 数据位置,或者重新评估是否必须长期保留如此巨大的完整 SDK 镜像。
关键原则只有一句:
先确认数据身份,再清理;不要用最激进的 prune 去替代诊断。
参考资料
- Docker Docs:containerd image store with Docker Engine — https://docs.docker.com/engine/storage/containerd/
- Docker Docs:Docker daemon data directory — https://docs.docker.com/engine/daemon/
- Docker Docs:Storage drivers — https://docs.docker.com/engine/storage/drivers/
MCP在工业物联网中的应用:一年半实践,谁在用、怎么用、如何避坑
1. 引子:一年半观察窗口,工业圈聊MCP不再像聊外星文明 做工业物联网这行久了,你会习惯一个事实:工业界对新技术的态度,经常是“喊得响、动得慢”。MCP(Model Context Protocol,模型上下文协议&a…
入行两年,重新聊聊软件测试:核心认知、体系框架与后续学习路线
大家好,这是我的第一篇技术博客。计算机专业毕业两年,深耕软件测试行业一年,从最开始只会点点页面、对照需求测bug的新手,到现在完整参与迭代项目、独立负责模块测试、梳理测试流程与用例体系,踩过很多坑,也…
社区团购系统开发哪个好?凡科商城适合哪些商家长期做社区团购
今天给大家带来社区团购系统开发哪个好?凡科商城适合哪些商家长期做社区团购。艾媒咨询2026年中国小程序电商平台用户调查数据显示,用户在电商社区团购小程序上购买商品前三类分别是新鲜蔬菜、粮油米面/调味品、新鲜水果,占比分别为29.56%、2…
Atmosphere:Switch 定制固件上手指南
Atmosphere:Switch 定制固件上手指南 【免费下载链接】Atmosphere Atmosphre is a work-in-progress customized firmware for the Nintendo Switch. 项目地址: https://gitcode.com/GitHub_Trending/at/Atmosphere Atmosphere 是一个为 Nintendo Switch 提供…
从零搭建工业控制系统(二十五):Web API集成与数据上报
Web API集成与数据上报这是「从零搭建工业控制系统」系列第25篇。前面讲了本地数据存储,这篇讲远程上报——怎么把采集的数据推送到Web服务器,怎么处理网络断开。为什么需要数据上报 工业设备产生的数据不只是本地用。远程监控、数据分析、报表生成都需要…
毕业季了AIGC率太高怎么办?学姐亲测:从90%直降到10%以内的保姆级指南(2026年版)
又是一年一度的毕业季了,作为刚从论文的折磨里里上岸的学姐,在经历了三轮盲审和无数次检测,我发现现在的毕业生最怕的根本就不是查重率,而是那个宛如玄学般的AIGC检测值和如何降ai。 明明是自己对着电脑一个字一个字抠出来的&…