1. 为什么我要自己搭一套私有镜像仓库
第一次认真考虑自建镜像仓库,是因为一次很尴尬的事故。团队做容器化改造,所有业务镜像都往公共仓库推,结果某天公共仓库限流,CI 流水线全线卡死,十几个服务等着发布,运维那边只能干瞪眼。那次之后我就下定决心,得在自己可控的环境里放一套镜像仓库,把镜像的"存取权"握在自己手里。Harbor 就是在这个背景下进入视野的——它是一个开源的容器镜像仓库项目,能存镜像、能管权限、能做镜像扫描、还能给镜像签名,基本覆盖了企业内做镜像治理的全部刚需。
说白了,Harbor 解决的核心问题就三个:镜像放哪儿、谁能动、动过之后安不安全。公共仓库能解决"放哪儿",但"谁能动"和"安不安全"这两件事,在多人协作、多环境隔离的场景下,公共仓库给不了你足够的控制力。Harbor 把这三件事一次性打包解决:项目级别的 RBAC 权限、基于角色的访问控制、镜像漏洞扫描、镜像复制、审计日志、配额管理,这些能力组合起来,才让它成为很多团队私有镜像仓库的首选。
这篇内容适合谁看?如果你正在做容器化落地,团队里镜像越堆越多、权限越来越乱、安全审计开始被提上日程,那这套东西你迟早要碰。如果你只是想本地跑个 demo 存两个镜像,那用不着 Harbor,一个轻量 registry 就够了。我下面讲的是真正要在团队里长期跑起来的那套方案,包括架构选型、部署细节、权限设计、日常运维和踩过的坑,尽量让你少走弯路。
2. 整体架构设计与选型思路拆解
2.1 Harbor 的组件构成与数据流向
Harbor 不是一个单体程序,它是一组服务拼起来的。核心组件包括:proxy(反向代理,通常用 nginx)、core(主服务,处理 API 和业务逻辑)、registry(真正存镜像的组件,基于开源 registry)、database(存元数据,默认 PostgreSQL)、redis(缓存和任务队列)、jobservice(异步任务,比如镜像复制、扫描),以及可选的trivy 扫描器、notary 签名服务。这些组件通过容器编排起来,对外只暴露一个入口。
理解这个结构很重要,因为它直接决定了你排查问题的思路。比如镜像推不上去,可能是 proxy 的证书问题,可能是 core 的认证问题,也可能是 registry 的存储问题,还可能是 database 连不上导致 core 起不来。你得知道请求是怎么流的:客户端先打到 proxy,proxy 转发给 core 做认证鉴权,认证通过后 core 返回一个 token,客户端拿着 token 直接和 registry 交互完成镜像的存取。这个"认证和传输分离"的设计是 Harbor 权限体系的基础,也是很多人第一次配的时候容易懵的地方。
2.2 为什么选 Harbor 而不是其他方案
市面上做私有镜像仓库的选择其实不少,我简单对比一下我考虑过的几个方向。轻量 registry 最省事,一个容器起来就能用,但它没有权限体系、没有 Web 界面、没有扫描,团队一多人就管不住。某些商业方案功能全但成本高,小团队用不起。Harbor 的定位刚好卡在中间:开源免费、功能完整、社区活跃、文档齐全,而且它是 CNCF 毕业项目,长期维护有保障。
更关键的是 Harbor 的几个能力正好戳中企业场景的痛点。项目隔离让你可以按业务线或环境划分镜像空间;RBAC让你能精细控制谁能推、谁能拉、谁只能看;镜像扫描让你在镜像上线前就知道有没有高危漏洞;镜像复制让你能在多机房或多集群之间同步镜像;审计日志让你事后能追溯谁动了什么。这些能力单拎出来都不稀奇,但整合在一个系统里、配置起来还不算太复杂,这就是 Harbor 的价值。
2.3 部署形态的选择:单机还是高可用
部署形态上,我建议先想清楚你的规模。如果只是内部小团队、镜像量不大、对可用性要求没那么苛刻,单机部署完全够用,用 docker-compose 一把起来,维护成本低。但如果你要承载多个集群的镜像拉取、或者镜像仓库挂了会影响生产发布,那就得考虑高可用部署,通常是多实例加共享存储(对象存储或共享文件系统)加外部数据库。
我这里给个实际的判断标准:如果镜像仓库宕机一小时内你能接受、并且有备用方案,单机就行;如果镜像仓库是发布链路的强依赖、宕机就发不了版,那就上高可用。别一上来就追求高可用,那会把部署复杂度拉高好几个档次,小团队维护不过来反而更容易出事。我见过不少团队为了"高可用"搞了一套复杂架构,结果因为没人真正懂,出问题时恢复得比单机还慢。
3. 部署实操:从零把 Harbor 跑起来
3.1 环境准备与前置检查
我以单机 docker-compose 部署为主线讲,这是绝大多数团队起步的方式。前置条件有这么几个:一台 Linux 机器(我习惯用较新的稳定版发行版)、装好 Docker 和 docker-compose、至少 4 核 8G 的配置(镜像多了存储要单独规划)、一个能解析的域名或者至少一个固定 IP。
有几个前置检查特别容易被忽略,我列一下。第一,磁盘空间要单独规划,镜像很吃存储,建议给 Harbor 的数据目录单独挂一块盘,别和系统盘混在一起,否则镜像一多系统盘满了整个机器都受影响。第二,时间同步要确保,Harbor 的 token 认证对时间敏感,机器时间偏差大了会出现莫名其妙的认证失败。第三,端口占用要确认,Harbor 默认用 80 和 443,如果机器上已经有 nginx 占了,要么改 Harbor 的端口,要么把前面的 nginx 停掉。
# 检查端口占用 ss -tlnp | grep -E ':80|:443' # 检查时间同步状态 timedatectl status # 检查磁盘 df -h /data提示:如果你打算用 HTTPS(强烈建议),提前把证书准备好。自签证书也行,但要记得把 CA 分发到所有需要访问 Harbor 的机器上,否则 docker 拉镜像会报证书错误。
3.2 下载与配置 harbor.yml
从官方发布页拿到离线安装包,解压后会看到一个harbor.yml.tmpl模板。复制一份改成harbor.yml,然后重点改这几个地方。hostname填你的域名或 IP,这个值会写进镜像地址里,改起来很麻烦,一开始就要定好。https段配置证书路径,harbor_admin_password设一个强密码,data_volume指向你规划好的数据盘目录,database段如果单机就用内置的 PostgreSQL。
还有一个参数值得单独说:storage_service。默认是本地文件系统,镜像存在 data_volume 下面。如果你后面想扩展到对象存储,这里可以配 s3 或 oss。我的经验是,单机阶段用本地存储最省心,等真到了要多实例高可用的时候再换对象存储,别一开始就上对象存储给自己增加调试成本。
hostname: harbor.example.internal https: port: 443 certificate: /data/certs/harbor.crt private_key: /data/certs/harbor.key harbor_admin_password: YourStrongPassw0rd data_volume: /data/harbor storage_service: filesystem: rootdirectory: /storage配置改完,执行./install.sh,脚本会生成 docker-compose 文件并拉起所有容器。第一次装的时候我建议加--with-trivy把扫描器一起装上,省得后面再补。装完用docker-compose ps看下容器状态,正常情况下应该全是 Up。
3.3 首次登录与基础验证
装完之后浏览器访问你的 hostname,用 admin 和你设的密码登录。第一件事是改掉 admin 的默认密码(如果你在配置文件里设的就是强密码,这步可以跳过,但还是要确认一下)。第二件事是建一个测试项目,比如叫library或test,然后试着推一个镜像上去验证整条链路。
# 登录(注意地址要和 hostname 一致) docker login harbor.example.internal # 给本地镜像打 tag docker tag nginx:latest harbor.example.internal/test/nginx:v1 # 推送 docker push harbor.example.internal/test/nginx:v1推成功之后回到 Web 界面,在项目里能看到这个镜像和它的 tag,说明存储、认证、registry 这条链路是通的。如果推失败,先看报错类型:unauthorized多半是登录或权限问题,certificate是证书问题,connection refused是网络或端口问题。这个分类排查法能帮你快速定位到是哪一层出的问题。
4. 权限体系与项目治理的落地细节
4.1 项目、用户与角色的关系设计
Harbor 的权限模型是"项目为中心"的。镜像归属于项目,用户通过被授予项目角色来获得对项目内镜像的操作权限。角色有几种:项目管理员能管项目配置和成员,开发者能推拉镜像,访客只能拉,受限访客只能拉特定仓库。系统层面还有系统管理员,能管所有项目和用户。
我实际落地时的做法是:按业务线或环境建项目,比如prod-payment、test-payment、prod-order这种命名,一眼能看出归属和环境。然后按团队建用户组,把组授予项目角色,而不是一个个用户去加。这样人员变动时只改组,不用动项目配置。这个习惯能省掉大量后期维护工作,我见过项目成员一个个手动加的,人一多就乱套。
4.2 机器人账号与 CI 集成
CI 流水线推镜像不能用真人账号,得用机器人账号(robot account)。机器人账号是绑定到项目或系统级别的,有独立的 token,权限可以精确到推或拉。给每个 CI 流水线建一个专属的机器人账号,好处是权限最小化、出问题能定位到具体流水线、token 泄露了只影响一个账号。
建机器人账号的时候,权限勾选要克制。只推镜像的流水线就只给 push 权限,不要图省事给全权限。token 生成后只显示一次,记得立刻存到 CI 的密钥管理里。我踩过的坑是:早期图方便用 admin 账号在 CI 里推镜像,后来要审计"谁推了什么"的时候完全查不出来,因为全是 admin。换成机器人账号之后,审计日志里每条推送都能对应到具体流水线,排查问题方便太多。
4.3 配额与垃圾回收策略
镜像越堆越多是必然的,得提前定策略。Harbor 支持项目配额,可以限制单个项目能用的存储量,防止某个项目把磁盘吃满影响所有人。我一般会给测试环境的项目设一个较小的配额,生产环境设大一些,这样测试环境乱推镜像也不会挤占生产空间。
垃圾回收(GC)是另一个必须定期做的事。删掉镜像 tag 之后,底层的 blob 不会立刻释放,得跑 GC 才能回收空间。GC 可以在 Web 界面手动触发,也可以配成定时任务。我的经验是每周跑一次,放在业务低峰期,因为 GC 期间仓库会短暂只读。另外要注意,GC 有"是否删除无 tag 的 manifest"的选项,勾选前想清楚,有些团队依赖无 tag 的镜像做中间层,删了会影响拉取。
| 治理项 | 建议策略 | 说明 |
|---|---|---|
| 项目配额 | 测试环境小、生产环境大 | 防止单项目吃满磁盘 |
| 镜像保留 | 按 tag 数量或时间保留 | 避免历史版本无限堆积 |
| 垃圾回收 | 每周低峰期执行 | 回收已删除镜像的底层数据 |
| 审计日志 | 保留至少 90 天 | 满足事后追溯需求 |
5. 镜像扫描、复制与高可用扩展
5.1 漏洞扫描的配置与解读
Trivy 扫描器装上之后,镜像推上来会自动触发扫描(也可以配成手动)。扫描结果会给出漏洞等级分布:严重、高、中、低。我的用法是在 CI 里加一道卡点:如果镜像有"严重"级漏洞,流水线直接失败,不允许推到生产项目。这个卡点能挡住大部分因为基础镜像过期带来的风险。
但扫描结果不能一刀切。有些漏洞在特定运行环境下根本不可达,全卡死会导致大量误报、拖慢发布。我的做法是分级处理:严重级必须修,高级评估后决定,中低级记录跟踪。另外要定期更新 Trivy 的漏洞库,否则扫出来的结果是过时的。Harbor 的扫描器可以配自动更新,记得打开。
5.2 多环境镜像复制的实践
当你有多个集群或多个机房时,镜像复制就派上用场了。Harbor 支持基于规则的复制:源项目里的镜像可以自动同步到目标 Harbor 实例。典型场景是"测试环境验证通过的镜像,自动同步到生产环境的仓库",或者"总部仓库同步到分支机构仓库"。
配复制规则时要注意触发模式:可以按事件触发(推上来就同步),也可以定时触发。事件触发实时性好但可能同步太频繁,定时触发适合对实时性要求不高的场景。还有过滤规则要配好,别把整个项目全同步过去,按 tag 模式过滤,比如只同步release-*的 tag。我见过没配过滤导致把测试镜像也同步到生产仓库的,虽然不影响运行,但仓库里一堆垃圾镜像很难看。
5.3 从单机到高可用的演进路径
前面说了单机起步,那什么时候该演进到高可用?我的判断是:当镜像仓库成为发布链路的单点、并且团队对停机零容忍时。演进路径一般是:共享存储(对象存储)+ 外部数据库(PostgreSQL 主从)+ 多 Harbor 实例 + 前置负载均衡。这个改造不是一蹴而就的,建议先在测试环境验证整套架构,再动生产。
改造过程中最容易出问题的是存储迁移。从本地文件系统迁到对象存储,需要用 Harbor 自带的迁移工具或者手动同步数据,迁移期间仓库要停写。我的建议是挑一个发布窗口,提前演练一遍迁移流程,把耗时和回滚方案都摸清楚,别在生产上第一次试。
6. 常见问题排查与运维避坑实录
6.1 推送拉取失败的典型排查路径
镜像推拉失败是最常见的问题,我整理了一个排查顺序。先看客户端报错信息,x509开头的是证书问题,unauthorized是认证问题,denied是权限问题,no such host是 DNS 问题。然后确认 docker login 的地址和 harbor.yml 里的 hostname 完全一致,不一致会导致 token 里的 audience 对不上,认证失败。再然后检查证书链,自签证书要把 CA 装到客户端的信任链里,否则 docker 不认。
还有一个很隐蔽的坑:docker 的 insecure-registries 配置。如果你用 HTTP 或者自签证书,需要在客户端的 daemon.json 里把 Harbor 地址加到 insecure-registries,改完要重启 docker。这个配置在每台需要访问 Harbor 的机器上都要做,包括 CI 的构建节点。我踩过一次,本地能推、CI 推不了,查了半天才发现是 CI 节点没配这个。
6.2 存储与数据库的运维要点
存储方面,定期看磁盘使用率是基本功。除了看总量,还要看增长趋势,镜像增长快的时候要提前扩容。本地存储扩容相对简单,加盘挂载就行;对象存储则要注意配额和生命周期策略。另外,备份不能只备份数据库,镜像数据本身也要考虑,虽然镜像可以从构建流水线重新生成,但历史版本丢了会影响回滚能力。
数据库方面,单机内置的 PostgreSQL 够用,但要定期备份。Harbor 的元数据(项目、用户、权限、镜像 tag 信息)都在数据库里,数据库丢了等于仓库配置全丢。备份策略我一般用每天全量加 binlog 增量,保留一周。恢复演练也要做,别备份了从来没恢复过,真出事的时候发现备份是坏的。
6.3 常见问题速查表
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| 推送报 unauthorized | 未登录或 token 过期 | 重新 docker login |
| 推送报 denied | 账号无 push 权限 | 检查项目角色或机器人账号权限 |
| 拉取报证书错误 | CA 未安装或证书过期 | 安装 CA 或更新证书 |
| Web 打不开 | proxy 容器异常或端口冲突 | 查容器状态和端口占用 |
| 扫描一直 pending | 扫描器未启动或队列堵塞 | 检查 trivy 容器和 jobservice 日志 |
| GC 后空间没释放 | 有镜像仍引用 blob | 确认镜像已全删再跑 GC |
| 复制任务失败 | 目标端网络或认证问题 | 检查目标地址连通性和凭据 |
6.4 我踩过的几个真实坑
第一个坑是升级没看 release note。Harbor 跨大版本升级有数据库迁移,有些版本升级前必须先升到中间版本,跳版本升会失败。我建议升级前一定读官方的升级说明,并且在测试环境先升一遍。升级前还要备份数据库和配置文件,出问题能回滚。
第二个坑是日志把磁盘写满。Harbor 的容器日志默认可能无限增长,跑久了把磁盘吃满,然后整个仓库挂掉。解决办法是配 docker 的日志轮转,限制单个日志文件大小和保留数量。这个配置在 daemon.json 里做,改完重启 docker。
第三个坑是机器人账号 token 过期。机器人账号的 token 可以设有效期,设短了安全但容易过期导致 CI 失败,设长了安全风险高。我的折中是设一个较长的有效期,同时在 CI 里做好失败告警,token 快过期时提前轮换。轮换的时候新旧 token 并行一段时间,避免切换瞬间流水线全挂。
7. 我个人的一些使用体会
这套东西我从单机一路用到多实例,最大的感受是:Harbor 的能力很全,但全不等于都要用。一开始别把所有功能都打开,先把镜像存取和权限跑顺,再逐步加扫描、加复制、加高可用。每加一个能力都要配套相应的运维流程,否则功能开了没人管,反而成了负担。
另外一个体会是命名和规范比技术选型更重要。项目怎么命名、tag 怎么打、谁能推哪个环境,这些规范定清楚了,Harbor 用起来就顺;规范不清楚,再好的工具也管不住混乱。我现在的习惯是项目名带环境和业务线、tag 用语义化版本加 git commit 短哈希、生产项目的推送权限只给发布流水线的机器人账号,这几条定下来之后,镜像治理基本就没出过大乱子。
最后分享一个小技巧:Harbor 的 Web 界面里有"审计日志",很多人不用,但它排查问题特别好使。谁在什么时候推了哪个镜像、删了哪个 tag、改了哪个项目配置,全都有记录。有次生产镜像被误删,就是靠审计日志定位到具体操作和时间点,快速恢复了。建议你把它当成日常排查的第一入口,比翻容器日志快得多。