<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>碧玉扉</title><description>Rediscory the beauty of typography</description><link>https://apoet.fun/</link><item><title>Harbor镜像存储异常占用清理记录</title><link>https://apoet.fun/posts/harbor%E9%95%9C%E5%83%8F%E5%AD%98%E5%82%A8%E5%BC%82%E5%B8%B8%E5%8D%A0%E7%94%A8%E6%B8%85%E7%90%86%E8%AE%B0%E5%BD%95/</link><guid isPermaLink="true">https://apoet.fun/posts/harbor%E9%95%9C%E5%83%8F%E5%AD%98%E5%82%A8%E5%BC%82%E5%B8%B8%E5%8D%A0%E7%94%A8%E6%B8%85%E7%90%86%E8%AE%B0%E5%BD%95/</guid><description>在进行服务器资源配置时，某些缓存文件可能才是真正的瓶颈</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Harbor镜像存储异常占用清理记录&lt;/h1&gt;
&lt;p&gt;学院的AI Station算力服务器分配给全体教师和学生使用，大约有140+用户，仅有的2TB空间难以支撑这么多人的镜像存储需求。服务器基本上每隔一段时间就会因为系统盘爆满而宕机。&lt;/p&gt;
&lt;p&gt;除去资源配比问题外，主要原因包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;资源使用粗放。启动容器时，系统存储在本地的2TB nvme上，数据挂载盘在管理节点的115TB机械硬盘上，巨大的差速迫使用户将模型权重放在非数据目录下；另一方面，部分用户存在习惯问题，把数据、日志等也打包到镜像中，导致镜像越来越大；&lt;/li&gt;
&lt;li&gt;镜像构建方式不当。习惯于从别人的已有镜像出发，如果缺少自己要的包，就打包，然后重新构建镜像。这种分层打包的方式让大家的镜像越来越大，服务器运行之初每个人的镜像一般在12G左右，现在运行3年，镜像普遍到了40G，部分账户下生产出了60-100G的大镜像&lt;/li&gt;
&lt;li&gt;K8S版本过旧，且配置存在不当，这是每次大清理都会发现的主要问题&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;粗糙管理&lt;/h2&gt;
&lt;p&gt;一直以来的做法都是搞一个统计面板，看看哪个老师的学生使用的镜像太大或者太多了，去跟对方沟通一下，删掉太大的镜像。
惯用的做法是告诉每个老师，让每个学生的账号下最多不超过2个镜像，且每个镜像不超过30G，如果有超过30G的镜像，则只允许保留1个。&lt;/p&gt;
&lt;h2&gt;Harbor垃圾回收&lt;/h2&gt;
&lt;h3&gt;手动清理悬空镜像&lt;/h3&gt;
&lt;p&gt;通过AI Station前端平台进行镜像删除后，Harbor中存在一些未被清理掉的悬空docker，需要在管理节点上手动执行清理命令。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker system prune
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;必要时增加&lt;code&gt;-a -f&lt;/code&gt;参数保证清理干净。&lt;/p&gt;
&lt;h3&gt;手动调用Harbor的垃圾回收&lt;/h3&gt;
&lt;p&gt;这是前期主要问题，即使删除了镜像，并调用了&lt;code&gt;docker system prune -a -f&lt;/code&gt;，在&lt;code&gt;df -h&lt;/code&gt;查看时仍然发现overlay2目录的存储占用极高，核心原因是k8s旧版本的garbage-collect没有自动执行（即使在网页端配置自动执行也无效），必须手动执行一次。&lt;/p&gt;
&lt;p&gt;两种路径：1. 通过Harbor网页端手动执行垃圾清理；2. 通过docker exec进入到harbor的管理shell，手动执行garbage collect的指令。&lt;/p&gt;
&lt;h2&gt;Harbor上传缓存&lt;/h2&gt;
&lt;p&gt;这个问题是今天新发现的。&lt;/p&gt;
&lt;h3&gt;解决过程&lt;/h3&gt;
&lt;p&gt;早期设置120镜像，基本都能正常运转，现在降到60镜像，镜像尺寸也没有大太多，磁盘占用达到99%，基本可以确定是镜像存储中有一些并非镜像本身的冗余。&lt;/p&gt;
&lt;h4&gt;空间分析&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;docker system df&lt;/code&gt;显示&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TYPE TOTAL ACTIVE SIZE RECLAIMABLE 
Images 47 47 9.129GB 1.233GB (13%) 
Containers 81 79 335.4MB 37.26MB (11%) 
Local Volumes 576 11 1.357kB 1.309kB (96%) 
Build Cache 0 0 0B 0B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从K8S本身看不出来有多少镜像占用。&lt;/p&gt;
&lt;p&gt;但是&lt;code&gt;df -h&lt;/code&gt;显示磁盘空间被&lt;code&gt;overlay&lt;/code&gt;占满：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Filesystem               Size  Used Avail Use% Mounted on
# ......
overlay                  1.9T  1.8T   21G  99% /var/lib/data/docker/overlay2/e4846fe7cfebc268d113044ce0cac1f3d2d0a42a6ab2db90eb1e57d8bbeea28f/merged
overlay                  1.9T  1.8T   21G  99% /var/lib/data/docker/overlay2/5d0963303d7c9b6845dc5d93469442146c02a6fee99cd797ec03cbe56ed89fed/merged
overlay                  1.9T  1.8T   21G  99% /var/lib/data/docker/overlay2/cbb3836190072aa0951cbf511e30b542502e75e542c61edbaaf4462c767ff6d9/merged
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对具体的目录进行分析，执行&lt;code&gt;du -xh --max-depth=1 /var/lib/data | sort -h&lt;/code&gt;得到如下信息，和预期一样，主要问题在harbor存储下。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;452K /var/lib/data/ldap 
525M /var/lib/data/etcd 
1.3G /var/lib/data/etcd_backup 
2.1G /var/lib/data/influxdb_backup 
11G /var/lib/data/docker 
14G /var/lib/data/mariadb_backup 
17G /var/lib/data/mysql 
26G /var/lib/data/log 
221G /var/lib/data/influxdb 
1.6T /var/lib/data/harbor 
1.8T /var/lib/data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继续深入查看&lt;code&gt;du -xh --max-depth=2 /var/lib/data/harbor/registry/dockerregistry/v2/repositories | sort -h | tail -50&lt;/code&gt;找到最大的几个仓库&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ......
19G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch/hongtauo_cv-t13 
28G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch/pytorch-t7-t7-t7
29G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch/pytorch_deepspeed_torch_llama_factory-12.10-h1 
63G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch/pytorch 
68G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch/zrh_docreasoning-stuzrh 
99G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/lerobot-t13-t13 
103G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh 
267G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other 
296G /var/lib/data/harbor/registry/docker/registry/v2/repositories/pytorch 
563G /var/lib/data/harbor/registry/docker/registry/v2/repositories
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个repositories目录占了563G空间，其中pytorch和other两个项目底下占用最多，这都符合预期。但从倒数8个目录之前出现了存储占用的显著不同，60G+还属于正常，但陡增到100+的存储显然不对。&lt;/p&gt;
&lt;p&gt;然而，harbor的真实layer数据存储在&lt;code&gt;/var/lib/data/harbor/registry/docker/v2/blobs&lt;/code&gt;下，这里的repositories存储的只是一些manifest、layer digest之间的link、上传过程中留下的数据等（此信息由ChatGPT提供）。显然manifest和link不可能有上百G的存储，那问题大概率出在上传过程。&lt;/p&gt;
&lt;p&gt;另一方面，通过对比实际看到的镜像列表，并与对应镜像的使用人实际沟通，这个103G的镜像并没有创建成功，这些信息也能确认该目录下存在的是某些缓存。&lt;/p&gt;
&lt;p&gt;对比blobs和repositories也能明显发现比例问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -sh /var/lib/data/harbor/registry/docker/registry/v2/blobs /var/lib/data/harbor/registry/docker/registry/v2/repositories
987G /var/lib/data/harbor/registry/docker/registry/v2/blobs 
563G /var/lib/data/harbor/registry/docker/registry/v2/repositories
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;具体对最大的镜像目录进行大小分析，进一步确定是&lt;code&gt;_uploads&lt;/code&gt;目录占用，应该是上传过程中服务器崩溃，留存下来的缓存文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;du -xh --max-depth=3 /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh | sort -h | tail -30 
# 大量4.0K的目录
4.0K /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_uploads/6d0af006-f4dd-4792-9519-75dca2459ea1/hashstates 
4.0K /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_uploads/b8c08c77-c085-4769-99f3-9936626c8880/hashstates 
88K /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_layers 
88K /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_layers/sha256 
131M /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_uploads/6d0af006-f4dd-4792-9519-75dca2459ea1 
103G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh 
103G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_uploads 
103G /var/lib/data/harbor/registry/docker/registry/v2/repositories/other/zrh_doc-stuzrh/_uploads/b8c08c77-c085-4769-99f3-9936626c8880
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来就要确定这些有没有在日常运行中被正常清理掉，先&lt;code&gt;docker ps | grep registry&lt;/code&gt;找到registry容器（本机上为registry），再&lt;code&gt;docker exec registry cat /etc/registry/config.yml&lt;/code&gt;，查看其中关于存储的字段，发现&lt;code&gt;uploadpurging&lt;/code&gt;字段被disable掉了（即一开始说的厂商配置不当）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;maintenance:
 uploadpurging:
  enabled: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常情况下它应该是类似如下的配置比较合理。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;storage:
  maintenance:
    uploadpurging:
      enabled: true
      age: 168h
      interval: 24h
      dryrun: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来就是分析占用量了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find /var/lib/data/harbor/registry/docker/registry/v2/repositories \
  -type d -name _uploads \
  -exec find {} -mindepth 1 -maxdepth 1 -type d -mtime +7 -exec du -sh {} \; \; \
  2&amp;gt;/dev/null | sort -h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此，问题分析完毕，可清理的空间高达560G。在多次上传中缓存的文件没有得到及时处理。
这个问题在网络上很少能找到类似情况的，看到的大多数清理都是处理日志占用之类的问题，关于上传缓存的清理没见过。&lt;/p&gt;
&lt;h4&gt;处置&lt;/h4&gt;
&lt;p&gt;这个处置就相对容易了，先通过Harbor UI将仓库设置成只读，然后直接脚本清理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find /var/lib/data/harbor/registry/docker/registry/v2/repositories \
  -type d -name _uploads \
  -print0 |
while IFS= read -r -d &apos;&apos; dir; do
    find &quot;$dir&quot; \
      -mindepth 1 \
      -maxdepth 1 \
      -type d \
      -mtime +7 \
      -exec rm -rf {} +
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后设置一个脚本，每天晚上清理一次。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

BASE=&quot;/var/lib/data/harbor/registry/docker/registry/v2/repositories&quot;
DAYS=7
LOG=&quot;/var/log/harbor-clean-uploads.log&quot;

echo &quot;[$(date &apos;+%F %T&apos;)] start&quot; &amp;gt;&amp;gt; &quot;$LOG&quot;

find &quot;$BASE&quot; -type d -name _uploads |
while IFS= read -r dir; do
    [ -z &quot;$dir&quot; ] &amp;amp;&amp;amp; continue

    find &quot;$dir&quot; \
        -mindepth 1 \
        -maxdepth 1 \
        -type d \
        -mtime +&quot;$DAYS&quot; |
    while IFS= read -r upload; do
        [ -z &quot;$upload&quot; ] &amp;amp;&amp;amp; continue

        echo &quot;[$(date &apos;+%F %T&apos;)] removing: $upload&quot; &amp;gt;&amp;gt; &quot;$LOG&quot;
        # echo &quot;would remove: $upload&quot; # dry run，测试时可以先运行这一句代替下面的rm，确定避免误删
        rm -rf -- &quot;$upload&quot;
    done
done

df -h /var/lib/data &amp;gt;&amp;gt; &quot;$LOG&quot;
echo &quot;[$(date &apos;+%F %T&apos;)] done&quot; &amp;gt;&amp;gt; &quot;$LOG&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用&lt;code&gt;crontab -e&lt;/code&gt;配置计划任务&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 3 * * * /usr/local/sbin/harbor-clean-uploads.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看运行日志就&lt;code&gt;tail -100 /var/log/harbor-clean-uploads.log&lt;/code&gt;。&lt;/p&gt;
&lt;h5&gt;关于harbor config&lt;/h5&gt;
&lt;p&gt;其实可以不自己写脚本，通过&lt;code&gt;docker inspect registry --format &apos;{{range .Mounts}}{{println .Source &quot;-&amp;gt;&quot; .Destination}}{{end}}&apos;&lt;/code&gt;找到&lt;code&gt;registry&lt;/code&gt;的映射目录，找到&lt;code&gt;config.yml&lt;/code&gt;文件，然后在里面修改&lt;code&gt;maintance&lt;/code&gt;字段进行修改，再&lt;code&gt;docker restart registry&lt;/code&gt;重启。&lt;/p&gt;
&lt;p&gt;但这个可能是厂商的Harbor安装配置自动生成的，这个奇怪的系统有什么暗坑也不知道，为了避免麻烦，这里没有选择改配置。&lt;/p&gt;
</content:encoded><category>服务器</category><author>八月槎</author></item><item><title>周末是自己的</title><link>https://apoet.fun/posts/%E5%91%A8%E6%9C%AB%E6%98%AF%E8%87%AA%E5%B7%B1%E7%9A%84/</link><guid isPermaLink="true">https://apoet.fun/posts/%E5%91%A8%E6%9C%AB%E6%98%AF%E8%87%AA%E5%B7%B1%E7%9A%84/</guid><pubDate>Sun, 05 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;周末是自己的&lt;/h1&gt;
&lt;p&gt;教育部本子没出校，周六也不怎么想看论文了，决定放松玩一下游戏，把从25年装上就没有玩过去的《黑神话·悟空》里大头娃娃这一关算是过去了，一路从广智、凌虚子、浪里个浪打到了广谋，可惜卡在了劝退BOSS白衣秀士上，太难了，又不知道什么时候才能过去咯。猴子不弱，菜的是我，大圣可没这么逊。再跟爱人一起打一打《天神镇》，体验建造然后重开的乐趣。&lt;/p&gt;
&lt;p&gt;卷不卷不重要，重要的是该休息的时候别让自己再那么焦虑了，周末是自己的。&lt;/p&gt;
&lt;p&gt;让Hermes+OpenCode帮自己搞了个杜甫诗集的网站，接下来还打算让它做个杜诗标注的网站，然后我一点一点把《杜诗镜诠》和《钱注杜诗》上的文本录入进去，也算是真正开始让AI服务于自己的兴趣。写了那么久数字人文的课程规划、基金本子，还是要自己兴趣出发才能真正开始做啊。&lt;/p&gt;
&lt;p&gt;一个小插曲，让Hermes调用OpenCode写代码时，它偷偷把我GLM coding plan里的API端点改成了普通调用的，账户里的80多块钱一天就用完了。幸好预付费我账上只有这么一点。以后涉及经济的还得是自己亲自审查过。&lt;/p&gt;
</content:encoded><category>随笔</category><author>八月槎</author></item></channel></rss>