1. 为什么非得自己搭 Harbor,而不是直接用 Docker Hub?
Harbor 不是 Docker 官方出品的“另一个镜像仓库”,它是 CNCF 毕业项目,背后有真实企业级落地逻辑支撑。我最早接触 Harbor 是在某高校实验室做边缘计算平台时——当时团队要部署 12 类 AI 推理服务到 37 台边缘设备,每类服务含 4~6 个微服务镜像,版本迭代平均每周 2.3 次。如果全走 Docker Hub,光拉取镜像就卡在公网带宽上:实测单节点首次 pull 一个 1.2GB 的 PyTorch 推理镜像,平均耗时 8 分 23 秒,且 37 台并发触发 rate limit,第二天凌晨三点被邮件告警“Your account has been temporarily rate limited”。
这不是个别现象。Docker Hub 免费账户的匿名拉取限速是 100 次/6 小时,登录用户是 200 次/6 小时;而 Harbor 私有仓库的核心价值,从来不是“把镜像存本地”这么简单——它解决的是镜像可信分发、权限精细管控、生命周期可追溯、审计合规可落地这四层问题。
比如某次我们上线新模型服务前,安全组要求所有镜像必须通过 Clair 扫描无 CVE-2023-29357 级别以上漏洞,且扫描报告需绑定 Git 提交哈希。Docker Hub 做不到自动绑定;但 Harbor 配合 Webhook + Jenkins Pipeline,能实现“代码提交 → 自动构建 → 自动扫描 → 报告存档 → 仅允许绿色镜像推送到 prod 项目”。这个闭环,才是 Harbor 在生产环境不可替代的底层逻辑。
关键词里虽未明写,但实际落地中绕不开的硬需求有三个:镜像签名验证(Notary)、多租户项目隔离(Project)、基于角色的细粒度权限(RBAC)。很多人以为“搭个 registry 就完事”,结果上线三天就被运维叫停——因为开发 A 误删了开发 B 的测试镜像,而 registry 默认不带操作审计日志。Harbor 的project概念天然隔离资源,每个项目可设独立配额、扫描策略、机器人账号,这才是企业级仓库的起点。
提示:Harbor 不是“Docker Registry 的图形界面增强版”,它是围绕 OCI 镜像标准构建的完整分发治理平台。它的核心组件(Core、Registry、Trivy、Notary、Clair)全部解耦设计,你可以只启用 Registry+Core 做轻量私仓,也可以全量启用做合规中枢。这种可裁剪性,决定了它比单纯用
docker run -d -p 5000:5000 registry:2高出至少两个工程成熟度层级。
2. Harbor 架构拆解:五个核心组件如何协同工作?
Harbor 不是单体进程,而是由 7 个容器协同组成的微服务集群(官方默认部署含 7 个,精简后可压至 5 个)。理解各组件职责,是调优和排障的前提。下面这张表不是照搬官网文档,而是我在线上环境反复 kill -9 某些容器后总结出的真实依赖关系:
| 组件名 | 容器名 | 关键职责 | 停止后影响 | 实测恢复时间 |
|---|---|---|---|---|
| harbor-core | core | 权限校验、Webhook 触发、机器人账号管理 | 所有 push/pull 失败(401 Unauthorized) | 重启后 12s 内恢复 |
| harbor-registry | registry | 镜像存储、OCI 层级读写、Blob 管理 | push 成功但 pull 返回 404 | 需等待 registry 重新加载 manifest 缓存,约 47s |
| harbor-trivy | trivy-adapter | 调用 Trivy 扫描镜像、生成报告、写入数据库 | 扫描任务卡住,但不影响 push/pull | 重启即恢复,无状态 |
| harbor-notary-server | notary-server | 签名密钥管理、TUF 元数据签发 | docker trust相关命令失败,但普通操作正常 | 启动较慢,约 92s(因需初始化 TUF 仓库) |
| harbor-jobservice | jobservice | 异步任务调度(GC、镜像复制、扫描队列) | 扫描不触发、GC 不执行、复制任务挂起 | 重启后需手动触发一次curl -X POST http://core:8080/api/v2.0/system/gc/schedule |
注意:harbor-portal(前端页面)和harbor-log(日志收集)属于辅助组件,停掉不影响核心功能,但会丢失 Web 界面和集中日志。而harbor-database(PostgreSQL)和harbor-redis是状态中心,一旦宕机,整个 Harbor 将不可用——这是所有初学者最容易忽略的单点故障点。
举个真实案例:某次我们升级 Harbor 到 v2.8.3,因未按文档先备份database容器的/var/lib/postgresql/data卷,升级脚本执行ALTER TABLE project ADD COLUMN ...时遭遇锁表,导致core服务持续返回 500 错误。排查链路如下:
curl -I http://harbor.example.com/api/v2.0/projects返回 500;- 查
core日志发现pq: relation "project" does not exist; - 进入
database容器执行\dt,发现project表确实不存在; - 对比 v2.7.3 和 v2.8.3 的 migration SQL,确认是
0001_add_project_table.up.sql未执行; - 手动执行该 SQL 后,
core服务 3 秒内恢复正常。
这个过程暴露出关键认知:Harbor 的数据库 schema 是强约束的,任何跳过 migration 步骤的“暴力升级”必然失败。官方文档强调的 “always backup database before upgrade” 不是客套话,而是血泪教训。
注意:Harbor 的
jobservice组件有个隐藏特性——它默认使用 Redis 的db 2存储任务队列,而core使用db 1存储会话。如果你在harbor.yml中自定义了redis.url但没指定db参数(如redis://localhost:6379/2),会导致任务队列和会话混用同一 DB,引发诡异的 401 错误。这个坑我在三个不同客户环境都踩过,解决方案永远是:显式声明redis://localhost:6379/1和redis://localhost:6379/2。
3. 生产级部署:从离线安装包到高可用架构的七步落地
Harbor 官方提供两种安装方式:在线install.sh(依赖网络下载镜像)和离线offline-installer.tgz(所有镜像打包)。生产环境必须选离线包——某次我们在线安装时,因goharbor/harbor-core:v2.7.1镜像在 Docker Hub 上被临时下架(版本号冲突),导致install.sh卡在pull harbor-core步骤长达 47 分钟,最终超时退出。离线包虽体积大(v2.8.3 约 1.2GB),但可控性远高于在线安装。
以下是我在某金融级系统中验证过的七步生产部署法,每步都标注了“为什么必须这么做”:
3.1 准备离线环境与基础依赖
# 1. 下载离线包(以 v2.8.3 为例) wget https://github.com/goharbor/harbor/releases/download/v2.8.3/harbor-offline-installer-v2.8.3.tgz # 2. 解压并修改配置(关键!) tar -xzf harbor-offline-installer-v2.8.3.tgz cd harbor # 编辑 harbor.yml,重点修改以下三项: hostname: harbor-prod.internal # 必须是 FQDN,不能是 IP 或 localhost https: port: 443 certificate: /data/cert/harbor.crt # 必须是 PEM 格式证书链 private_key: /data/cert/harbor.key为什么必须用 FQDN?因为 Notary 签名证书的 SAN(Subject Alternative Name)字段必须包含 hostname,若填
192.168.1.100,docker trust会报x509: certificate is valid for 192.168.1.100, not for harbor-prod.internal。这个错误在测试环境常被忽略,但上线后所有签名镜像将无法拉取。
3.2 证书生成:用 OpenSSL 生成符合 OCI 标准的证书链
# 创建 CA 根证书(有效期 10 年) openssl genrsa -out ca.key 4096 openssl req -x509 -new -nodes -key ca.key -subj "/CN=Harbor-CA" -days 3650 -out ca.crt # 为 Harbor 生成证书(关键参数不能错) openssl genrsa -out harbor.key 2048 openssl req -new -key harbor.key -subj "/CN=harbor-prod.internal" -out harbor.csr # 生成 extfile(必须包含 SAN) cat > harbor.ext <<EOF subjectAltName = DNS:harbor-prod.internal,IP:192.168.1.100 EOF openssl x509 -req -in harbor.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -extfile harbor.ext -days 365 -out harbor.crt为什么必须加
IPSAN?因为某些内网设备(如 IoT 网关)可能只认 IP 访问,若证书无 IP SAN,curl 会报SSL certificate problem: unable to get local issuer certificate。这个细节在 Harbor 文档里藏得很深,但线上故障率极高。
3.3 配置持久化存储:避开 NFS 的三个致命陷阱
Harbor 默认使用本地路径/data,但生产环境必须外挂存储。我们实测过三种方案:
NFS v4.1:吞吐稳定,但存在三个致命问题:
registry容器对 NFS 的open(O_EXCL)支持不一致,导致镜像层写入失败(错误日志:failed to create blob upload);jobservice的 GC 任务在 NFS 上执行极慢(10GB 镜像 GC 耗时 23 分钟);- NFS 锁机制与 PostgreSQL 的 WAL 日志写入冲突,偶发数据库崩溃。
LVM 逻辑卷:性能最优,但扩容复杂,且无法跨节点。
对象存储(S3 兼容):最终选择 MinIO(自建 S3),配置如下:
# harbor.yml 中 storage_service 部分 storage_service: s3: region: us-east-1 bucket: harbor-bucket accesskey: minioadmin secretkey: minioadmin secure: false endpoint: http://minio.internal:9000为什么选 MinIO 而非公有云 S3?因为金融客户要求数据不出内网,且 MinIO 的
mc admin info命令可实时监控每个桶的 IOPS,比 NFS 的iostat更精准。实测 MinIO 下 10GB 镜像 GC 时间降至 3 分 12 秒。
3.4 启动与验证:用 curl 替代浏览器做首检
# 启动(必须用 root,因需创建 /data 目录) sudo ./install.sh --with-notary --with-trivy # 验证核心服务(不用打开浏览器!) curl -k -I https://harbor-prod.internal/api/v2.0/systeminfo # 应返回 HTTP/2 200 OK,且 header 含 X-Harbor-Version: v2.8.3 # 验证 Notary(关键!) curl -k -I https://harbor-prod.internal:4443/v2/ # 应返回 200,否则 Notary 未生效为什么首检不用浏览器?因为浏览器会缓存 HTTP 重定向(如 http→https),掩盖
nginx配置错误。用 curl 可直击后端服务,且-I参数只取 header,避免大响应体干扰判断。
3.5 配置高可用:双节点 Active-Standby 模式
单节点 Harbor 无法满足 SLA 99.95% 要求。我们采用 Keepalived + Harbor 双节点方案:
- 节点 A(192.168.1.100)和节点 B(192.168.1.101)部署完全相同的 Harbor;
- 共享 MinIO 存储和 PostgreSQL 集群(主从同步);
- Keepalived VIP(192.168.1.102)漂移,客户端始终访问 VIP;
jobservice在 standby 节点禁用(harbor.yml中jobservice.max_job_workers: 0)。
关键配置在keepalived.conf:
vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 # 备节点设为 90 virtual_ipaddress { 192.168.1.102 } # 检测 Harbor Core 是否存活 track_script { check_harbor_core } } vrrp_script check_harbor_core { script "/usr/bin/curl -k -f https://localhost/api/v2.0/systeminfo || exit 1" interval 3 fall 2 rise 2 }为什么检测
/api/v2.0/systeminfo而非/?因为/返回 HTML 页面,而/systeminfo返回 JSON 且不依赖前端资源,检测更精准。曾因检测/导致 VIP 误漂移——因 Portal 容器启动慢于 Core,但/已返回 200。
3.6 首次推送测试:绕过证书信任的三步法
# 1. 将 ca.crt 复制到客户端 sudo mkdir -p /etc/docker/certs.d/harbor-prod.internal sudo cp ca.crt /etc/docker/certs.d/harbor-prod.internal/ca.crt # 2. 重启 docker daemon(必须!) sudo systemctl restart docker # 3. 登录并推送(用 admin 用户) docker login https://harbor-prod.internal docker tag nginx:alpine harbor-prod.internal/library/nginx:alpine docker push harbor-prod.internal/library/nginx:alpine为什么必须重启 docker?因为 Docker daemon 启动时才读取
/etc/docker/certs.d/下的证书,热加载不生效。曾有同事改完证书不重启,docker push一直报x509: certificate signed by unknown authority,折腾两小时才发现。
3.7 权限初始化:创建第一个项目与机器人账号
登录 Web 界面后,立即执行:
- 创建项目
library(公开,用于基础镜像); - 创建项目
prod(私有,配额 500GB,启用自动扫描); - 为 CI/CD 创建机器人账号
jenkins-bot,权限:prod项目的pull/push; - 为安全组创建只读账号
sec-audit,权限:所有项目的pull。
为什么先建
library项目?因为library是 Harbor 的默认公共项目,所有未指定项目的 push 会自动进入此处。若不提前建好,docker push harbor-prod.internal/nginx:alpine会因项目不存在而失败,错误提示却是unauthorized: authentication required,极具误导性。
4. 权限与安全:RBAC 模型下的最小权限实践
Harbor 的 RBAC(基于角色的访问控制)不是简单的“管理员/开发者/访客”三级,而是由Project Role + System Role + Robot Account三层叠加构成。很多团队初期只用 Project Role,结果出现权限越界——比如给测试人员developer角色,他却能删除整个项目。这是因为developer角色默认拥有project_admin权限,而project_admin可删除项目。
我们制定的最小权限原则是:所有账号默认无权限,按需授予精确到 API 级别的权限。具体落地分三步:
4.1 系统角色(System Role)的严格分级
Harbor 内置四个系统角色,但生产环境只启用三个:
system-admin:仅限 2 人(主运维 + 备运维),负责全局配置、用户管理、审计日志查看;security-admin:仅限安全组 1 人,负责扫描策略、CVE 库更新、签名密钥管理;user:所有普通用户默认角色,无任何项目权限(这是关键!)。
为什么禁用
project-admin系统角色?因为该角色可创建任意项目,且新建项目默认继承其权限。曾有实习生用project-admin创建了hack-test项目,因未设配额,其构建的 200GB 镜像占满 MinIO 存储,导致生产镜像无法推送。解决方案:在harbor.yml中注释掉project_admin的 role definition,并用curl脚本定期检查GET /api/v2.0/users?role=3(role=3 即 project-admin)返回空数组。
4.2 项目角色(Project Role)的精细化配置
每个项目必须设置三类角色:
maintainer:可管理项目设置、成员、机器人账号,不可删除项目(通过 API 级别限制);developer:可 push/pull 镜像、触发扫描,不可管理成员;guest:仅可 pull 镜像。
关键操作:在 Harbor Web 界面 → 项目 → 成员 → 添加成员时,必须取消勾选“继承系统角色”。否则user系统角色会覆盖项目角色,导致权限混乱。
4.3 机器人账号(Robot Account)的 CI/CD 安全实践
机器人账号是 CI/CD 的命脉,但也是最大风险点。我们的规范:
- 每个流水线(Jenkins Job)对应唯一机器人账号,命名规则:
jenkins-{job-name}-{env}(如jenkins-web-api-prod); - 令牌(token)有效期设为 90 天,到期自动失效;
- 权限严格限定:仅授予目标项目的
pull/push,禁止delete权限; - 所有机器人账号密码存入 HashiCorp Vault,Jenkins 通过 Vault Plugin 动态获取。
实测发现:若机器人账号有delete权限,Jenkins 流水线中docker rmi命令会误删远程镜像(因docker rmi默认连接本地 registry,但 Harbor 的robot账号权限作用于远程)。解决方案是在 Jenkinsfile 中显式指定 registry:
sh "docker rmi harbor-prod.internal/prod/web-api:latest" // 明确指定 registry4.4 审计日志:用 ELK 实现操作行为可追溯
Harbor 默认审计日志存于harbor-log容器的/var/log/harbor/audit.log,但文本日志难以分析。我们接入 ELK 栈:
- Filebeat 采集
audit.log,过滤action: "push"或action: "delete"; - Logstash 解析 JSON 字段(
user_name,repo_name,operation); - Kibana 建立看板,关键看板包括:
- “TOP 10 镜像删除者”(定位误操作高频人员);
- “非工作时间 push 行为”(检测异常活动);
- “失败登录 Top 5 IP”(关联防火墙封禁)。
一个真实案例:审计日志显示
user_name: "jenkins-bot"在凌晨 2:17 删除了prod/ml-model:v1.2,而 Jenkins 流水线记录显示该任务在 2:15 已成功。追查发现是某开发在本地执行make clean时,Makefile 中的docker rmi $(IMAGE)未加 registry 前缀,误删了远程镜像。ELK 看板 3 分钟内发出告警,我们立即从 MinIO 的版本控制中恢复了该镜像。
5. 故障排查:从 500 错误到镜像拉取失败的完整诊断链
Harbor 故障最典型的表现是docker push返回500 Internal Server Error或docker pull返回unauthorized: authentication required。下面是我整理的标准化排查链路,按优先级排序:
5.1 第一层:网络与证书(占故障率 62%)
症状:curl -kI https://harbor-prod.internal/api/v2.0/systeminfo返回 500
排查步骤:
- 检查
nginx容器日志:docker logs harbor-nginx 2>&1 | tail -20- 若见
connect() failed (111: Connection refused) while connecting to upstream,说明core容器未就绪;
- 若见
- 检查
core容器状态:docker ps | grep core- 若
STATUS为Restarting (1),查docker logs harbor-core; - 常见错误:
failed to connect to database: pq: password authentication failed for user "postgres"→ 检查harbor.yml中database.password是否与database容器的POSTGRES_PASSWORD一致;
- 若
快速修复:
# 重置数据库密码(需进入 database 容器) docker exec -it harbor-db psql -U postgres postgres=# ALTER USER postgres PASSWORD 'newpass123'; \q # 修改 harbor.yml 中 database.password 为 newpass123,重启 sudo docker-compose down && sudo ./install.sh --with-notary --with-trivy5.2 第二层:存储与权限(占故障率 23%)
症状:docker push卡住,docker logs harbor-registry显示failed to create blob upload
根因:MinIO 存储桶权限不足或 NFS 文件锁冲突。
验证方法:
# 进入 registry 容器,手动写入测试文件 docker exec -it harbor-registry sh / # touch /storage/test.txt # 若报 Permission denied,则存储挂载失败 / # ls -l /storage/ # 检查 uid/gid 是否匹配(registry 容器 uid=10000)修复方案:
- 若用 MinIO,检查
harbor.yml中accesskey/secretkey是否正确; - 若用 NFS,强制卸载并重挂载,添加
nolock参数:mount -t nfs4 -o nolock,proto=tcp,port=2049 192.168.1.200:/harbor /data
5.3 第三层:认证与 Token(占故障率 12%)
症状:docker login成功,但docker push返回unauthorized: authentication required
本质:Token 服务(core)与 Registry 之间的 token exchange 失败。
诊断命令:
# 获取登录时的 token(从 ~/.docker/config.json 中提取 auth 字段,base64 解码) echo "YWRtaW46SGFyYm9yMTIz" | base64 -d # 输出 admin:Harbor123 # 手动请求 token curl -k "https://harbor-prod.internal/service/token?service=harbor-registry&scope=repository:library/nginx:push,pull" # 若返回 401,说明 core 的 token service 未启用修复:检查harbor.yml中auth_mode: oidc是否误配(应为db_auth),或core容器是否因数据库连接失败而降级为只读模式。
5.4 第四层:扫描与 Trivy(占故障率 3%)
症状:镜像 push 成功,但 Web 界面显示“扫描中...”且永不结束
原因:Trivy adapter 无法连接 Trivy server,或镜像过大超时。
检查点:
docker logs harbor-trivy是否有connection refused;harbor.yml中trivy.ignore_unfixed: true是否开启(关闭可加速扫描);trivy.timeout: 5m是否过短(建议设为10m)。
终极验证法:
# 在 core 容器内直接调用 Trivy API docker exec -it harbor-core curl -X POST http://trivy-adapter:8080/api/v1/scans \ -H "Content-Type: application/json" \ -d '{"artifact_digest":"sha256:abc123","artifact_repository":"library/nginx"}'若返回{"code":500,"message":"timeout"},则需调大trivy.timeout并重启。
我的个人经验:90% 的 Harbor 故障可在 5 分钟内定位,关键在于按层排查,不跳步。曾有个故障耗时 3 小时,最后发现是
harbor.yml中https.port: 443被误写为https.port: "443"(字符串类型),导致 nginx 配置生成失败,但日志无明确报错。解决方案:每次修改harbor.yml后,运行./prepare手动检查配置生成是否成功。
6. 运维进阶:自动化巡检与容量预测的实战脚本
Harbor 上线后,运维不能只靠人工点检。我们编写了一套 Bash + Python 巡检脚本,每日凌晨 2 点自动执行,结果邮件发送至运维群。以下是核心模块:
6.1 存储容量预测脚本(Python)
#!/usr/bin/env python3 # capacity_predict.py import requests import json from datetime import datetime, timedelta # Harbor API 认证 HARBOR_URL = "https://harbor-prod.internal" USER = "admin" PASS = "Harbor123" def get_storage_usage(): """获取当前存储使用量(单位:GB)""" resp = requests.get(f"{HARBOR_URL}/api/v2.0/statistics", auth=(USER, PASS), verify=False) data = resp.json() return data["storage"]["used"] / (1024**3) # 转 GB def predict_growth(days=30): """基于过去 7 天日均增长,预测未来 30 天用量""" # 实际中从 Prometheus 获取历史数据,此处简化为模拟 daily_avg = 2.3 # GB/天,从 Grafana 获取 current = get_storage_usage() future = current + daily_avg * days threshold = 450 # 预警阈值(GB) if future > threshold: print(f"⚠️ 预警:30 天后存储将达 {future:.1f}GB,超阈值 {threshold}GB") print(f" 建议:立即清理 >90 天未拉取的镜像(执行 GC)") else: print(f"✅ 安全:30 天后存储预计 {future:.1f}GB,低于阈值") if __name__ == "__main__": predict_growth()为什么用日均增长而非线性回归?因为镜像增长受发布节奏影响大(如月底集中上线),日均值更稳健。该脚本已集成到 Zabbix,当预测值超阈值时自动创建工单。
6.2 自动化 GC 脚本(Bash)
#!/bin/bash # auto_gc.sh HARBOR_URL="https://harbor-prod.internal" ADMIN_USER="admin" ADMIN_PASS="Harbor123" # 获取所有项目 ID PROJECT_IDS=$(curl -k -s -u "$ADMIN_USER:$ADMIN_PASS" \ "$HARBOR_URL/api/v2.0/projects?page=1&page_size=100" | \ jq -r '.[] | select(.name != "library") | .project_id') for pid in $PROJECT_IDS; do echo "🔄 执行项目 $pid 的 GC..." # 触发 GC(仅删除未引用的 blob) curl -k -X POST -u "$ADMIN_USER:$ADMIN_PASS" \ "$HARBOR_URL/api/v2.0/system/gc/schedule" \ -H "Content-Type: application/json" \ -d '{"schedule":{"type":"Manual"}}' > /dev/null # 等待 GC 完成(轮询状态) for i in {1..30}; do STATUS=$(curl -k -s -u "$ADMIN_USER:$ADMIN_PASS" \ "$HARBOR_URL/api/v2.0/system/gc" | jq -r '.status') if [[ "$STATUS" == "completed" ]]; then echo "✅ 项目 $pid GC 完成" break fi sleep 10 done done注意:Harbor 的 GC 默认只清理未被任何 manifest 引用的 blob,不会删除镜像标签。若要彻底清理旧标签,需先调用
DELETE /api/v2.0/projects/{project_id}/repositories/{repository_name}/artifacts/{reference}/tags/{tag},再执行 GC。我们将其封装为cleanup-old-tags.sh,配合jq筛选created_at < $(date -d '90 days ago' +%Y-%m-%dT%H:%M:%S)的标签。
6.3 证书续期自动化(Certbot + Harbor)
Harbor 证书有效期通常 365 天,手动续期易遗漏。我们用 Certbot 自动续期:
# certbot-renew.sh certbot renew --pre-hook "docker stop harbor-nginx" \ --post-hook "docker start harbor-nginx && \ cp /etc/letsencrypt/live/harbor-prod.internal/fullchain.pem /data/cert/harbor.crt && \ cp /etc/letsencrypt/live/harbor-prod.internal/privkey.pem /data/cert/harbor.key && \ docker restart harbor-nginx"关键点:
--pre-hook停止 nginx 避免端口占用,--post-hook中的docker restart harbor-nginx会重新加载证书。Harbor 的 nginx 配置支持热重载,但harbor-nginx容器本身需重启才能读取新证书文件。
7. 性能调优:从 100 并发到 2000 并发的参数实测
Harbor 默认配置仅支持约 300 并发 pull,某次大促前压测发现:当并发数升至 800 时,registry容器 CPU 达 100%,core容器响应延迟超 5s。我们通过四层调优将并发能力提升至 2000+:
7.1 Registry 层:调整 Golang 运行时参数
在harbor.yml的registry部分添加:
registry: version: 2.8.3 # 增加最大打开文件数 max_open_files: 65536 # 调整 GOGC(垃圾回收阈值) env: GOGC: "200" # 默认 100,提高到 200 减少 GC 频率 GOMAXPROCS: "8" # 设置为 CPU 核数实测效果:GOGC 从 100 调至 200 后,800 并发下 GC 暂停时间从 120ms 降至 45ms;
max_open_files提升后,Too many open files错误归零。
7.2 Core 层:数据库连接池优化
Harbor 的core服务使用 PostgreSQL,其连接池默认仅 10 个。在harbor.yml中:
database: max_idle_conns: 50 max_open_conns: 100 conn_max_lifetime: 1h为什么 max_open_conns 设为 100?因为每个并发请求至少占用 1 个连接,2000 并发需 2000 连接,但 Harbor 的连接复用率高,实测 100 连接即可支撑 2000 并发。超过此值反而因上下文切换增加延迟。
7.3 Nginx 层:反向代理缓冲区调优
修改common/config/nginx/nginx.conf(在install.sh后修改,重启 nginx):
upstream core { server core:8080; keepalive 32; # 启用长连接 } server { # 增大缓冲区 client_max_body_size 10G; proxy_buffering on; proxy_buffer_size 128k; proxy_buffers 8 256k; proxy_busy_buffers_size