
做容器化落地之后镜像仓库是我最先着手解决的基建。最初图省事直接用Docker官方Registry跑两分钟就能起来但真正用起来才发现问题一堆没有项目隔离权限控制等于没有团队里谁都能删镜像出了事连基本审计都查不到。后来换到Harbor这些问题才算真正解决。这篇文章我就完整记录一下Harbor的安装与使用过程从选型思路、环境准备、离线部署到日常运维中真正会踩的坑一次性讲清楚。想自建私有镜像仓库的可以直接照着抄。1. 为什么我的镜像仓库选了Harbor1.1 裸Registry的痛点一句话说不完先说说我最早用官方Registry的感受。单纯推送拉取镜像它确实够用Docker客户端原生支持部署也轻。但只要你把它放进真实团队环境短板马上就暴露了。一个最直接的痛点是权限。官方的Registry没有用户体系没有角色概念默认情况下只要能访问到这个仓库地址就能对镜像做任意操作。我当时遇到过一个很尴尬的情况某个测试镜像被误删全组排查了半天最后发现是有人顺手清理磁盘时把整个仓库目录删了。这种事反复出现之后我意识到镜像仓库不能仅靠文件和目录管理它需要真正的“账号 角色 项目”模型。第二个痛点是可视化和审计。官方的Registry没有像样的Web界面查一个镜像的tag列表都得写脚本调API。谁在什么时间推了什么镜像、删了什么镜像完全没有记录。出了问题只能靠猜这对生产环境是致命的。第三个痛点是数据管理。镜像删掉之后底层的存储并不会自动释放还需要手动跑垃圾回收。官方Registry的GC流程繁琐日常维护成本很高。再加上多集群同步、镜像漏洞扫描这类需求官方Registry更是完全没有原生方案。于是我从一开始就确定需要的是一个企业级的镜像仓库管理平台而不是一个单纯存储镜像的工具。1.2 Harbor补上的关键能力Harbor走的是“基于开源Registry再封装”的路线底层依旧是标准的Registry实现兼容所有Docker命令和OCI镜像规范但在此之上把镜像仓库真正做成了平台。具体到功能上我最看重的是这几个项目级隔离每个项目是独立的命名空间镜像名以项目名为前缀项目可以设置公开或私有。RBAC权限模型系统管理员、项目管理员、开发者、访客四级角色粒度足够日常使用。审计日志对用户操作有记录镜像是谁推的、谁删的都能追溯。复制功能支持跨Harbor实例同步镜像主备机房分发不用再自己写脚本。漏洞扫描推送镜像后自动触发扫描能及时发现基础镜像里的安全漏洞。配额与保留策略限制项目存储空间按规则自动清理旧镜像避免仓库被撑爆。机器人账号和Webhook给CI/CD系统提供自动化入口推送事件能主动通知到外部系统。这些功能如果全部自己造轮子工作量非常大。Harbor把这些能力做成了开箱即用的功能而且它是开源项目社区活跃版本迭代也快。安装配置一次之后日常使用基本围绕Web界面和Docker命令展开运维成本是我能接受的。1.3 认识Harbor的组成与运行方式不了解Harbor的架构安装完之后一旦出问题会很难排查。我第一次部署时就是只知道“安装成功”结果遇到故障完全无从下手。Harbor从部署形态看是一组容器化的微服务通过Docker Compose编排启动。它的核心组件包括以下几部分Nginx反向代理所有外部请求的入口负责TLS终结和请求转发也对外暴露80和443端口。CoreHarbor的核心业务服务处理用户认证、项目管理、API请求等主流程逻辑。Registry底层的镜像仓库服务负责镜像的存储与分发承载实际推拉请求。Jobservice异步任务执行器镜像复制、垃圾回收、扫描等耗时任务都交给它处理。PostgreSQL存储用户、项目、复制规则、审计日志等元数据。Redis缓存和任务队列。PortalWeb前端界面给用户操作和系统管理提供页面入口。可选组件漏洞扫描器、镜像签名服务等按需启用。理解了这个组成后续定位问题会快很多。比如页面打不开先看Nginx推送成功但复制任务没执行要查Jobservice用户登录不了要看Core和数据库。安装过程本质上就是把这一套组件通过脚本拉起来调通它们之间的依赖关系。2. 安装前先做规划环境、包与目录2.1 硬件和系统要求Harbor对机器配置不算高但也不能太寒酸。官方建议是至少2核CPU、4GB内存我实际部署的经验是内存绝对不要低于4GB。因为PostgreSQL和Redis本身就吃内存再加上镜像推送时的并发连接2GB的内存我试过经常出现服务假死、Jobservice任务堆积的情况。磁盘容量的规划更要认真对待。Harbor本身只占几个GB的空间但镜像数据会不断增长。我一般建议镜像存储盘至少单独准备一块容量按“未来一年镜像体积估算 30%余量”来规划。一个团队每天构建几十个镜像几个月下来几十GB很正常。如果你打算长期使用直接给100GB以上的独立数据盘是稳妥的。操作系统方面主流的Linux发行版都可以跑。我平时用的是Debian系和RedHat系Harbor并没有绑定某个特定系统只要满足Docker环境即可。安装前用uname -a确认一下系统位数64位是必须的。2.2 检查依赖项与端口Harbor的安装脚本依赖Docker和Docker Compose安装前先把这两个环境确认好。docker version docker compose versionDocker版本建议在20.10以上太老的版本对容器网络和资源限制支持不完善容易在安装过程中出现莫名问题。Docker Compose如果还是v1也就是docker-compose命令也建议换成v2插件版本Harbor新版本的安装脚本对v2的支持更顺畅。端口方面Harbor默认使用80和443分别对应HTTP和HTTPS入口。安装前要检查这两个端口没有被其他服务占用ss -tlnp | grep -E :(80|443)\s如果被占了要么释放端口要么在harbor.yml里改成其他端口。这里有一个容易忽略的细节客户端执行docker login时如果走的是非标准端口要写成reg.example.local:8080这种格式而且要确认这个端口在整个网络链路中都是放行的。防火墙和安全组策略都要提前查一遍不然很可能出现“本机能访问别的机器连不上”的情况。另外系统时间同步也要提前确认。容器和证书机制都依赖时间尤其是后面用HTTPS自签证书时客户端和服务器时间偏差过大会直接导致证书校验失败。用date看一下当前时间建议把系统时间同步服务开好。2.3 离线包还是在线包我推荐离线Harbor官方提供两种安装包在线安装包和离线安装包。在线安装包体积小安装脚本执行时会从镜像源实时拉取Harbor各个组件的镜像。这种方式适合机器能够联网、且网络状况稳定的场景。但它有一个隐藏风险如果镜像源或网络出现波动安装会中途失败而且反复重试会很耽误时间。离线安装包就不一样了它把Harbor所有组件的镜像预先打包在一个压缩文件里安装时直接从本地加载整个过程不依赖外网。我推荐在内网环境使用离线包理由很直接首先这类私有镜像仓库通常部署在隔离网络内离线包天然适配这种部署环境其次离线包排除了安装过程中的网络不确定性出问题只会在本机环境排查范围小最后离线包安装之后运行时也不会因为镜像源变化出现拉取失败的问题。离线包的缺点是文件体积大下载时稍微费点时间但对一次安装来说完全可以接受。下载渠道就是Harbor官方发布页面找到对应版本号的harbor-offline-installer-v2.x.x.tgz文件即可。版本选择上一般建议用最新的稳定版本但如果你后续有基于旧版本API做对接也完全可以用旧版本功能核心差异不大。3. 离线安装Harbor的完整实操3.1 解压安装包并认识目录结构拿到离线安装包后先找个干净的目录放它然后解压tar -xzvf harbor-offline-installer-v2.x.x.tgz cd harbor解压之后目录里会出现以下关键文件harbor.yml.tmpl配置文件模板安装前必须复制成harbor.yml并修改。install.sh安装脚本负责加载镜像、生成编排文件并启动服务。harbor.v2.x.x.tar.gz离线镜像压缩包里面是Harbor所有组件的镜像。common.sh公共脚本安装脚本会调用它做环境检查和辅助操作。这里必须强调一件事千万不要直接改harbor.yml.tmpl而是先复制成自己的配置文件再改。cp harbor.yml.tmpl harbor.yml因为模板文件是后续升级和重置时的参考基准保留了原始模板出问题时方便对比哪些配置被改动过。3.2 配置harbor.yml这些字段必须认真填Harbor安装的核心在于配置文件。打开harbor.yml后重点修改以下几项。hostname: reg.example.local http: port: 80 https: port: 443 certificate: /data/cert/server.crt private_key: /data/cert/server.key harbor_admin_password: Harbor12345 database: password: root123 data_volume: /data/harbor先解释hostname这个字段。它不只是一个标识而是所有客户端访问Harbor时使用的地址。客户端执行docker login reg.example.localDNS解析和证书校验都会围绕这个hostname进行。这就意味着第一次安装前务必要把hostname定死我踩过改hostname的坑改完之后客户端本地的Docker证书目录和镜像tag前缀全部要跟着改非常麻烦。所以实际部署时要么用正式域名要么用你确定长期不变的内部域名。接下来是HTTP和HTTPS。如果你的环境允许走HTTPS建议直接配置证书因为Docker客户端默认对非HTTPS仓库有安全限制。证书可以来自正规机构也可以用自签证书区别在于自签证书需要额外让每台客户端信任CA。如果暂时没有证书可以先用HTTP模式之后在客户端的Docker配置里加insecure-registries但不推荐生产环境长期这么干。harbor_admin_password是系统管理员的初始密码。默认值是Harbor12345安装后必须第一时间登录后台改掉。database里的password是PostgreSQL数据库的密码同样要改成强密码它不会在安装后自动变动。data_volume决定镜像和数据库文件的存放位置。强烈建议把这一项指向独立的数据盘挂载目录不要放在系统盘根目录下。镜像数据增长很快如果和系统共用磁盘很容易把整个机器磁盘撑满导致系统服务都跟着受影响。配置保存后install.sh会读取这些配置生成最终的Docker Compose文件。注意如果https.certificate和private_key字段填了路径安装前必须确认这两个文件真实存在否则脚本会报错退出。3.3 执行install.sh脚本到底做了什么配置完成后执行安装sudo ./install.sh脚本会做几件事。第一步是检查环境包括Docker和Docker Compose是否可用。第二步是加载离线镜像包里的镜像这一步会花几分钟时间取决于磁盘读取速度。第三步是根据harbor.yml生成docker-compose.yml并启动全部容器。如果你在配置中启用了漏洞扫描器之类的可选组件脚本还会额外启动对应的服务容器。安装过程中会把每个服务的启动状态打印出来看到Successfully之类的输出就说明启动完成。这一步如果出错最常见的原因就是配置文件格式有问题YAML缩进不对或者端口被占用回头检查并修复后重新执行即可。脚本执行完之后并不会自动初始化admin密码而是使用你配置里写的初始密码。另外脚本执行一次之后如果以后改了配置再执行它会按照现有数据卷重新拉起服务不会清掉已有的镜像数据这一点放心。3.4 验证部署从命令行到浏览器安装完成后先确认所有容器都在正常运行docker compose ps正常情况下能看到harbor-core、harbor-registry、harbor-db、harbor-redis、harbor-portal、harbor-jobservice、nginx、harbor-log这些容器状态是Up健康检查处应该显示healthy。然后在浏览器里打开你配置的地址比如https://reg.example.local。第一次访问如果浏览器提示证书不受信任这是正常的因为证书不在浏览器信任列表里。自签证书环境需要手动导入CA证书或者临时跳过检查。用admin账号和初始密码登录后能在首页看到系统状态、存储使用情况确认Harbor运行正常安装就算完成了。接下来才是真正有含金量的部分怎么把镜像推上去、怎么管理权限、怎么让它自动清理和复制。4. Harbor的核心使用场景从推镜像到自动化4.1 创建项目并完成第一次镜像推送Harbor里所有镜像都归属于某个项目项目就是命名空间也是权限边界。登录Web UI后在项目页面新建一个项目例如demo。创建时可以设置是否公开公开项目不登录也能拉取镜像适合存放通用基础镜像私有项目适合业务镜像和部署产物。本地推送镜像前先要把镜像的tag重新打上Harbor地址前缀这一步骤是刚接触Harbor时最容易出错的点。Docker镜像的完整名称是“仓库地址/项目名/镜像名:标签”而很多本地镜像的tag直接叫nginx:latest缺少了仓库地址和项目名这两个前缀。标准流程是这样的docker tag nginx:latest reg.example.local/demo/nginx:v1 docker login reg.example.local docker push reg.example.local/demo/nginx:v1执行docker login时输入用户名和密码。如果走的是HTTPS且证书可信这一步会顺利通过如果走HTTP会提示不安全的注册表需要提前在客户端Docker的daemon.json里配置insecure-registries。{ insecure-registries: [reg.example.local] }改完这个文件需要重启Docker服务才能生效。拉取镜像的方向正好相反docker pull reg.example.local/demo/nginx:v1无论推还是拉只要镜像的tag里带了完整的前缀客户端就能定位到正确的仓库和项目。这一步通了后续流水线接入就有基础了。4.2 用户、权限和机器人账号怎么配合镜像推拉跑通后下一步就是权限分配。Harbor的权限模型分两层系统级和项目级。系统级角色主要就是系统管理员拥有所有权限包括用户管理、系统配置、垃圾回收等。项目级角色有项目管理员、开发者、访客。项目管理员可以管理项目配置、成员和保留策略开发者可以推送和拉取镜像访客只能拉取。实际团队管理中我的习惯是给每个项目分配一个项目管理员由他管理项目成员和权限普通开发人员统一给开发者角色需要拉取镜像的测试环境只给访客角色。这样即使有人误操作影响范围也控制在单个项目内。如果团队规模大还可以在Harbor的系统配置里接入外部认证源比如LDAP或统一身份认证系统。配置好之后用户可以使用已有账号登录Harbor不需要在Harbor里逐个创建账号。这个功能对上了规模的企业团队几乎是必备的。容器化和CI/CD场景还建议用机器人账号。机器人账号是专门给自动化系统用的可以理解为一个只携带token的“虚拟用户”。比如在CI系统里推送镜像不需要也最好不要用真实人的账号。创建机器人账号时可以指定它能访问哪些项目、拥有什么权限可以设置为只读或仅推送。使用时用户名是类似robot$deploy的格式密码是一串token重点是在shell脚本里命令替换时要注意$符号建议加引号docker login reg.example.local -u robot$deploy -p token字符串4.3 复制、保留策略与垃圾回收仓库自洁镜像仓库运行一段时间后数据膨胀是必然的。版本迭代频繁时一天能产生几十个镜像tag如果不加控制磁盘告警迟早会来。Harbor提供了三个手段来管理这个问题复制、保留策略和垃圾回收。复制功能解决的是多机房或多集群的镜像分发问题。在主Harbor上配置复制规则目标是另一套Harbor实例设置要同步的项目和过滤条件之后主仓库推送的镜像可以自动同步到目标仓库。复制支持推模式和拉模式支持手动、定时和事件触发。生产环境里我通常用它在测试环境和生产环境之间做镜像同步或者做灾备复制。保留策略解决的是“旧镜像堆积”问题。在项目配置中设置保留策略可以按“镜像数量”、“镜像时间”或“标签匹配”来清理。比如设定每个项目保留最近20个版本的镜像策略执行后超过数量的旧镜像会被自动清理掉。这里的清理只是删掉了仓库记录和清除了镜像的manifest不会马上释放底层磁盘空间。真正释放空间还需要垃圾回收。垃圾回收在系统管理页面可以手动执行也可以设置定时任务。它的作用是删除底层没有被任何镜像引用的blob数据。建议把保留策略和垃圾回收配合起来保留策略定时清理旧版本垃圾回收定时释放空间。我实际使用的组合是每天凌晨2点执行保留策略凌晨4点执行垃圾回收高峰期避开磁盘使用量一直很平稳。另一个容易被忽视的是配额管理。在项目配置里可以给项目设置存储上限例如限制为50GB。超过配额后新的镜像推送会被拒绝。这个功能虽然简单但在多项目共用一个仓库时能防止某个项目把磁盘空间全部占掉。4.4 Webhook和配额管理把Harbor接入流程Harbor要真正融入研发流程单靠人手动推镜像是不够的。Webhook和机器人账号让自动化成为可能。Webhook可以在某个事件发生时向外部系统发送一个HTTP请求。Harbor支持的触发事件包括镜像推送、镜像删除、镜像扫描完成等。我常用的是镜像推送WebhookCI系统构建完成并推送镜像后Harbor会调用通知服务的接口通知服务把镜像信息和构建信息推到团队沟通群或触发后续的部署流程。配置Webhook时只需要填写目标URL和需要监听的事件类型还可以用请求头带上认证信息防止接口被随意调用。要注意的是目标系统要能承受消息频率如果推送频繁需要考虑接收端的限流和幂等处理。配额管理前面提过本质上是对项目的存储上限做约束。结合保留策略仓库的容量管理基本可以做到无人值守。我的习惯是每个项目的配额按实际需要设置保留策略按“保留最近版本数按时间”双条件组合设置垃圾回收固定到深夜执行。这套组合拳打下来镜像仓库的存储管理基本不用人工干预。5. 常见问题与排查技巧实录5.1 证书报错是最普遍的拦路虎Harbor安装完成后的头号问题不是功能不好用而是客户端连不上。最典型的报错是Error response from daemon: Get https://reg.example.local/v2/: x509: certificate signed by unknown authority这个错误的意思很明确客户端Docker不信任Harbor使用的证书。如果是正规证书机构签发的证书一般不会出现如果是自签证书就需要把Harbor用的CA证书放到客户端的信任目录里。Docker读的是/etc/docker/certs.d/仓库地址/ca.crt这个路径把CA证书放进去然后重启Docker服务即可。我之前处理这个问题时走过弯路直接在Docker配置里加insecure-registries把HTTPS校验关掉。这样确实能通但等于放弃了传输加密和服务器身份校验在内网环境短期用可以生产环境不建议。正规做法还是维护好CA证书的分发客户端机器多的话可以把CA证书的安装做到系统初始化脚本里免得每台机器手动去弄。另一种证书相关的问题是证书过期。Harbor自签证书忘了更新某天突然所有客户端都推不了镜像日志里会看到x509: certificate has expired or is not yet valid。这个问题没有太好的自动化办法只能建个提醒证书到期前更新。5.2 忘记admin密码的两个恢复思路admin密码丢失是比较尴尬但实际会发生的事情。有两条恢复路径。第一条思路是修改配置后重跑安装脚本。停掉Harbor服务编辑harbor.yml里的harbor_admin_password为新密码然后重新执行./install.sh。这种方式会重新初始化admin密码但不会删除已有的项目和镜像数据。要注意的是执行前最好备份配置文件和数据库以防万一。第二条思路是直接操作数据库。Harbor的PostgreSQL容器里存着所有用户信息通过修改harbor_user表的密码哈希来完成重置。具体SQL操作需要按照代码里的加密规则生成新密码的哈希流程比较绕而且需要改salt不适合手工敲命令。相比之下我推荐第一条思路简单直接风险可控。无论用哪种方式恢复admin密码后要做的事是一样的第一时间用新密码登录改成一个高强度密码并检查有没有可疑的机器人账号或异常操作记录。密码问题说到底还是管理规范问题重要的运维账号建议用密码管理器统一管理。5.3 磁盘、内存和端口资源类问题排查容器都起来了但访问很慢页面卡顿推送镜像超时这种问题多半不是软件配置问题而是资源不够了。内存不足时最明显的是Harbor的Jobservice任务长时间不执行PostgreSQL和Redis频繁重启。用free -h查看内存使用情况如果可用内存很少就需要考虑扩容或关闭不必要的组件。有用户会用Docker的--memory限制容器内存但Harbor官方编排文件里对内存限制比较宽松没必要额外去卡。磁盘满的问题更常见。镜像推不上去时第一反应不应该是查Harbor配置而是先用df -h检查数据盘使用率。之前遇到过推送大镜像时报no space left on device以为是并发问题查了一圈才发现是磁盘满了。解决办法是先清旧镜像再跑垃圾回收把空间释放出来。端口问题也值得单独说。安装时如果修改过端口客户端访问时的完整地址必须带上端口号不然默认走443或80。如果页面能打开但是登录一直失败检查反向代理是否正确地转发到了Core服务看Nginx容器的日志能最快定位。5.4 高频问题速查表平时群里的提问五花八门但核心问题相对集中整理成一张表方便快速排查。问题现象可能原因解决思路Docker login提示unknown authority自签证书未被信任把CA证书放入客户端/etc/docker/certs.d/仓库地址/下重启DockerLogin成功但push失败镜像tag缺少项目名前缀确认镜像完整名称是仓库地址/项目名/镜像名:标签页面打不开端口未放行或Nginx异常检查防火墙查看Nginx容器日志推镜像提示no space left数据盘满了删除旧镜像执行垃圾回收释放空间复制任务一直PendingJobservice异常或网络不通查看Jobservice日志确认目标仓库可达扫描一直失败扫描器镜像缺失或网络受限检查扫描器组件是否启用镜像配置是否正确修改hostname后客户端登录失败客户端缓存和证书仍绑定旧地址同步修改客户端certs.d目录和镜像tag前缀这张表覆盖了我遇到的大部分场景。遇到问题先对照表排查能省下很多时间。最后分享一个我自己的运维习惯Harbor的数据库和harbor.yml配置一定要定期备份。镜像数据可以从远端重新拉取但项目权限、复制规则、用户信息这些元数据一旦丢失恢复成本非常高。我在实际部署中会每周把数据库做一次逻辑备份配置文件跟着版本管理走出问题时能快速恢复到任意时间点。镜像仓库是容器化环境里的“数据底座”它平时不显眼挂了才意识到有多依赖它。前期多花点时间把安装和备份的基础打好后面能省出数倍的运维精力。