news 2026/9/27 22:56:52

Harbor 私有镜像仓库部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Harbor 私有镜像仓库部署

Harbor 私有镜像仓库部署

一、方案概述

1.1 目标

在 K8s 高可用集群上,部署一套 Harbor 私有镜像仓库,具备:

  • 镜像存储:存储 Docker 镜像和 Helm Chart
  • 访问控制:用户认证、项目权限
  • HTTPS:Let’s Encrypt 泛域名证书
  • 持久化:Longhorn 分布式存储
  • 高可用:核心组件多副本
  • 外部访问:FRP + Ingress 从公网访问

1.2 技术选型

组件用途
Harbor Helm Chart部署 Harbor
Nginx Ingress Controller外部访问入口
Longhorn持久化存储
Let’s EncryptTLS 证书
FRP内网穿透

1.3 架构

text

外网用户 ↓ https://harbor.<域名>:40443 ↓ frps(vhost_https_port = 40443) ↓ frpc ↓ 内网 VIP:443 ↓ HAProxy ↓ Ingress Controller(TLS 终止) ↓ Harbor Service ↓ Harbor Pod(core、portal、registry、jobservice)

二、前置条件

2.1 集群状态

  • K8s 集群kubectl get nodes全部Ready
  • Nginx Ingress Controller 已部署
  • Longhorn 已部署,longhornStorageClass 就绪
  • FRP 已配置

2.2 存储要求

Harbor 需要 PVC 持久化数据。本文档使用Longhorn作为存储后端。

关键约束:

  • Harbor registry 组件不支持多副本共享 RWO 卷,所以registry和jobservice必须单副本。
  • Longhorn 卷默认 3 副本,如果节点磁盘空间紧张,可以降到 2 副本。
  • Longhorn 的storage-over-provisioning-percentage和storage-minimal-available-percentage需要提前调整,否则卷会因insufficient storage调度失败。

2.3 TLS 证书

需要泛域名证书*.<域名>。本文档使用acme.sh + Let’s Encrypt申请。

2.4 FRP 配置

frpc 需要加 HTTP 和 HTTPS 的 vhost 映射:

[harbor-http] type = http local_ip = <内网VIP> local_port = 80 custom_domains = harbor.<域名> [harbor-https] type = https local_ip = <内网VIP> local_port = 443 custom_domains = harbor.<域名>

三、申请 TLS 证书

3.1 安装 acme.sh

curl https://get.acme.sh | sh -s email=<邮箱> source ~/.bashrc

3.2 配置 DNS API

以阿里云为例:

export Ali_Key="<AccessKeyID>" export Ali_Secret="<AccessKeySecret>"

3.3 申请泛域名证书

acme.sh --issue --server letsencrypt --dns dns_ali --dnssleep 60 -d <域名> -d '*.<域名>'

解析:

  • --server letsencrypt:指定 Let’s Encrypt,不用 ZeroSSL。
  • --dnssleep 60:加完 TXT 记录后等 60 秒再验证。
  • -d <域名> -d '*.<域名>':同时申请根域名和泛域名。

证书路径:

~/.acme.sh/<域名>_ecc/fullchain.cer ~/.acme.sh/<域名>_ecc/<域名>.key

3.4 配置自动续期脚本

创建/root/update-tls-secrets.sh:

#!/bin/bash CERT_DIR="/root/.acme.sh/<域名>_ecc" NAMESPACES=("harbor" "argocd" "jenkins" "gitlab" "default") for ns in "${NAMESPACES[@]}"; do kubectl create secret tls <域名>-tls \ --cert="$CERT_DIR/fullchain.cer" \ --key="$CERT_DIR/<域名>.key" \ --namespace "$ns" \ --dry-run=client -o yaml | kubectl apply -f - done

加执行权限:

chmod +x /root/update-tls-secrets.sh

配置 acme.sh 续期回调:

acme.sh --install-cert -d <域名> --ecc --reloadcmd "/root/update-tls-secrets.sh"

四、安装 Harbor

4.1 添加 Helm 仓库

helm repo add harbor https://helm.goharbor.io helm repo update helm search repo harbor/harbor

如果helm.goharbor.io访问超时,从 GitHub 代理下载 chart:

curl -fsSL https://ghproxy.net/https://github.com/goharbor/harbor-helm/releases/download/v1.19.2/harbor-1.19.2.tgz -o harbor-1.19.2.tgz

4.2 创建命名空间

kubectl create namespace harbor

4.3 创建 TLS Secret

kubectl create secret tls <域名>-tls \ --cert=/root/.acme.sh/<域名>_ecc/fullchain.cer \ --key=/root/.acme.sh/<域名>_ecc/<域名>.key \ --namespace harbor

4.4 创建 values.yaml

expose: type: ingress tls: enabled: true certSource: secret secret: secretName: <域名>-tls notarySecretName: <域名>-tls ingress: hosts: core: harbor.<域名> className: nginx annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" externalURL: https://harbor.<域名>:40443 persistence: enabled: true resourcePolicy: "keep" persistentVolumeClaim: registry: storageClass: longhorn size: 15Gi database: storageClass: longhorn size: 20Gi redis: storageClass: longhorn size: 10Gi jobservice: storageClass: longhorn size: 10Gi trivy: storageClass: longhorn size: 10Gi harborAdminPassword: "<强密码>" core: replicas: 2 resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "2" memory: "2Gi" portal: replicas: 2 resources: requests: cpu: "200m" memory: "256Mi" limits: cpu: "1" memory: "1Gi" jobservice: replicas: 1 resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "2" memory: "2Gi" registry: replicas: 1 resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "2" memory: "2Gi" database: type: internal internal: resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "2" memory: "2Gi" redis: type: internal internal: resources: requests: cpu: "200m" memory: "256Mi" limits: cpu: "1" memory: "1Gi" trivy: enabled: true replicas: 1 resources: requests: cpu: "200m" memory: "512Mi" limits: cpu: "1" memory: "1Gi"

4.5 逐项解析

字段含义
expose.type: ingress用 Ingress 暴露
tls.enabled: true开启 HTTPS
tls.certSource: secret证书从 K8s Secret 读
tls.secret.secretNameTLS Secret 名字
ingress.hosts.coreHarbor 域名
proxy-body-size: "0"不限上传大小
proxy-read-timeout: "600"读超时 10 分钟
ssl-redirect: "true"HTTP 自动跳转 HTTPS
externalURL外部访问地址,带端口
persistence各组件 PVC 配置
harborAdminPasswordadmin 初始密码
core.replicas: 2core 双副本
portal.replicas: 2portal 双副本
jobservice.replicas: 1jobservice 单副本
registry.replicas: 1registry 单副本

关键点:

  • registry和jobservice必须单副本,因为它们的卷是 RWO,多副本会报Multi-Attach error。
  • externalURL必须带端口,因为外网访问是https://harbor.<域名>:40443。

4.6 安装 Harbor

helm install harbor harbor/harbor \ --namespace harbor \ -f /root/harbor-values.yaml

如果helm.goharbor.io不通,用本地 chart:

helm install harbor ./harbor-1.19.2.tgz \ --namespace harbor \ -f /root/harbor-values.yaml

4.7 观察 Pod 启动

kubectl get pods -n harbor -w

按Ctrl+C退出。

预期:

harbor-core-xxx 1/1 Running (2个) harbor-database-0 1/1 Running harbor-jobservice-xxx 1/1 Running harbor-portal-xxx 1/1 Running (2个) harbor-redis-0 1/1 Running harbor-registry-xxx 2/2 Running harbor-trivy-0 1/1 Running

五、验证 Harbor

5.1 查看 Pod 和 PVC

kubectl get pods -n harbor kubectl get pvc -n harbor kubectl get ingress -n harbor

预期:

  • 所有 PodRunning。
  • PVC 全部Bound,STORAGECLASS是longhorn。
  • Ingress 有harbor-ingress,域名harbor.<域名>。

5.2 测试 HTTPS 访问

curl -v https://harbor.<域名>:40443 2>&1 | grep "SSL certificate"

预期:

SSL certificate verify ok.

5.3 浏览器访问

https://harbor.<域名>:40443

用户名:admin
密码:你设置的强密码

第一次登录会要求修改密码。

5.4 创建项目

登录后,创建项目,比如library。

解析:

  • 项目是 Harbor 里镜像的组织单位。
  • 推送镜像时路径是harbor.<域名>:40443/library/<image>:<tag>。

六、配置 K8s 拉取 Harbor 镜像

6.1 配置 containerd 信任 Harbor

在每台节点上编辑/etc/containerd/config.toml,在registry.mirrors段加:

[plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.<域名>:40443"] endpoint = ["https://harbor.<域名>:40443"]

用 Ansible 批量推:

ansible k8s_cluster -i inventory.ini -m shell -a "grep -q 'registry.mirrors.\"harbor.<域名>:40443\"' /etc/containerd/config.toml || sed -i '/\[plugins.\"io.containerd.grpc.v1.cri\".registry.mirrors\]/a\ [plugins.\"io.containerd.grpc.v1.cri\".registry.mirrors\".\"harbor.<域名>:40443\"]\n endpoint = [\"https://harbor.<域名>:40443\"]' /etc/containerd/config.toml && systemctl restart containerd" -b

6.2 创建镜像拉取 Secret

kubectl create secret docker-registry harbor-secret \ --docker-server=harbor.<域名>:40443 \ --docker-username=admin \ --docker-password=<强密码> \ --namespace default

6.3 在 Deployment 里引用

spec: template: spec: imagePullSecrets: - name: harbor-secret containers: - name: myapp image: harbor.<域名>:40443/library/myapp:1.0

6.4 验证拉取

crictl pull harbor.<域名>:40443/library/nginx:latest

七、常见问题

7.1 Pod 卡在ImagePullBackOff

Harbor 镜像在docker.io/goharbor上,containerd 镜像加速应该能覆盖。如果拉不下来,手动拉取并打标签:

crictl pull docker.m.daocloud.io/goharbor/harbor-jobservice:v2.15.2 ctr -n k8s.io images tag docker.m.daocloud.io/goharbor/harbor-jobservice:v2.15.2 docker.m.daocloud.io/goharbor/harbor-jobservice:v2.15.2

如果某个节点拉不下来,从其他节点导出:

ctr -n k8s.io images export /tmp/jobservice.tar docker.m.daocloud.io/goharbor/harbor-jobservice:v2.15.2 scp /tmp/jobservice.tar root@<目标节点>:/tmp/ ctr -n k8s.io images import /tmp/jobservice.tar

7.2 registry 多副本时Multi-Attach error

原因:registry 用 RWO 卷,多副本无法共享。

解决方案:

  • registry.replicas: 1。
  • 或者改 Deployment 的更新策略为Recreate:
kubectl patch deployment -n harbor harbor-registry -p '{"spec":{"strategy":{"type":"Recreate"}}}'

7.3 PVC 绑不上,卷faulted或degraded

原因:Longhorn 卷调度失败。

排查:

kubectl get volumes.longhorn.io -n longhorn-system kubectl get volume.longhorn.io <volume-name> -n longhorn-system -o yaml | grep -A5 "type: Scheduled"

如果报insufficient storage:

kubectl patch settings.longhorn.io storage-over-provisioning-percentage -n longhorn-system --type=merge -p '{"value":"200"}' kubectl patch settings.longhorn.io storage-minimal-available-percentage -n longhorn-system --type=merge -p '{"value":"10"}'

然后触发副本重建:

kubectl get engines.longhorn.io -n longhorn-system | grep <volume-name> kubectl delete engine.longhorn.io <engine-name> -n longhorn-system

7.4 Harbor 登不上,报relation "properties" does not exist

原因:database 重建后,表没建。

解决方案:删掉 Harbor 和所有 PVC,重建。

helm uninstall harbor -n harbor kubectl delete pvc -n harbor --all kubectl delete namespace harbor kubectl create namespace harbor kubectl create secret tls <域名>-tls --cert=/root/.acme.sh/<域名>_ecc/fullchain.cer --key=/root/.acme.sh/<域名>_ecc/<域名>.key --namespace harbor helm install harbor harbor/harbor -n harbor -f /root/harbor-values.yaml

7.5 413 Request Entity Too Large

原因:Ingress 的proxy-body-size太小。

解决方案:设为"0",不限大小。

7.6 HTTPS 访问报证书错误

原因:证书链不完整,或 Secret 没配对。

排查:

kubectl get secret <域名>-tls -n harbor kubectl describe ingress -n harbor harbor-ingress | grep TLS

7.7 镜像拉取超时

Harbor 镜像在docker.io/goharbor上。如果拉不下来,配置 containerd 镜像加速,或手动导入。


八、常用操作

8.1 查看 Harbor 状态

kubectl get pods -n harbor kubectl get svc -n harbor kubectl get ingress -n harbor kubectl get pvc -n harbor

8.2 查看日志

kubectl logs -n harbor -l component=core --tail=100 kubectl logs -n harbor -l component=registry --tail=100 kubectl logs -n harbor -l component=database --tail=100

8.3 取 admin 密码

kubectl get secret -n harbor harbor-core -o jsonpath='{.data.HARBOR_ADMIN_PASSWORD}' | base64 -d echo

8.4 升级 Harbor

helm upgrade harbor harbor/harbor -n harbor -f /root/harbor-values.yaml

8.5 删除 Harbor

helm uninstall harbor -n harbor kubectl delete pvc -n harbor --all kubectl delete namespace harbor

警告:删除 PVC 会删除所有镜像数据,操作前先备份。


九、架构总结

9.1 组件清单

组件副本数作用
harbor-core2API 服务、认证
harbor-portal2Web UI
harbor-registry1镜像存储
harbor-jobservice1镜像复制、扫描任务
harbor-database1PostgreSQL 数据库
harbor-redis1缓存
harbor-trivy1镜像扫描

9.2 端口速查

端口用途
40443外网 HTTPS 入口
40080外网 HTTP 入口
443内网 HAProxy HTTPS
80内网 HAProxy HTTP
30443Ingress Controller HTTPS NodePort
30080Ingress Controller HTTP NodePort

9.3 已知隐患

隐患影响解决方案
registry/jobservice 单副本节点故障服务中断需要 RWX 存储才能多副本
Longhorn 空间调度保守卷报insufficient storage改 over-provisioning 和 minimal-available
证书手动更新续期后 Secret 需更新配 acme.sh 续期回调脚本
database 重建后表没建Harbor 登不上删掉 Harbor 和 PVC,重建

十、总结

这套 Harbor 基于官方 Helm Chart 部署,提供了:

  • 镜像存储:私有 Docker 镜像仓库
  • 访问控制:用户认证和项目权限
  • 外部访问:FRP + Ingress 从公网访问
  • HTTPS:Let’s Encrypt 泛域名证书
  • 持久化:Longhorn 分布式存储
  • 高可用:core、portal 多副本

部署中最容易踩的坑:

  1. chart 拉取超时:用 GitHub 代理下载本地安装。
  2. registry 多副本 Multi-Attach:registry 和 jobservice 必须单副本。
  3. 卷容量超过节点可用空间:registry 卷不要超过 20Gi。
  4. Longhorn 空间调度保守:改storage-over-provisioning-percentage=200和storage-minimal-available-percentage=10。
  5. Harbor database 表没建:删掉 Harbor 和所有 PVC,重建。
  6. HTTPS 证书链不完整:用fullchain.cer。
  7. externalURL 不带端口:外网访问带 40443,externalURL必须包含端口。

解决了这七个问题,Harbor 就能稳定运行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 22:56:47

企业获客软件导出限额测评方法与数据:9款产品对比

这篇按统一维度测了9款企业获客软件的每日导出次数和条数限制。为什么每日导出限额对团队规模这么关键&#xff1f;如果是1人单干&#xff0c;每天要用的名单量本身有限&#xff0c;大多数平台的每日额度基本都够用&#xff0c;导出限额很少会成为瓶颈。但换成5人以上的团队&am…

作者头像 李华
网站建设 2026/9/27 22:55:15

初学者怎么用docker打包代码

如果你是处学者&#xff0c;连docker是什么都不知道&#xff0c;那么我这篇博客将直接上手docker&#xff0c;帮助打包第一个项目代码。首先我们先要明白docker它是什么东西&#xff0c;主要干什么。初学者理解docker只要知道他是一个可以让你的代码放在别人的电脑上也能顺利运…

作者头像 李华
网站建设 2026/9/27 22:54:59

混沌拓扑学(HDT)演化论真相

副标题&#xff1a; 别再迷信"物竞天择"——自然选择从不"选中"谁&#xff0c;它只是"剩下"了谁。从随机突变到技术弥补&#xff0c;重新理解演化论、自然选择与幸存者偏差。演化并非简单遵循物竞天择&#xff0c;适者生存.SEO摘要&#xff1a; …

作者头像 李华
网站建设 2026/9/27 22:54:07

Python入门:零基础3天学会办公自动化,工作效率翻倍

在二零二六年这个把效率追求达到极致的职场环境里面, 假设你依旧还在使用手动复制粘贴 Excel 表格的方式处理数据, 还在逐个修改 Word 文档名称这样操作, 那么这种行为真的就是在毫无意义地浪费生命时光。办公自动化这一项技术能力, 目前已经不再属于程序员群体所独有的专业技能…

作者头像 李华
网站建设 2026/9/27 22:52:16

集成pageOffice到springboot项目关键步骤

集成pageOffice到springboot项目关键步骤 PageOffice&#xff08;卓正软件&#xff09;是国内常用的Web 在线 Office 文档编辑控件&#xff0c;用于 OA、政务、ERP 等 B/S 系统&#xff0c;在网页里直接打开、编辑、保存 Word/Excel/PPT&#xff0c;不需要下载上传文件&#xf…

作者头像 李华
网站建设 2026/9/27 22:51:52

高频核心硬件面试2026—通用电子方向深度精讲

本文为专栏内部精讲内容,聚焦硬件工程师面试中最具区分度的高频问题,每题配套考察点剖析、标准解法、易错项提醒、工程案例与关键计算,帮助读者在2026届招聘季中展现系统级工程思维与实战功底。 对于硬件工程师而言,面试是展现技术深度、工程严谨性与问题解决能力的核心舞…

作者头像 李华