当 GC 失败时如何手动清理 blob 目录

解读

国内生产环境普遍使用 HarborDocker Distribution 作为私有镜像仓库。GC(Garbage Collection)失败通常表现为 磁盘空间持续增长registry 日志报 “blob not found”Harbor UI 清理任务卡住S3 后端出现 404。根本原因是 registry 的 mark-and-sweep 阶段中断,导致 orphan blob(已无任何 manifest 指向的层文件)未被删除,堆积在 docker/registry/v2/blobs/sha256/* 目录。手动清理必须在 只读模式 下进行,否则并发推送会产生数据不一致,甚至触发 镜像拉取 500 错误。因此,面试官想确认你能否在 零停机可接受窗口 内,安全地回收空间并恢复服务。

知识点

  1. registry 存储结构blobs/sha256/xx/xxx… 存放真实层文件,repositories/*/manifests 存放镜像索引,_layers 存放软链接。
  2. GC 两阶段:read-only=true → docker-registry garbage-collect config.yml → 生成 mark 清单 → 删除未标记 blob。
  3. GC 失败常见根因
    • S3 令牌过期 导致 list 中断;
    • NFS 锁竞争 造成 manifest 读取超时;
    • Harbor 2.1 之前版本 的 Redis 缓存与数据库不一致,mark 阶段漏扫。
  4. 手动清理原则先备份再只读再二次标记再删除最后校验
  5. 工具链registry garbage-collect --dry-runfuserlsofrsync --deletesha256sum 比对。

答案

步骤以 Harbor 2.8 + filesystem 存储 为例,S3 后端只需把本地路径换成 s3cmd 即可

  1. 禁用写操作
    在 harbor.yml 设置 read_only: true重启 harbor-core 与 registry;若仅用原生 distribution,给 registry 加环境变量 REGISTRY_STORAGE_MAINTENANCE_READONLY=true

  2. 备份元数据
    cp -a /data/registry/docker/registry/v2/repositories /backup/repositories_$(date +%F)
    只备份元数据,不备份 blob,节省空间与时间。

  3. 二次标记(生成白名单)
    docker run --rm -v /data/registry:/registry -v /etc/registry/config.yml:/etc/registry/config.yml registry:2.8 garbage-collect --dry-run /etc/registry/config.yml > /tmp/mark.list 2>&1
    解析 mark.list,提取 “marked” 的 blob digest,写入 /tmp/white.list,一行一个 sha256:xxx…

  4. 扫描现存 blob
    find /data/registry/docker/registry/v2/blobs/sha256 -type f -name 'data' | awk -F/ '{print $(NF-1)}' | sort > /tmp/all.blob

  5. 求差集得 orphan
    comm -23 /tmp/all.blob /tmp/white.list > /tmp/orphan.blob

  6. 安全删除
    while read dgst; do rm -rf /data/registry/docker/registry/v2/blobs/sha256/${dgst:0:2}/$dgst; done < /tmp/orphan.blob
    删除后 再次运行 sha256sum 抽样校验仍在白名单中的 blob 可正常读取,确保无误删。

  7. 恢复写操作
    read_only 改回 false,重启 registry;Harbor 需额外 清空 Redis 缓存 redis-cli -n 2 FLUSHDB,防止旧 manifest 缓存命中。

  8. 验证
    docker pull 私有域名/项目/镜像:tag 成功,GC 后磁盘空间下降du -sh /data/registry 对比,Harbor 项目配额实时刷新 即视为完成。

拓展思考

  1. 在线清理方案:若业务 不允许只读,可搭建 双实例主从(利用 harbor replication),在从库做 GC,完成后 切换 SLB 流量,实现 用户无感知
  2. 自动化兜底:在 夜维脚本 里先 garbage-collect --dry-run 统计可释放空间,超过阈值 20 % 才触发只读与真实 GC,否则只报警,避免频繁中断。
  3. 版本缺陷:Harbor 2.3 之前存在 artifact 与 blob 不同步 的 bug,需 升级至 2.5+ 并执行 migrate -t 220 修复数据库,否则手动清理后仍会出现 幽灵记录
  4. S3 后端清理加速:使用 s3cmd lifecycle 先标记 orphan 对象,再调用 registry GC减少 LIST 请求费用;同时开启 S3 多版本暂停,防止删除后又被版本化占用空间。