
先抛个问题给正在搭 CI/CD 的各位你的构建流水线跑得再快镜像产出后往哪放几十个微服务、几百个版本的镜像、Helm Chart、SBOM 清单如果制品管理这块没提前选好后面投产就是灾难现场。制品管理工具这件事我这两年被问得最多的是两个名字Harbor 和 Hadess。Harbor 是 CNCF 顶级项目企业级制品平台从镜像仓库、漏洞扫描、签名认证到多站点复制全部覆盖Hadess 则是轻量化制品库的代表主打小资源、快部署、低维护成本适合中小团队和边缘场景。这篇文章我想把二者的定位差异、核心功能对比、部署实操和踩坑经历一次性讲清楚重点覆盖新手最关心的 Harbor 安装与配置、Docker Compose 快速搭建私有镜像仓库以及很多人被问懵的“Docker 部署的 Harbor 如何升级 nginx”。无论你是在选型阶段还是已经在维护一套 Harbor这篇都值得先收藏再慢慢看。1. 先搞清楚制品管理工具到底在解决什么问题1.1 制品的范围不止镜像这一篓子事很多人以为制品管理就是私有镜像仓库其实这只是冰山一角。我见过不少团队镜像用 Harbor 管得规规矩矩但 Helm Chart 放在同事的个人网盘里前端构建产物传到对象存储某个叫“final_final_v3”的目录里模型训练权重甚至靠 U 盘拷贝。等到版本回溯或者事故排查的时候那个酸爽谁经历谁知道。制品Artifact这个概念跟研发交付物基本是一回事容器镜像、OCI 制品、Helm Chart、RPM/DEB 安装包、jar 包、前端静态包甚至镜像签名和 SBOM 清单都属于制品。一个合格的制品管理工具应该做到版本可追溯、权限可控制、内容可校验、空间可回收最好还能配合流水线做自动化清扫。哪一环缺失后面都是运维在替你填坑。我经常举一个生活化类比制品库就是研发团队的仓库。Harbor 是一个自带安保、库存台账、温控分区和多地分仓的现代化仓储中心Hadess 则像一个开在实验室门口的小货架东西好放好拿装不了太多货但胜在轻便。没有谁的架构绝对正确只有你的团队规模更适合哪一套。1.2 Harbor 和 Hadess两个完全不同的解题思路Harbor 最早起源于 2014 年前后由原 VMware 中国研发团队发起之后进入 CNCF 并在 2020 年成为毕业项目这是目前制品管理领域含金量最高的一档身份。Harbor 的功能覆盖很长私有镜像仓库、项目级多租户 RBAC、漏洞扫描、镜像签名、复制与代理缓存、垃圾回收、存储配额、审计日志。部署形态支持 Docker Compose 和 Kubernetes Helm Chart还可以切外部 PostgreSQL、Redis、S3 对象存储来支撑高可用。Hadess 这边社区资料相对少一些但这正是它的定位不想让你在制品平台上花太多精力。它通常只需要一个容器或者一套极简的 Compose 栈资源占用可以压到一两百兆内存级别提供镜像推送、拉取、Web UI 浏览、项目空间隔离这些基础能力。它解决的是“我需要一个内网能放镜像的地方”而不是“我需要一个制品治理平台”。如果你拿到两款工具的官网介绍第一反应一定是 Harbor 功能列表长得像天书。这是正常的Harbor 的复杂度来自它面向的是有审计、合规、多环境、多团队诉求的企业场景。Hadess 的简单也真实它面向的是“少即是多”的工程场景。所以选型的第一步不是比参数而是先回答一个问题你的制品管理瓶颈到底在“放得下”还是在“管得住”1.3 一张对比表帮你看清差异重点我把自己实测下来两个方向比较有价值的差异点整理成了一个表格对比维度HarborHadess轻量制品库定位企业级制品管理平台轻量化制品存储与分发部署复杂度中高组件多支持 Docker Compose / Helm低单容器或极简 Compose资源占用建议 4C/8G 起步开启扫描还要更高通常 1C/1G 以内可跑镜像规范支持 Docker V2 / OCI含复制、代理缓存核心支持 Docker V2 / OCI 的推拉制品类型镜像、Helm Chart、OCI 制品、CVE 报告等一般以容器镜像为主需看具体版本权限体系项目级 RBAC、机器人账号、LDAP/AD/OIDC基础项目隔离与账号管理安全能力Trivy 漏洞扫描、Notary 镜像签名、配额通常不内置扫描需配合外部工具复制分发多级复制、跨地域同步、代理缓存一般不支持或仅支持单上游代理运维成本需要关注版本升级、备份、GC、存储水位简单升级基本等于换镜像适用规模多团队、多环境、合规敏感场景小团队、内网、边缘、工具链辅助这里要专门提醒一句Hadess 的能力边界取决于你选的具体版本和社区维护状态表格里的“一般、通常”是基于轻量制品库的常见能力去判断的。真到决策环节拿官方 README 和文档逐条核对比看任何对比博客都靠谱。2. Harbor 安装与配置Docker Compose 快速搭建私有镜像仓库2.1 Harbor 下载离线包还是在线包怎么选Harbor 官方提供了两种安装包离线离线安装包offline installer和在线安装包online installer。我个人建议直接选离线包。在线包虽然体积小但执行安装脚本时会现场从镜像仓库拉取 Harbor 全部组件镜像一旦网络抖动或者源仓库慢整个安装流程会出现各种莫名其妙的 Docker pull timeout。离线安装包把所有组件镜像打包在 tgz 里执行脚本时只需要本地加载环境越受控越稳定。下载时记得去 Harbor 官方 GitHub 项目的 Releases 页面找harbor-offline-installer-v2.x.x.tgz这个文件旁边一般都有对应的 sha256 校验值下完先做一次完整性校验防止文件损坏。这一步看起来多余但在大版本升级时如果用了坏包轻则 prepare 失败重则把 config 目录改坏那时候就不是浪费几分钟的事了。cd /data wget https://github.com/goharbor/harbor/releases/download/v2.11.1/harbor-offline-installer-v2.11.1.tgz sha256sum harbor-offline-installer-v2.11.1.tgz tar xzvf harbor-offline-installer-v2.11.1.tgz cd harbor解压之后你会看到一个标准目录harbor.yml.tmpl是配置模板install.sh是安装脚本prepare负责生成配置和编排文件common 目录里放着各组件的基础配置。如果你在内网环境部署最简单的方式就是在外网拿机器下好离线包再通过内网文件通道传进去整个过程不需要依赖任何外部镜像源。2.2 环境规划harbor.yml 到底要改哪几处硬件方面我自己的经验是纯粹跑一个编译产物缓存2C/4G 勉强能用如果还要开 Trivy 漏洞扫描建议至少 4C/8G。Harbor 的镜像数据存放在 data_volume 目录下这个目录一定要规划在独立磁盘或独立逻辑卷上因为镜像数据增长远比你想的快。我见过有团队把 Harbor 装在系统盘上跑了大半年磁盘 100% 直接导致 registry 容器频繁重启最后还是靠迁移数据卷才救回来。安装之前先复制配置文件模板cp harbor.yml.tmpl harbor.yml然后打开 harbor.yml重点看这几项hostname: registry.example.com http: port: 80 https: port: 443 certificate: /data/certs/registry.example.com.crt private_key: /data/certs/registry.example.com.key harbor_admin_password: YourStrongPassword database: password: rootpass123 data_volume: /data/harbor trivy: enabled: truehostname是重中之重它会被写入镜像仓库地址和 UI 的回调地址。你以后 docker login 的命令会是docker login registry.example.com所以这个域名要在部署前就定好内部 DNS 或 /etc/hosts 都要指到这台机器。很多人一开始随手填了个 IP后面企业要上 HTTPS 证书或对外暴露域名时会把自己坑进一个很大的配置深坑我后面专门讲。harbor_admin_password在 2.x 版本里不再是网上教程常写的 Harbor12345而是模板里自动生成的随机密码字符串一定要在启动前改成强密码并妥善保存到密码管理器里。database.password是 Harbor 内置 PostgreSQL 的管理密码同样只会在初次 prepare 时生效后改无效。data_volume建议放到数据盘比如 /data/harbor。trivy.enabled想开启扫描就设 true不需要就先关掉能省不少资源。2.3 执行安装./prepare 和 ./install.sh 分别干了什么Harbor 安装过程分两步先./prepare再./install.sh。prepare 这一步的核心工作是根据 harbor.yml 生成各组件的配置文件、证书文件和 docker-compose.yml它其实是一个渲染动作。如果你修改了 harbor.yml必须重新执行 prepare再重启服务配置才会生效。install.sh 负责加载离线镜像包里的全部组件镜像然后调用 Docker Compose 启动整个堆栈。sudo ./prepare sudo ./install.sh想要开启扫描可以用sudo ./install.sh --with-trivy想支持镜像签名加--with-notary。我建议第一次就按需把 trivy 带上后面再想加虽然不用重装 Harbor但 prepare 和组件配置都要重新走一遍麻烦不少。安装完成后Harbor 会启动大约 8 个左右的核心服务可以通过这个命令确认状态docker compose ps看到所有容器都是 Up 状态后浏览器访问http://registry.example.com用 admin 账号登录。接下来做一次完整的推拉验证确保整条链路是通的docker tag nginx:latest registry.example.com/library/nginx:1.0 docker login registry.example.com docker push registry.example.com/library/nginx:1.0 docker pull registry.example.com/library/nginx:1.0这里有一个非常常见的坑直接执行 docker push 会报http: server gave HTTP response to HTTPS client。原因是你走的是 HTTP 端口Docker 客户端默认要求仓库用 HTTPS。如果你就是内网环境不想上证书需要在每台客户端的/etc/docker/daemon.json里把insecure-registries指到 Harbor 地址然后重启 Docker。更正规的做法是上一张正式或内部 CA 签发的证书配置到 Harbor 和客户端双向信任这个我们在后面升级 nginx 的章节还会谈到。2.4 数据持久化与备份思路别等磁盘满再后悔Harbor 的数据卷里装着几类关键数据registry 目录是真正的镜像存储database 目录是内置 PostgreSQL 数据redis 和 secret 目录管理缓存和内部密钥。备份方案我建议分两条线第一条线是容器层面的定期备份用 docker exec 对 PostgreSQL 做逻辑导出第二条线是文件层面的备份重点是 registry 和 database。docker exec harbor-db pg_dump -U postgres -F custom registry harbor_registry.dumprestore 时同样通过 psql 或 pg_restore 恢复到同版本数据库。我这里要特别强调不要简单粗暴地直接复制整个 data_volume 目录来当热备份尤其不能在 Harbor 运行状态下直接对 database 目录做文件拷贝PostgreSQL 对这种操作非常敏感极容易得到一份损坏的备份。正确做法是先停服务再拷贝或者用数据库自身的备份机制。还有一点Harbor 的 secret 目录不要让它在容器重建后丢失。如果 secret 大量变更部分组件的 token 校验会失败表现就是登录成功但 API 请求一直 401。我习惯把整个 data_volume 在升级前打一个快照或 tar 包热备冷备都做虽然占点时间但换来了升级时的安心。3. Docker 部署的 Harbor 如何升级 nginx一个高频问题的完整解法3.1 为什么大家都在问 nginx 升级Harbor 对外暴露端口时承担反代职责的是内置的 nginx 容器。UI 页面、API、registry 的 /v2 接口全部经过这层 nginx 转发到 portal、core、registry 等上游服务。安全扫描软件扫内网资产时只要探测到对外开放的 80/443 端口就会把它 banner 里的 nginx 版本号拿去和 CVE 库比对。很多团队一开扫描报告第一条高危就是“Harbor 内置 nginx 版本过旧”于是四处找升级方案。这里有个很容易踩的误区觉得进了容器里跑几条apt upgrade就能解决。容器是临时文件系统升级的软件包在容器重建后会全部还原等于白忙。更诡异的是Harbor 官方发布新版本时确实会更新 nginx 版本但如果你的 Harbor 版本不能随意升级或者升级窗口被业务卡住就需要单独处理 nginx。我先把结论摆在这里官方支持且最推荐的方式永远是升级整个 Harbor 版本单独升级 nginx 属于社区实践可以临时弥补安全窗口但不要长期指望它。3.2 升级 nginx 的三条可行路径第一条路升级整个 Harbor。官方的 install.sh 支持原地升级离线包解压到同一目录后先备份数据卷再执行sudo ./install.sh安装脚本识别到已有实例后会自动走升级逻辑。这是最省心、最稳妥的路径nginx 版本会随新版 Harbor 一起更新各组件的兼容性由官方保证。第二条路基于 Harbor 现有配置自己构建一个新的 nginx 镜像。核心思路是把容器内的 nginx 配置原封不动地取出来换一个较新的 nginx 基础镜像重新构建再替换 docker-compose.yml 里 nginx 服务的镜像名。先导出配置docker cp nginx-container:/etc/nginx /data/nginx-backup/conf然后写一个最小 DockerfileFROM nginx:1.27-alpine COPY conf/ /etc/nginx/构建并打上自定义标签docker build -t custom/harbor-nginx:1.27 .修改 Harbor 生成的 docker-compose.yml把 nginx 服务原来的镜像地址改成custom/harbor-nginx:1.27然后重建 nginx 容器。这里我警告一下Harbor 的 nginx 配置不是普通网站的 server 块里面包含了/api/、/v2/、/service/等大量 location 转发逻辑直接从网上找一份通用 nginx 配置来替换一定会翻车。配置目录里的内容结构尽量不要动只通过更新基础镜像来修复版本漏洞。第三条路用外部反代终结 TLS把 Harbor 内置 nginx 收敛到内网监听。很多企业本来就有统一的 LVS、Nginx、Ingress 或云负载均衡在前面兜流量那么你完全可以让外网只访问到外部反代由外部反代配置 HTTPS 证书然后转发到 Harbor 的 HTTP 端口。Harbor 内置 nginx 的版本即使旧一点也不直接暴露公网安全扫描的暴露面一下子就变小了。这条路对网络架构改造有要求但对已经有多层代理的团队来说最干净。3.3 升级后常见故障排查速查表不管是走官方升级还是自定义镜像都有可能出现服务异常。下面这些症状我基本都遇到过整理成速查表方便你排障的时候直接对号入座。症状常见原因排查动作打开 UI 直接 502内部上游 core/portal 未就绪或自定义 nginx 后容器间网络别名变了先确认docker compose ps再看 nginx 日志docker compose logs nginxdocker login / push 报 404nginx 转发/v2/的 location 配置丢失或损坏对照配置备份确认proxy_pass路径和上游地址正确UI 能打开接口一直 401secret 不一致导致 token 服务验签失败不要乱动 secret 目录回滚到备份或重新执行 prepare页面能登录但样式全乱了前端静态资源路径没匹配到 portal 服务检查 nginx 中/与/portal/的转发规则HTTPS 证书不生效HTTPS 配置引用的证书路径在自定义镜像里没有挂载检查 docker-compose 中 nginx 的 volume 挂载是否保留原路径镜像推拉正常但扫描功能失效trivy adapter 与核心之间网络或版本对不上查看 trivy 容器日志确认版本与主版本一致排障有一个基本原则先看容器状态再看组件日志最后才动配置。不要一上来就怀疑是 nginx 配置被改坏很多时候只是 core 容器还没就绪、PostgreSQL 连接数打满了这些初级问题。3.4 配套排查镜像推拉报错先查这五个位置镜像推拉报错的排查我要单独多写一些。因为这类问题占了我日常技术支持里的大头而且绝大多数不是 Harbor 本身出了问题。第一处是客户端的 daemon.json。insecure-registries配没配、证书有没有加进系统信任库决定了 Docker 客户端和 Harbor 之间的会话方式。第二处是 DNS 和 hosts。你在公司内网访问 registry.example.com如果 DNS 没有解析到 Harbor 机器那报错必然络绎不绝。第三处是防火墙和负载均衡策略。端口通不通、四层还是七层转发、后端有没有打开长连接这些都要逐个验证。第四处是磁盘空间。registry 写入镜像时磁盘满了Harbor 会返回很模糊的 500 错误很多人下意识以为是网络问题实际 df -h 一看就明白了。第五处才是 Harbor 自身的日志docker compose logs -f registry core 分别查看仓库组件和核心组件的实时输出。我把五个位置按概率排序daemon.json 配置问题 DNS 解析问题 磁盘空间不足 防火墙策略 Harbor 自身异常。你照着这个顺序排查通常能在五分钟内定位问题而不是在 Harbor 配置里反复折腾。4. Harbor 日常运维从“能跑”到“好用”4.1 镜像保留策略与垃圾回收不然磁盘早晚爆Harbor 安装完成能推拉镜像只算“能跑”。日常运维真正要面对的是镜像版本越来越多、磁盘空间曲线越来越不可控。很多团队的问题不是没空间而是不知道怎么回收空间。Harbor 的镜像清理靠两层配合第一层是保留策略在项目页面的“保留”标签里创建规则比如“保留最近 30 个版本”或“保留最近 7 天的制品”第二层是垃圾回收在“管理”页面的“垃圾清理”里执行。保留策略先决定哪些镜像可以被清垃圾回收再把镜像存储里没有被引用、被标记为可回收的 blob 真正删除。我的建议是给每个项目都建立保留规则再设置每周执行一次定时垃圾回收。不要从安装那天起就不管等到磁盘 90% 才临时清理那时候一次 GC 可能要跑几个小时业务发布还要暂停代价极大。另外 GC 执行前如果磁盘实在紧张可以先用 docker exec 查看 registry 日志确认当前没有推拉任务避免在流量高峰期跑 GC 影响性能。4.2 制品安全漏洞扫描与镜像签名Harbor 的漏洞扫描默认用 Trivy 作为扫描引擎它会拉取漏洞数据库对仓库里的镜像逐层解析依赖输出 CVE 列表和修复建议。开启扫描后在镜像仓库页面点一下扫描按钮就能看到每个镜像的风险等级。扫描数据库需要定期更新如果你所在环境的网络受限需要在管理页面手动上传离线漏洞库文件或者配置内部可达的源。镜像签名我多提一句Harbor 支持用 Notary 对镜像做内容签名签名后的镜像带有完整性和来源校验推到生产集群前可以强制校验签名。这个功能在合规要求高、需要防镜像篡改的环境里很有用但对大多数内网团队来说属于“锦上添花”而非“雪中送炭”。如果团队就十个人先别给自己上太高配置签名机制的密钥管理本身也是一笔运维成本。4.3 跨环境复制与代理缓存不止是仓库Harbor 的复制功能是我认为是它比起轻量制品库最有价值的分水岭之一。你可以创建一条复制规则把源项目镜像周期性地复制到另一个 Harbor 实例或兼容 registry典型场景是测试环境到生产环境的分发以及总部到分支机构的同步。复制方向分推模式和拉模式支持按镜像名和 tag 过滤断点续传和校验机制也比较成熟。代理缓存是另一个日常“神器”。团队经常要拉取公共上游镜像如果每个人都从外网拉带宽和效率都很难看。在 Harbor 里创建一个代理缓存项目把它指向 Docker Hub 或某个内部的上游仓库团队统一从这个代理项目拉公共镜像第一次拉取后缓存到本地后续完全走内网。这个能力在多次构建、多节点拉镜像的场景下节省的流量和等待时间非常可观。4.4 多实例高可用与升级节奏单机 Docker Compose 部署的 Harbor 已经能满足中小团队需求但如果你把它当作生产基础设施就要考虑高可用。Harbor 官方支持把内置的 PostgreSQL、Redis、对象存储切换为外部服务这样任何一个实例挂了只要 LB 把流量切走服务还能继续用。镜像数据可以放到 S3 或兼容对象存储上多实例共享同一份数据层。升级节奏上我的经验是不要盲目追新也不要长期停在旧版本。建议每季度评估一次 Harbor 版本发布情况重要安全更新出来后先在测试环境走一遍 prepare 和迁移测试再排生产窗口升级。所有升级都要先备份数据卷最好同时对核心目录做一次快照。升级最忌讳的就是直接拿生产库跑新版本 install.sh一旦数据库 schema 迁移失败回滚会很痛苦。5. 回到选型Harbor 还是 Hadess我的建议5.1 什么情况闭眼选 Harbor如果团队处在下面这些场景我的建议非常直接不用犹豫直接上 Harbor。第一类是 K8s 环境为主、微服务数量超过 20 的团队镜像和 Helm Chart 都需要集中管理Harbor 的一站式能力能把制品链路打通第二类是多人多角色协作的团队需要项目隔离、细粒度权限、机器人和 LDAP 对接Harbor 的用户体系明显更成熟第三类是有合规和审计要求的场景需要镜像签名、漏洞扫描、操作审计日志这个基本是 Harbor 的看家本领第四类是多环境多中心团队需要跨地域复制和代理缓存Harbor 的复制引擎能把分发这件事变成配置而非脚本。一句话总结当你的瓶颈是“治理”不是“存储”就选 Harbor。它的复杂度换来的是制品的生命周期可管可控这个账在规模化之后非常划算。5.2 什么场景可以考虑 Hadess如果你打开需求文档发现里面只有“内网有个镜像仓库给开发用”这一条那么 Hadess 这类轻量制品库是更务实的选项。具体来说百人以下小团队制品量不大没有外部审计需求边缘计算和嵌入式场景机器资源紧张需要尽可能少地占用 CPU 和内存开发自测环境只想快速起一个本地镜像缓存完全没必要上全家桶运维人力有限没法维护 Harbor 这种多组件服务的生命周期。在这些场景里Hadess 的轻量部署、低资源占用、低升级成本是实打实的优势。但你也要接受它的边界扫描、签名、复制等高级能力可能缺失或依赖外部工具。如果选 Hadess我建议把镜像推拉链路做好监控并用 skopeo、crane 这类工具做底层镜像的备份和迁移防备它某些高级能力不到位时你还有手动兜底的手段。5.3 迁移与共存这不是一个二选一的问题很多团队一种误解以为选型必须在 Harbor 和 Hadess 之间二选一其实完全可以共存。比如日常开发使用的镜像缓存库用 Hadess跑得轻快、部署简单生产环境用 Harbor做安全扫描、复制分发和正式交付。两端通过复制或手动镜像搬运工具打通开发环境的东西验证通过后再同步到生产 Harbor。如果要从 Hadess 迁到 Harbor也可以做得平滑。先用 skopeo 或 crane 把存量镜像从旧仓库批量导出、推送进 Harbor然后让流水线把推送地址改为 Harbor旧仓库保留一段时间作为只读备份。等确认新链路稳定再逐步回收旧的制品库。Harbor 本身也支持把老仓库作为复制源通过一条复制规则把镜像带到 Harbor这种方式的优点是不需要离线导出脚本复制任务会自动起来跑。5.4 我踩过的坑提前给你避掉最后分享几条我实际踩过的教训每一条要么花过时间要么花过存储。第一个坑是 Harbor 装完才发现 hostname 填错了。Harbor 的 hostname 一旦初始化后面改起来相当麻烦不只是改配置文件那么简单还牵扯到已推送镜像的 tag、机器人账号 token、复制规则的 endpoint。所以我强烈建议部署前先确定好对外域名哪怕是先用registry.local这种内网域名也比填 IP 强。第二个坑是管理员密码没改被内部共享出去后来权限体系形同虚设。Harbor 装完第一件事除了登录就是把 admin 密码改成强密码并记录到密钥管理平台同时立刻创建几个普通用户账号日常使用不要都拿 admin 去碰。第三个坑是镜像保留策略没有初始化导致磁盘连续使用率报警。Harbor 安装完成后的默认状态不会自动清理任何镜像你必须主动建立保留规则和 GC 定时任务这应该写进安装后的检查清单里。第四个坑是升级时没有备份一键 install.sh 跑完后发现客户端 401 频繁。Harbor 升级前务必备份整个 data_volume至少把 database 和 secret 目录完整复制一份。宁可备份多了占地方也不能在升级失败时无路可退。按照我的个人习惯每次新的 Harbor 环境跑起来都会先做一次完整的推拉验证再建立一个最小的保留规则并手动跑一次 GC确认整个链路顺畅才收工。这几个动作加起来十分钟但能在后续几个月里帮你省下大量救火时间。