尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

k3s 镜像盘只增不减:删 8 个 tag 释放 0 字节,孤儿 manifest 才是真占盘的那个

k3s 镜像盘只增不减:删 8 个 tag 释放 0 字节,孤儿 manifest 才是真占盘的那个 k3s 镜像盘只增不减:删 8 个 tag 释放 0 字节,孤儿 manifest 才是真占盘的那个一套自建镜像跑起来的湖仓平台(SQL 网关、批流引擎、Notebook 内核、OLAP、对象存储),镜像盘会只增不减:每次引擎升级都新增一组 tag,旧组留着回滚。等到磁盘告警,按常规操作删掉旧 tag——空间一个字节都不掉。这不是玄学,是 containerd 的删除语义。「我的数据空间」(datastudiohappy.cn)这次把镜像盘从115G(71%)清到 81G(50%),释放 34G,全程零第三方镜像重下载。下面是可复用的那套判据。一、清理只有一条约束任何清理都不得导致「下次 build 或运行需要重新联网下载」。一条约束就够,因为它同时覆盖两类东西:自建镜像是真·单点——本地构建、从没 push 过任何仓库,任何 registry 上都不存在它,删了无处可拉、平台起不来;第三方镜像公共仓库上有、能重拉——但重拉就是联网下载,正是这条约束要避免的。所以清理的目标从来不是「删镜像」,而是删那些没有任何东西引用、却仍在占盘的记录与 blob。二、删 tag 不释放空间,因为 tag 不是占盘的那一头ctr images rm tag只摘 tag。同一个镜像的by-digest 记录(sha256:...那条)仍然在,继续钉住全部层——这就是删完旧 tag 后 overlayfs 快照纹丝不动的原因。实测:删 8 个旧 tag,占用44399MB → 44399MB,0 释放。真正该删的是孤儿 manifest:不被任何 tag 引用的那些sha256:记录。判据是引用式的——收集所有带 tag 镜像的 manifest digest 作为白名单,白名单之外的记录即孤儿。实测:15 条孤儿删完释放7.8GB,33 个 tag 镜像一个不少、19 个 pod 全 Running、查询冒烟 8/8。同样的道理还有一处更隐蔽:docker 侧的moby-danglingsha256:...记录。它是 docker 自己已经不显示(docker images -f danglingtrue为空)、但仍钉住快照的残留。这次清盘的主矿就是它。三、三个存储层,漏一层就白干产物散在三个互不相干的存储层,只看df根本不知道该清哪层:层里面是什么清什么k3s containerd(运行时)镜像记录 overlayfs 快照孤儿 manifest 记录k3s content store压缩层 blob无引用的 blob(引用式 GC)docker / moby本机只用来 build、零容器运行构建产物镜像、moby-dangling记录、无引用 content其中 content store 那层有个容易被误解的点:k3s 默认discard_unpacked_layerstrue,镜像解包成 snapshot 之后,压缩层 blob 本就是冗余的(运行跑 snapshot 不跑 blob),所以引用式地清掉无引用 blob,build 和 run 都不受影响。实测:content store20G → 1.1M,镜像一个不少、pod 全 Running。四、引用式 vs「有没有容器在用」式——这是红线所在这两种判据听起来像同一件事,后果差一个量级:引用式(content prune references、按白名单算孤儿):只删没有任何镜像对象引用的东西。仍被 tag 镜像引用的层由镜像对象保护,绝不会删。安全。「有没有容器在用」式(crictl rmi --prune、ctr images prune、docker system prune):按当前有没有 pod 在跑判生死。危险。危险在于:数据平台里有一大类按需拉起的镜像——批处理 Spark 作业、Flink application 集群、Notebook 内核。它们空闲时一个 pod 都没有,于是在这类 prune 眼里全是垃圾,而它们恰恰是自建单点。实测:某次批量清理一次释放 8GB,连带删掉了两个从未推过仓库的引擎镜像——两个都被在跑的部署清单引用着。判据是「有没有 pod 正在用」,不是「能不能重拉」。五、实测:34G 从哪来,以及三条反直觉动作释放摘249 条moby-dangling记录 引用式 content prune23G删 docker 侧上一代引擎镜像组7.6G删 k3s 侧上一代引擎镜像组(4 个 tag 各自 by-digest 记录)5.7G逐条删 13 条 docker 悬空层1G旧日志 已被取代的离线包0.8G三条值得记住的:CLI 看不见的记录是主矿,悬空层不是。13 条悬空层的「大小」加起来 32GB,实删只掉1G(层几乎全与 tag 化镜像共享);而docker images完全无感的 249 条记录掉了23G。按「大小」列排序去删,方向就错了。别按文件名里的版本号判生死。名字带旧版号的 connector jar 可能正在用;而看着在用的某个 jar 其实是从发行版目录里拷的、跟本地物料无关。要看COPY的源路径,grep 到名字 ≠ 引用了这个文件。硬链接会浪费你半小时。备份目录与构建物料目录若是硬链接(inode 相同、链接数 2),只删一侧不释放任何空间。六、leases不能一把梭containerd 的 lease 是 GC 保护。清理时需要先解掉孤儿 lease 的 pin,再跑引用式 prune——但只能删确认是孤儿的那些。把全部 lease 一次删光再 prune,containerd 会把「有镜像记录、但从没被任何 pod 解包使用过」的镜像整个回收掉(不只是压缩层)。实测一次丢了 15 个镜像,自建的那批只能从 build 侧重新导入,第三方的多数只能重新联网拉——正好撞在唯一那条约束上。正确做法:只删确认孤儿的 lease,或者干脆不碰 lease,直接跑引用式 prune。七、把判据固化成一个只读审计脚本镜像盘冲到高位,根因不是「忘了清」,而是三件事:删除语义会骗人、产物散在三层、能不能删一直靠人读文档加临场记忆。所以最后落下来的东西不是一份清理命令清单,而是一个只读、不删任何东西的审计脚本,输出报告供人决策,五段各答一个问题:段回答的问题1 存储水位现在多少、哪一层在胀2 缺失镜像有没有「声明了却不在」的(replicas0的 workload 不报 ImagePullBackOff,全绿也可能缺镜像)3 孤儿 manifest有多少能安全释放4 重建链这么清会不会害得下次 build 联网5 docker 侧产物悬空层与moby-dangling记录各多少关键是判据做成版本无关:第 4 段只问「上游 base 是不是本仓库自建的镜像」——是则按链先建上游,否则是真断点。不硬编码任何 tag。结论会随升级过期,判据不会。于是清理从「凭感觉动手」变成「跑一遍看报告再动手」。同一套思路在平台侧也是这么落的:资源与容量不靠人盯,靠可观测面板与配额闸。八、四句话总结删 tag 不等于删镜像:by-digest 的孤儿 manifest 才钉着层,删 tag 常常 0 释放;清理判据必须是引用式的,「当前有没有容器在用」式的批量 prune 会精准删掉按需拉起的作业镜像;产物散在三层(运行时镜像记录 / content blob / build 侧),CLI 看不见的那类记录往往是主矿,而「大小」列会把你带偏;真正的产出不是一串删除命令,而是一份只读审计报告 一条版本无关的判据——先看报告,再动手。「我的数据空间」是一套可私有化部署的数据平台(湖仓 调度 数据治理 智能诊断),部署、镜像与资源治理均已脚本化,支持 OEM 合作。产品介绍:https://datastudiohappy.cn/。
返回列表