如何限制每个租户的最大镜像数量

解读

在国内私有云或行业云场景里,**“租户”**通常对应一个命名空间(Namespace)或一个 Harbor 项目(Project)。
面试官想确认你是否理解:

  1. Docker 本身没有“租户”概念,必须借助 镜像仓库级(Registry) 的配额机制;
  2. 配额需要与 身份认证(LDAP/OIDC)+ RBAC 打通,防止租户绕过;
  3. 配额超限后,push 阶段必须强制拒绝并给出清晰错误码,否则就是“假限制”;
  4. 还要考虑 镜像 GC 策略,防止租户“删标签不释放空间”导致配额统计失真。

知识点

  • Harbor 配额模型:项目级配额(Project Quota)支持“镜像数量”与“存储容量”双维度,基于 Redis 计数,数据库事务保证一致性。
  • OCI Distribution Spec:Docker Registry v2 协议在 push manifest 阶段返回 429/403 即可阻断上传,Harbor 中间件 quota.go 正是利用该扩展点。
  • 配额计算口径:数量=同一 Repository 下不同 Digest 的 Manifest 个数,标签(tag)重复覆盖不会增加计数,但多架构索引(index)每张子 manifest 都会计入。
  • 软限制与硬限制:国内金融云常要求“软 80% 邮件、硬 100% 拒绝”,Harbor 通过 webhook 触发企业微信或钉钉告警。
  • 多租户隔离:若使用 Harbor 复制模式,需在主实例上开启“只读非管理员”,防止租户在子实例绕过配额。
  • Jenkins CI 适配:在 pipeline 里捕获 429 错误,自动触发 镜像清理脚本(保留最近 N 个版本),实现无人值守。

答案

生产环境最成熟的方案是 Harbor 项目级配额,步骤如下:

  1. 安装 Harbor ≥ v2.2,启用“配额管理”特性(helm 安装时 quota.enabled=true)。
  2. 为每个租户创建独立 Project,在“项目配置→镜像数量”字段填写上限值,例如 200。
  3. 通过 OIDC 绑定企业微信或 LDAP 组,把用户加入该项目 Developer 角色,确保只能 push 到本项目。
  4. 当租户 CI 执行 docker push 时,Harbor core 服务会在 PUT /v2/<name>/manifests/<tag> 阶段检查计数;若超限立即返回
    DENIED: The image count exceeds the quota of 200 for project tenant-a
    HTTP 403,Docker CLI 直接退出非 0,CI 任务失败。
  5. 若需自动化清理,可调用 Harbor API
    GET /projects/{project_id}/repositories/{repo}/artifacts?with_tag=true
    按 created_time 排序,保留最近 30 个 digest,其余执行 DELETE,删除后立即触发 GC 释放配额计数

若环境未部署 Harbor,也可临时用 Registry 插件方案

  • 官方 Distribution 没有计数接口,需自研 authz 插件(Go 实现)拦截 manifest PUT,把计数写入 Redis HashHINCRBY tenant:<name>:count 并设置 TTL 与事务锁;
  • 插件返回 429 即可阻断;
  • 该方案需自己处理 并发锁、计数回滚、GC 同步,维护成本高,国内仅少数大厂自研,面试时建议优先回答 Harbor。

拓展思考

  1. 镜像数量与存储容量双维度配额如何权衡?
    数量配额防止“小镜像大数量”拖慢数据库索引;容量配额防止“超大镜像”占满磁盘。国内运营商通常 数量≤500 且容量≤500 GiB,双触发任一即拒绝。
  2. 如何防止租户利用“多架构索引”绕过数量限制?
    Harbor 2.5+ 已把 index 里的子 manifest 全部计入;若自研插件,需在 manifest list 展开阶段递归统计
  3. Serverless 场景下函数镜像生命周期极短,配额是否还有意义?
    可改为 TTL 策略:镜像 24 h 内无 pull 访问即自动回收,配额只用于防止瞬时 burst,降低 Redis 压力。
  4. 国产信创环境(ARM+openEuler)如何移植?
    Harbor 官方镜像已支持 arm64,只需替换基础镜像为 openEuler 20.03 LTS,重新编译 quota 插件即可通过鲲鹏 900 测试。