首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Harbor镜像仓库高可用:HAProxy主备切换与故障演练
📅 2026/10/21 13:47:01
✍️ 爱科研究院
👁 阅读 3,247
Harbor 装起来确实快一条install.sh跑完几十分钟一个私有镜像仓库就活了。但部署快不代表能高枕无忧我在实际维护中吃过亏镜像仓库挂在 CI/CD 链路的咽喉位置前面连着代码构建后面接着应用发布一旦它出问题整个开发团队都会停下来等。最开始我只在一台机器上跑 Harbor结果有一次镜像数据把磁盘写满服务直接假死线上发布窗口被卡了整整一个下午。从那以后我就不再接受单点 Harbor这个选项。这篇文章就把我用 HAProxy 给 Harbor 做高可用的完整落地过程写一遍包括架构设计、共享存储、外部数据库、双节点部署、负载均衡配置和故障演练都是可以直接抄作业的内容。1. 为什么镜像仓库必须做高可用1.1 单点 Harbor 的隐患很多团队觉得镜像仓库只是个文件服务器重要性比不上核心业务应用。这个认知在数据量小、发布频率低的时候没毛病但一旦团队规模上来镜像仓库就是事实上的单点故障源。单点 Harbor 的风险主要集中在三个方面。第一是资源耗尽Harbor 运行时会不断产生日志、临时文件、漏洞扫描数据磁盘一旦写满registry 组件会直接报 500看起来像是应用假死实际上所有构建和部署都在等它恢复。第二是容器状态丢失Docker 容器本身是无状态的Harbor 容器一重启如果本地数据没有做好持久化镜像说没就没这对生产环境是毁灭性的。第三是升级和修复窗口困难单机跑 Harbor你想做版本升级、调配置、优化参数都必须停服操作而停服就意味着发布链路中断。所以高可用这个事不是我建议你做而是只要你的团队每天依赖这个仓库拉镜像、推镜像就应该把它当成生产基础设施来对待。1.2 高可用方案怎么选Harbor 高可用的核心思路就一句话把有状态的东西抽出去让应用层变成可以水平扩展的无状态节点。有状态的东西有三个镜像数据、数据库元数据、会话缓存。镜像数据要放到共享存储上比如 NFS、NAS、云盘或者对象存储数据库要换成外部 PostgreSQL缓存要换成共享 Redis。做完这三件事Harbor 节点本身就是无状态的节点挂了随时可以替换。应用层的部署形态有两条路线双活和主备。双活是两个 Harbor 节点同时接收读写流量由 HAProxy 做负载均衡。听起来资源利用率更高但对底层存储的一致性要求很苛刻。镜像推送到一半的时候registry 会在本地生成临时文件和锁状态如果两个节点同时处理同一个 blob 的上传共享存储上很容易出现写冲突。很多团队跑了双活之后push 大镜像时偶发 manifest 冲突排查起来很痛苦。主备模式就简单直接同一个时刻只有主节点接收流量备节点处于 ready 状态但不接收业务流量主节点挂了之后由 HAProxy 自动切换。这种模式对共享存储和数据库的压力小得多故障切换时间在几秒到十几秒之间对绝大多数发布场景完全够用。我目前在生产环境里给客户落地这套方案用的就是主备模式稳得很。2. 高可用架构设计与组件准备2.1 架构拓扑与流量走向整套架构的流量走向非常清晰客户端把harbor.example.com解析到 HAProxy 所在服务器的地址所有 Docker 命令请求先打到 HAProxyHAProxy 根据健康检查结果把请求转发给当前可用的 Harbor 节点。Harbor 节点之间通过共享存储和外部数据库保证数据一致任一节点故障都不影响整体服务。具体角色划分如下HAProxy 节点对外暴露 443 端口负责 TLS 终结、流量转发、健康检查和故障切换。Harbor 节点 1主节点正常状态下承接所有读写流量。Harbor 节点 2备节点和主节点使用同一套共享存储与外部数据库平时不接流量主节点宕机时自动接管。NFS 存储存放 Harbor 的data_volume数据包括镜像层文件、配置、临时文件等。PostgreSQL存放 Harbor 的元数据包括项目、镜像仓库、标签、用户权限等。Redis存放会话和缓存数据避免切换节点后用户登录态丢失。这里补充一点HAProxy 本身也是单点如果连 HAProxy 这台机器都挂了整个链路照样断。所以更完整的方案会给 HAProxy 配 Keepalived 做 VIP 漂移两台 HAProxy 一主一备。篇幅有限本文把重点放在 Harbor 节点的高可用上HAProxy 自身的双机热备我会在文末提一句有需要可以自己扩展。2.2 组件选型与版本搭配我落地这套方案用的组件版本如下都是经过生产验证的稳定组合组件版本作用Harbor2.8 系列企业级镜像仓库支持外部数据库与外部 RedisHAProxy2.6 系列四七层负载均衡健康检查与故障切换能力完善PostgreSQL14 系列元数据存储推荐独立部署或使用云数据库Redis6.2 系列会话与缓存存储使用独立实例NFS4.1 协议共享镜像数据也可替换为 NAS 或云盘Harbor 的版本选择很关键。老版本对高可用的支持较弱我之前用 1.x 版本做外部数据库时踩过依赖组件不全的坑。2.x 之后官方已经明确支持外部 PostgreSQL 和外部 Redis并且组件之间通过 Redis 做分布式锁多节点协同更可靠。HAProxy 用 2.x 是因为它的http-check send语法更灵活健康检查可以带完整请求头比老版本只写一个 URL 要精确得多。2.3 端口规划与安全边界规划端口时我给每个服务都做了清晰的分配避免端口冲突和排查混乱服务部署位置端口说明HAProxy 对外入口HAProxy 节点443Docker 客户端访问的统一地址Harbor 节点 HTTP节点 1 / 节点 28080HAProxy 后端连接使用的内部端口Harbor 节点 HTTPS节点 1 / 节点 28443直连测试用的 HTTPS 端口PostgreSQL数据库主机5432只允许 Harbor 节点网段访问Redis数据库主机6379只允许 Harbor 节点网段访问NFS存储主机2049只允许 Harbor 节点网段访问这里有个细节要注意Harbor 默认会占用宿主机的 80 和 443 端口我把它改成 8080 和 8443是为了避免和 HAProxy 的 443 端口在客户端访问路径上产生歧义。你也可以不改只要 HAProxy 后端连接用对应的端口就行但改成非标准端口之后直连某个节点测试时会更容易区分流量走的是谁。3. 底层依赖先行共享存储、外部数据库与缓存3.1 NFS 共享存储配置Harbor 的镜像数据都在data_volume目录下两个 Harbor 节点必须把这一目录挂载到同一个共享存储上。我用的是 NFS配置过程比较简单。存储节点上先创建导出的根目录mkdir -p /data/nfs/harbor编辑/etc/exports把目录导出给内网网段/data/nfs/harbor 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)注意no_root_squash这个参数不能少。Harbor 容器内部进程往存储目录写入时用的是容器内的 root 或指定用户如果 NFS 默认启用 root_squash容器内 root 会被映射成匿名用户写入直接 permission denied。加上这个参数可以避免大量莫名其妙的权限报错。导出之后重启 NFS 服务exportfs -ra systemctl restart nfs-server两个 Harbor 节点上执行挂载mkdir -p /data mount.nfs4 192.168.1.20:/data/nfs/harbor /data为了重启后自动挂载写入/etc/fstab192.168.1.20:/data/nfs/harbor /data nfs4 rw,hard,intr,timeo600,retrans2,noatime 0 0把/data权限设置为 777 最省事因为 Harbor 会在这个目录下创建很多子目录某些子目录属主是容器内用户直接给满权限一劳永逸。3.2 外部 PostgreSQL 部署PostgreSQL 我用独立主机部署版本用的 14。如果团队有云数据库直接用云厂商的实例也可以关键是给 Harbor 建好专用的库和账号。安装完成后执行sudo -u postgres psql创建 Harbor 专用的账号和数据库CREATE USER harbor WITH PASSWORD HarborPGpass; CREATE DATABASE harbor OWNER harbor;Harbor 2.8 之后只需要一个harbor库就够用了。早期版本连 Trivy 还需要单独的harbor_clair库很多朋友照着老教程抄结果发现 2.8 执行install.sh时根本不会去碰那个库白白浪费时间。远程连接要允许 Harbor 节点网段访问。编辑pg_hba.conf在文件末尾加上host all harbor 192.168.1.0/24 md5然后修改postgresql.conf里的listen_addresses重启服务alter system set listen_addresses 192.168.1.30; systemctl restart postgresql这里有一个容易忽略的点Harbor 连接数据库时会创建连接池连接数取决于max_open_conns。如果 PostgreSQL 默认的max_connections是 100而你把max_open_conns也设成 100再算上其他连接数据库很容易被打满。建议 Harbor 配置里max_open_conns不要超过 50给数据库预留一些余量。3.3 Redis 共享缓存配置Redis 的作用经常被低估。Harbor 的 Web 会话、registry 的某些缓存状态、分布式锁都依赖 Redis。两个 Harbor 节点必须使用同一个 Redis 实例否则用户登录状态和跨节点的数据一致性都会出问题。安装 Redis 后做三件事bind 192.168.1.30 requirepass HarborRedispass重启服务后在两个 Harbor 节点的harbor.yml里配置同一个 Redis 地址和密码。Redis 不需要开持久化因为这里存的是缓存和会话数据丢了最多让人重新登录一次不会丢核心数据。但 Redis 所在的机器最好有充足内存别和 PostgreSQL 挤在同一台低配机器上否则镜像并发推送时容易出现延迟。4. Harbor 双节点部署实操4.1 harbor.yml 核心配置从官网下载 Harbor 离线安装包后进入目录复制模板tar xzvf harbor-offline-installer-v2.8.4.tgz cd harbor cp harbor.yml.tmpl harbor.yml编辑harbor.yml核心配置如下hostname: harbor.example.com http: port: 8080 https: port: 8443 certificate: /data/cert/harbor.crt private_key: /data/cert/harbor.key harbor_admin_password: HarborAdmin123 data_volume: /data database: type: external external: host: 192.168.1.30 port: 5432 db_name: harbor username: harbor password: HarborPGpass sslmode: disable max_idle_conns: 5 max_open_conns: 50 redis: type: external external: host: 192.168.1.30 port: 6379 password: HarborRedispass db: 0注意hostname两个节点必须完全一致都填同一个对外域名。Harbor 会根据这个值生成 registry 的访问地址如果节点 2 的 hostname 填成节点 2 自己的 IPDocker 客户端从 HAProxy 转发过来之后某些 API 返回的地址会错乱导致 push 失败。证书文件要提前放到/data/cert下Harbor 的 HTTPS 端口需要用到。如果你打算让 HAProxy 终结 TLSHarbor 节点的证书可以直接用同一张也可以临时生成一张自签的后面统一替换。4.2 部署首个节点并初始化数据库配置好harbor.yml后执行安装脚本sudo ./install.sh --with-trivy首次安装会做数据库初始化、迁移、创建容器组件。这个过程在节点 1 上必须完整跑完让数据库 schema 迁到最新版本。跑完之后看下所有容器状态sudo docker-compose ps正常情况下所有组件状态都是 healthy。如果某个组件一直处于 restarting 状态大概率是配置问题先看日志排查sudo docker-compose logs -f core节点 1 初始化完成后外部数据库里已经存在 Harbor 的表结构和基础数据。这是整个部署过程中最关键的一步因为后面节点 2 启动时会复用这套 schema绝不能在节点 2 上再执行一次数据库初始化。4.3 部署第二个节点节点 2 的部署方式几乎和节点 1 一模一样但有几个细节要格外小心。把节点 1 那份已经验证过的harbor.yml直接复制到节点 2不要重新从模板生成否则容易漏掉外部数据库和外部 Redis 的配置。然后执行同样的安装命令sudo ./install.sh --with-trivy节点 2 启动时Harbor 会检测外部数据库已有数据自动跳过初始化迁移直接拉起组件。如果日志里出现 migration 失败不要硬着头皮重试先检查数据库版本是否和 Harbor 版本匹配。我遇到过一次节点 2 用的离线包和节点 1 不是同一个微版本结果数据库迁移直接报了版本冲突。两个节点都起来之后确认节点 2 不会尝试重置管理员密码。因为管理员密码存在外部数据库中节点 2 的harbor_admin_password即使和节点 1 不同也不会覆盖数据库里的密码。实际登录时用的还是节点 1 部署时设置的那个密码。4.4 双节点功能自检直接访问节点 IP 做健康检查确认核心 API 正常curl -k https://192.168.1.10:8443/api/v2.0/ping curl -k https://192.168.1.11:8443/api/v2.0/ping返回 200 说明核心服务正常。接着验证登录和 push 流程可以先用 docker 客户端登录echo HarborAdmin123 | docker login harbor.example.com -u admin --password-stdin两个节点都自检通过后就可以切到 HAProxy 配置了。5. HAProxy 负载均衡配置核心细节5.1 安装与证书准备HAProxy 我单独放在一台低配虚拟机上2C4G 就够跑主要吃带宽和连接数。安装apt install haproxyTLS 证书直接复用 Harbor 的那张证书。HAProxy 需要的是 PEM 格式把证书和私钥合并成一个文件mkdir -p /etc/haproxy/certs cat /data/cert/harbor.crt /data/cert/harbor.key /etc/haproxy/certs/harbor-example.pem chmod 600 /etc/haproxy/certs/harbor-example.pem这里建议直接用一张包含harbor.example.com、节点 1 IP、节点 2 IP 的 SAN 证书这样无论客户端最终连到哪个节点证书校验都能通过。如果证书和域名不匹配客户端的 docker daemon 会拒绝连接终端会报 unknown certificate 错误。5.2 主备模式的 HAProxy 配置编辑/etc/haproxy/haproxy.cfg完整配置如下global log /dev/log local0 info maxconn 50000 user haproxy group haproxy daemon stats socket /run/haproxy/admin.sock mode 660 level admin spread-checks 5 defaults mode http log global option httplog option dontlognull option redispatch timeout connect 10s timeout client 900s timeout server 900s timeout check 10s frontend harbor_https bind *:443 ssl crt /etc/haproxy/certs/harbor-example.pem http-request set-header X-Forwarded-Proto https option forwardfor default_backend harbor_nodes backend harbor_nodes balance leastconn option httpchk http-check send meth GET uri /api/v2.0/ping hdr Host harbor.example.com http-check expect status 200 server harbor01 192.168.1.10:8080 check inter 3s fall 2 rise 2 server harbor02 192.168.1.11:8080 check inter 3s fall 2 rise 2 backup listen stats bind *:9101 mode http stats enable stats uri /stats stats refresh 5s stats auth monitor:Haproxy123关键点是harbor02后面的backup关键字。HAProxy 的调度策略是只要存在可用的非 backup 服务器就绝不把新连接发给 backup 服务器。也就是说正常情况流量全部走harbor01harbor01宕机后harbor02自动接管。这正好实现了我前面说的主备模式。5.3 健康检查参数拆解很多人配置健康检查只写一个check就完事但这样只是 TCP 层的端口探测Harbor 进程没死透但业务已经不可用时端口照样能连上流量还是会打过来。所以这里用option httpchk加上http-check send向/api/v2.0/ping发送请求并要求返回 200。这个接口是整个 Harbor 对外服务的心跳口只要核心 API 组件活着这个接口就正常只要这个接口出问题说明 Harbor 已经无法正常服务业务健康检查就会立刻标记节点 DOWN。参数解释inter 3s每 3 秒发送一次健康检查。fall 2连续两次失败才判定节点 DOWN避免网络抖动误切换。rise 2连续两次成功才判定节点 UP避免刚恢复就立刻接流量又被冲垮。spread-checks 5给健康检查增加 5% 的随机时间偏置避免两个节点的检查请求同时打过来形成节奏性冲击。按照这个配置主节点从故障到切换完成的时间大约在 3 到 6 秒之间。如果你希望切换更快可以把inter缩短到 2 秒、fall降为 1但会增加误判风险我建议保持这个平衡。5.4 统计监控页面与日志配置里listen stats段启动了一个统计服务访问http://HAProxy节点IP:9101/stats输入配置的账号密码就能看到两个后端节点的实时状态。页面里会清楚显示主节点状态为 UP、备节点状态为 UP (backup)一旦主节点宕机它的状态变成 DOWN流量全跑到备节点上。这个页面也是我做故障演练时的第一观察入口。HAProxy 日志默认输出到系统日志可以在/var/log/haproxy.log里看到转发记录。我把option httplog打开之后每条请求都能看到源 IP、目标节点、状态码。故障排查时最常用的操作就是tailf /var/log/haproxy.log重点看有没有 503 状态码出现 503 说明当前没有可用后端要么两个节点都挂了要么健康检查配置有问题。5.5 针对大镜像场景的超时调优默认的timeout client和timeout server经常不够用。Docker 客户端 push 一个几个 GB 的大镜像时整个数据传输过程可能持续几分钟而 HAProxy 默认的 server 超时只有几十秒。一旦超过时限HAProxy 会主动切断连接客户端就会报 unexpected EOF 或者连接重置。我把两个超时都设成 900 秒基本可以覆盖绝大部分生产场景。如果你的团队经常推送超大模型镜像或者离线安装包可以再往上调。这个参数改完之后的效果立竿见影之前偶尔出现的大镜像 push 到一半断了的诡异问题瞬间消失。6. 故障切换演练与高频问题排查6.1 手动模拟主节点宕机方案落地后一定要做一次故障演练别等真出事了再验证配置有没有用。我的演练流程如下。先在测试机器上推送一个镜像到 Harbor确认当前后端节点是主节点harbor01。然后到主节点上直接停掉 Harbor 服务cd /data/harbor sudo docker-compose down此时立即观察 HAProxy 统计页面大约 6 秒后主节点状态从 UP 变成 DOWN同时备节点状态从 UP (backup) 变成 UP 并从右侧流量计数里看到请求开始进来。再执行一次 docker 登录和 pushecho HarborAdmin123 | docker login harbor.example.com -u admin --password-stdin docker push harbor.example.com/test/demo:v1一切正常说明故障切换生效。最后恢复主节点cd /data/harbor sudo docker-compose up -d等待容器全部 healthy再观察 HAProxy 统计页面主节点恢复 UP 状态并自动重新接管流量备节点退回 backup 状态。整个过程不需要人工干预Docker 客户端也无感知。6.2 高频问题速查表现象可能原因解决办法健康检查失败HAProxy 返回 503Harbor 容器未启动或 NFS 挂载断开查看docker-compose ps检查mount状态重新挂载 /dataping 接口返回 200 但 docker login 报证书错误客户端不信任 Harbor 证书将 Harbor 证书加入 Docker 客户端信任列表或配置 insecure-registries 后重启 docker主备切换后 push 报 manifest 冲突旧连接残留在已停止节点上等待旧连接自然断开或在客户端重新登录再 pushNFS 目录写入 permission deniedroot_squash 生效或目录属主不匹配exports 配置 no_root_squash并将 /data 权限设为 777PostgreSQL 连接数打满max_open_conns 配得过大将 max_open_conns 调整为 30-50并把 PG max_connections 调大双节点部署后 UI 访问偶发 401Redis 未共用或 session 不一致确认两个节点的 redis.external 配置指向同一个实例大镜像 push 到一半断开HAProxy 超时配置过小将 timeout client 和 timeout server 调大到 900s6.3 生产环境避坑心得整套方案跑起来不难真正难的是那些文档里不写的细节。第一个坑是双节点不要同时跑install.sh。我有一次图省事两个节点同时执行安装脚本结果外部数据库的迁移锁被两个进程同时抢占Harbor 任务表的数据序列直接错乱最后只能删掉数据库重建。正确做法是老老实实先跑节点 1确认数据迁移完成再跑节点 2。第二个坑是 NFS 性能。镜像仓库是 IO 密集型场景尤其多人同时 push 时底层存储压力非常大。千兆网卡在并发超过几十个连接时就会成为瓶颈表现为 push 速度很慢、健康检查偶发超时。建议至少上万兆内网或者直接用云盘、NAS。性能测试时别只测单线程 push要模拟多团队并发推镜像的真实场景。第三个坑是证书和域名的一致性。HAProxy、Harbor 节点、客户端三方的域名和证书必须统一。最省心的方法是把同一个 PEM 文件复制到所有节点并确保证书 SAN 包含对外域名。客户端侧在/etc/docker/daemon.json里把harbor.example.com加进insecure-registries或者配置系统 CA这样就不会出现测试环境能登录生产环境一直报错的尴尬。第四个坑是高可用不等于备份。即使做了双节点主备也不代表数据绝对安全因为两个节点用的是同一份 NFS 和同一个数据库一旦存储设备整体损坏两个节点一起完蛋。所以镜像数据的外部备份仍然是必须的定期将 NFS 数据复制到异地或者推到云对象存储才是真正的最后一道防线。我个人在实际操作中的体会是高可用方案的价值不在技术含量而在稳定性和可维护性。主备模式确实不上双活那些华丽的概念但它够简单、够可靠切换逻辑一眼就能看懂出了问题也好排查。这套架构我前后在好几个环境跑了一年多故障切换时间稳定在十秒内平时几乎感觉不到它的存在但每次演练都在提醒我这份存在感低的配置正是整个发布链路最关键的保险绳。最后再给一个实用建议方案全部落地后把故障演练排进运维计划每季度至少做一次不要等到镜像仓库真的挂了才验证配置是否有效。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/21 13:47:01
生产级K8s高可用流量入口:haproxy+pacemaker负载均衡集群详解
2026/10/21 13:47:01
HAProxy实现Harbor高可用架构:负载均衡与故障转移实战
2026/10/21 13:41:59
软件验证是什么?从静态分析到形式化方法的工程化落地
2026/10/21 17:56:03
C#开发进阶:从语法到架构设计的实战踩坑与优化指南
2026/10/21 17:56:03
Loop Engineering:系统级反馈控制的工程化实践
2026/10/21 17:56:03
技术博文高效写作:从信息模板到SEO友好呈现
2026/10/21 17:56:03
从源码到可执行文件:GCC编译链接原理与常见坑点全解
2026/10/21 17:56:03
Next.js 14 + Prisma 实战:用 AI 高效生成 CRUD、SSR 与多任务模块
2026/10/21 17:50:59
SQL Server + Swing 宾馆管理系统:数据库课设中的事务与CRUD实战
2026/10/21 0:01:44
ClickHouse实战:从列式存储到亿级数据秒级查询
2026/10/21 0:01:44
高效筛选arXiv机器学习论文:四步法实战指南
2026/10/21 0:01:44
Python爬取百度迁徙数据:接口签名、反爬与SQLite存储实战
2026/10/20 16:07:12
OpenResearch实战:Claude Code、Codex、OpenCode、Cursor 工作流搭建与故障排查
2026/10/21 14:47:26
知识管理核弹:用Obsidian构建第二大脑的工程化方案(TaoToken 统一 Key 接入版)
2026/10/20 16:49:38
金融AI落地指南:从调研报告到技术选型与工程实践
2026/10/20 2:24:03
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/20 2:23:57
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/20 2:23:53
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)