Harbor 私有镜像仓库部署与使用:项目、权限与垃圾回收
团队一旦开始用 Docker 交付,镜像放哪儿很快会成为问题:公共仓库传私有镜像有泄露风险,各自 docker save/load 又无法做版本管理和权限控制。Harbor 是 CNCF 毕业的开源镜像仓库,提供项目隔离、基于角色的权限、镜像复制、漏洞扫描和垃圾回收,正好补上这块短板。本文完成一台 Harbor 的部署与日常使用配置,并把上线后最容易踩的坑提前讲清。
适用环境:一台独立的 Linux 主机(建议 4 核 8G 起步,磁盘按镜像总量预留并可扩容),域名 harbor.example.com 解析到该主机。下文以 Harbor 2.x 离线安装包为例,存储使用本地磁盘,证书使用自有 CA 或公有 CA 签发的证书。
前置条件
- 主机已安装 Docker Engine 与 Docker Compose v2,时间已同步(证书校验对时间敏感)。
- 域名 harbor.example.com 已解析到主机(示例 IP 192.0.2.20),443 端口放行。
- 已准备好该域名的证书文件 fullchain.pem 与 privkey.pem;内网环境用内部 CA 签发也可以,但要把 CA 根证书分发到所有客户端,见后文。
- Harbor 对主机名敏感,规划好域名后不要随意改,改域名意味着所有客户端要重新 login 并改镜像前缀。
第一步:获取安装包并改 harbor.yml
Harbor 提供在线与离线两种安装包:在线包体积小、安装时从官方仓库拉组件镜像;离线包把全部镜像打进一个 tar,内网和生产环境应优先用离线包,避免安装时受外网波动影响。下载解压后只有一个关键配置文件 harbor.yml,由模板复制而来:
tar xvf harbor-offline-installer-v2.11.0.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
vi harbor.yml
需要改的关键项不多,但每一项都影响后续使用:
hostname: harbor.example.com
https:
port: 443
certificate: /srv/harbor/certs/fullchain.pem
private_key: /srv/harbor/certs/privkey.pem
harbor_admin_password: '请改成强密码'
data_volume: /data/harbor
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
说明三点:第一,data_volume 是镜像层、数据库和 Redis 的总目录,务必放在独立的大磁盘上并纳入备份与磁盘告警,上线后再迁移成本很高。第二,http 段建议整段注释掉,只留 HTTPS,避免明文传输镜像和凭据。第三,harbor_admin_password 只在首次初始化时生效,装完再改这个文件不会同步修改管理员密码,改密要走 Web 界面或 API。
第二步:安装与首次登录
./prepare
./install.sh
docker compose ps
install.sh 会用 Compose 拉起 harbor-core、registry、portal、db、redis、log 等一组容器。全部 healthy 后浏览器打开 https://harbor.example.com,用 admin 账号和刚设置的密码登录,第一件事是修改管理员密码并创建一个日常运维用的管理员账号,admin 账号只作应急保留。
第三步:客户端登录与推送拉取
在任意一台开发或 CI 主机上:
docker login harbor.example.com
docker tag myapp:1.0.0 harbor.example.com/team/myapp:1.0.0
docker push harbor.example.com/team/myapp:1.0.0
docker pull harbor.example.com/team/myapp:1.0.0
镜像名必须带仓库域名和项目名两段前缀,Harbor 按项目做隔离,不带项目名推送会被拒绝。CI 里不要用个人账号登录,给每个流水线建独立的机器人账户(项目内「机器人账户」),权限只给 push/pull 对应项目,令牌可单独吊销。
第四步:项目与成员权限模型
Harbor 的权限以「项目」为边界。项目分公开与私有:公开项目允许匿名 pull,私有项目必须登录且是成员。成员角色从高到低为:项目管理员(管成员与项目配置)、开发者(push/pull)、访客(只 pull)、受限访客(pull 且受配额等限制)。实务建议:
- 按团队或产品线建项目,如 team、infra、base;基础镜像单独放 base 项目,只给少数人 push 权限,避免人人都能覆盖基础镜像。
- 生产拉取使用只读的机器人账户或访客账号,推送账号只出现在 CI 里,权限分离能显著降低令牌泄露的影响面。
- 在系统管理里打开「禁止内容」相关策略时要谨慎,例如阻止拉取有高危漏洞的镜像,先观察一段时间再开启拦截,避免误伤发布。
第五步:保留策略与垃圾回收
镜像只进不出,磁盘迟早被打满。Harbor 的清理分两步,缺一不可:保留策略决定「哪些 tag 从界面上删除」,垃圾回收(GC)才真正回收 blob 占用的磁盘。
在项目内配置保留策略,常见组合是:保留最近推送的 10 个版本、同时保留最近 30 天内的 tag、并对 latest 这类长期 tag 单独设置始终保留。在系统管理 → 垃圾回收里设置定时 GC(例如每周日凌晨),有两点要注意:
- GC 执行期间仓库会短暂进入只读状态,推送会被拒绝,定时任务必须避开发布窗口。
- 被保留策略删掉 tag 但仍被其他 tag 引用的共享层不会被回收,这是正常现象;GC 日志里的实际回收量小于删除 tag 数时先看层引用关系,不要怀疑 GC 没生效。
- 执行 GC 前确保没有正在进行的大镜像推送,中断的上传会产生无用分片,也正是 GC 要清理的对象之一。
第六步:复制与备份要点
复制(Replication)用于把镜像同步到另一个仓库:灾备仓库、异地机房、或者把官方基础镜像同步进内网加速拉取。规则按项目或 tag 过滤配置,触发方式可选手动、定时或事件驱动(push 后自动复制)。注意复制是单向的,目标端同名 tag 已存在时按规则决定是否覆盖,生产仓库与灾备仓库不要配成双向复制。
备份方面,Harbor 的核心资产是两样:data_volume 目录(镜像层与数据库)和 harbor.yml 及证书。官方推荐停机后整体打包数据卷;不停机直接拷 registry 目录会得到不一致的对应关系,恢复时会出现界面有记录、拉取 404 的半残状态。元数据与部署参数要一起备份、一起留存版本。
验证
curl -k https://harbor.example.com/api/v2.0/health
docker login harbor.example.com
docker push harbor.example.com/library/hello:test
health 接口各组件返回 healthy、用新建项目的机器人账户能完成一次 push 与 pull,即认为部署可用。再到界面确认该 tag 的摘要(digest)与本地 docker images --digests 一致。
常见问题
1. docker login 报 x509: certificate signed by unknown authority。Harbor 用了内部 CA 或自签证书,Docker 客户端不信任。把 CA 根证书放到客户端的 /etc/docker/certs.d/harbor.example.com/ca.crt(注意目录名带端口时要写 harbor.example.com:443),重启 Docker 后再登录。不要用在 daemon.json 里配 insecure-registries 关掉校验作为长期方案,那等于放弃传输安全。
2. 推送大镜像报 413 Request Entity Too Large。Harbor 前面若还有一层 Nginx 或负载均衡,请求体大小限制在那层。把入口代理的 client_max_body_size 调大(如 0 表示不限制或设为 1024m),Harbor 自带的 nginx 默认已处理,本问题基本都出在自加的前置代理上。
3. login 成功但 push 报 unauthorized 或 denied。先确认镜像前缀里的项目名存在且账号是该项目成员、机器人账户未过期且未被禁用;再确认 tag 是否命中了项目的「不可变 tag」规则,被设为不可变的 tag 不能覆盖推送,这是保护生产镜像的机制,不是故障。
4. 界面删了 tag 磁盘却没变小。删除 tag 只是删元数据,必须等 GC 执行后 blob 才回收,见第五步。另注意 GC 分 dry run 与正式执行,定时任务别只配成演练模式。
小结
Harbor 上线不难,长期用得稳靠三件事:部署时把数据卷和域名一次规划到位;权限上坚持按项目最小授权、CI 用机器人账户;运维上把保留策略与定时 GC 配成组合拳,并把 GC 时间避开发布窗口。做到这三点,私有仓库基本可以从「装完就不敢动」变成团队的日常基础设施。







