一、核心定位
本文作为GitOps环境搭建系列的第九篇,聚焦容器镜像仓库Harbor的部署与配置。Harbor是由CNCF孵化而成的企业级开源Registry项目,提供完整的镜像存储、签名、扫描和分发能力。
在GitOps环境中,Harbor扮演”镜像存储中枢”角色,作为GitOps流程的镜像仓库环节,接收来自Tekton构建的镜像,并为ArgoCD提供可信的镜像源。Harbor与Gitea、Tekton、ArgoCD协同工作,形成完整的”代码→构建→镜像→部署”自动化流水线。
二、部署前置检查
部署前需验证K3s集群状态及前序组件运行情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| kubectl get nodes
kubectl get pods -n postgres
kubectl get pods -n redis
kubectl get pods -n kube-system -l app=traefik
kubectl get pods -n cert-manager
nslookup harbor.example.io nslookup notary.example.io
|
前置条件检查清单:
三、准备Harbor数据库
3.1 创建Harbor数据库
1 2 3 4
| kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "CREATE DATABASE harbor;" kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "CREATE USER harbor WITH PASSWORD 'harbor123';" kubectl exec -it postgres-0 -n postgres -- psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE harbor TO harbor;"
|
3.2 创建Harbor命名空间
1 2
| kubectl create namespace harbor
|
四、配置Harbor证书
4.1 创建Harbor证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: harbor-cert namespace: harbor spec: secretName: harbor-tls-secret issuerRef: name: selfsigned-cluster-issuer kind: ClusterIssuer commonName: harbor.example.io dnsNames: - harbor.example.io - notary.example.io duration: 2160h renewBefore: 360h privateKey: algorithm: RSA size: 2048 usages: - server auth
|
4.2 应用证书配置
1 2 3 4 5 6
| kubectl apply -f harbor-certificate.yaml
kubectl get certificate -n harbor kubectl describe certificate harbor-cert -n harbor
|
五、标准化部署Harbor
5.1 添加Helm仓库
1 2 3
| helm repo add harbor https://helm.goharbor.io --force-update helm repo update
|
5.2 创建Harbor配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
expose: type: ingress tls: enabled: true certSource: secret secret: secretName: "harbor-tls-secret" notarySecretName: "harbor-tls-secret" ingress: hosts: core: harbor.example.io notary: notary.example.io annotations: kubernetes.io/ingress.class: "traefik" traefik.ingress.kubernetes.io/router.tls: "true" traefik.ingress.kubernetes.io/router.entrypoints: websecure
externalURL: https://harbor.example.io
harborAdminPassword: "HarborAdmin123!"
persistence: enabled: true resourcePolicy: "keep" persistentVolumeClaim: registry: storageClass: "local-path" accessMode: ReadWriteOnce size: 100Gi chartmuseum: storageClass: "local-path" accessMode: ReadWriteOnce size: 5Gi jobservice: storageClass: "local-path" accessMode: ReadWriteOnce size: 5Gi trivy: storageClass: "local-path" accessMode: ReadWriteOnce size: 5Gi
database: type: external external: host: "postgres.postgres.svc.cluster.local" port: "5432" username: "harbor" password: "harbor123" coreDatabase: "harbor" clairDatabase: "harbor_clair" notaryServerDatabase: "harbor_notary_server" notarySignerDatabase: "harbor_notary_signer"
redis: type: external external: addr: "redis.redis.svc.cluster.local:6379" password: "redis123456"
chartmuseum: enabled: true resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
trivy: enabled: true resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "500m"
nginx: resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"
portal: resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"
core: resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
jobservice: resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
registry: registry: resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
notary: enabled: true server: resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" signer: resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m"
|
5.3 部署Harbor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| helm install harbor harbor/harbor \ --namespace harbor \ --version 1.13.2 \ -f harbor-values.yaml
helm install harbor harbor/harbor \ --namespace harbor \ --version 1.13.2 \ --set expose.type=ingress \ --set expose.tls.enabled=true \ --set expose.tls.secret.secretName=harbor-tls-secret \ --set expose.ingress.hosts.core=harbor.example.io \ --set expose.ingress.hosts.notary=notary.example.io \ --set externalURL=https://harbor.example.io \ --set harborAdminPassword=HarborAdmin123! \ --set persistence.enabled=true \ --set persistence.persistentVolumeClaim.registry.storageClass=local-path \ --set persistence.persistentVolumeClaim.registry.size=100Gi \ --set database.type=external \ --set database.external.host=postgres.postgres.svc.cluster.local \ --set database.external.port=5432 \ --set database.external.username=harbor \ --set database.external.password=harbor123 \ --set redis.type=external \ --set redis.external.addr=redis.redis.svc.cluster.local:6379 \ --set redis.external.password=redis123456 \ --set chartmuseum.enabled=true \ --set trivy.enabled=true \ --set notary.enabled=true
|
六、验证部署结果
6.1 验证组件状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| kubectl get pods -n harbor -w
kubectl get svc -n harbor
kubectl get ingress -n harbor
kubectl get certificate -n harbor
kubectl get pvc -n harbor
|
6.2 测试访问功能
1 2 3 4 5 6 7 8 9 10 11
| sleep 120
curl -k https://harbor.example.io
kubectl logs -n harbor -l app=harbor --tail=50
curl -k https://notary.example.io
|
6.3 初始化Harbor
- 浏览器访问:
https://harbor.example.io
- 用户名:
admin
- 密码:
HarborAdmin123!
- 首次登录后立即修改密码
- 创建项目(如
gitops-demo)
七、配置容器运行时访问
7.1 Docker客户端配置
1 2 3 4 5 6 7 8 9 10
| kubectl get secret harbor-tls-secret -n harbor -o jsonpath='{.data.ca\.crt}' | base64 --decode > harbor-ca.crt
sudo mkdir -p /etc/docker/certs.d/harbor.example.io sudo cp harbor-ca.crt /etc/docker/certs.d/harbor.example.io/ca.crt sudo systemctl restart docker
docker login harbor.example.io -u admin -p HarborAdmin123!
|
7.2 Containerd配置(K3s节点)
1 2 3 4
| sudo mkdir -p /etc/containerd/certs.d/harbor.example.io sudo cp harbor-ca.crt /etc/containerd/certs.d/harbor.example.io/ca.crt sudo systemctl restart containerd
|
7.3 测试镜像推送
1 2 3 4 5 6 7 8
| docker pull alpine:latest
docker tag alpine:latest harbor.example.io/gitops-demo/alpine:latest
docker push harbor.example.io/gitops-demo/alpine:latest
|
八、Harbor与GitOps全链路集成
完成Harbor部署后,GitOps环境搭建系列已具备完整的端到端交付能力。以下阐述Harbor与系列中其他核心组件的联动关系。
8.1 全链路组件矩阵
| 组件 |
职责 |
在GitOps链路中的角色 |
| Gitea |
代码托管与版本控制 |
开发者推送代码的单一可信数据源 |
| Tekton |
云原生CI/CD流水线引擎 |
监听代码变更,构建镜像并推送至Harbor |
| Harbor |
容器镜像仓库与安全扫描 |
存储签名镜像,提供可信镜像分发 |
| ArgoCD |
GitOps持续部署控制平面 |
监听Harbor镜像Tag变化,自动同步至K3s |
8.2 完整流水线联动流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ┌─────────────────────────────────────────────────────────────────┐ │ GitOps 完整链路 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ① 开发者 ──push──▶ Gitea (Git仓库) │ │ │ │ ② Tekton Pipeline ──webhook触发──▶ 克隆代码 │ │ │ │ ③ Tekton Pipeline ──构建──▶ Docker镜像 │ │ │ │ │ │ docker push │ │ ▼ │ │ ④ Harbor (镜像仓库) ◀── 推送镜像 │ │ │ • 存储镜像bits │ │ │ • Trivy CVE扫描 │ │ │ • Notary镜像签名(可选) │ │ │ │ ⑤ ArgoCD Application ──监听镜像Tag变化──▶ 检测到新镜像 │ │ │ │ │ │ 更新Deployment镜像Tag │ │ ▼ │ │ ⑥ K3s集群 ──kubectl apply──▶ 新Pod以新镜像启动 │ │ │ └─────────────────────────────────────────────────────────────────┘
|
8.3 Harbor与Gitea、Tekton、ArgoCD联动
Harbor + Gitea(认证集成)
Harbor与Gitea可共用外部认证源(如LDAP/OIDC),实现统一身份管理:
1 2 3 4 5 6 7 8
| harbor-core: config: auth_mode: "oidc_auth" oidc_name: "Gitea OIDC" oidc_endpoint: "https://gitea.example.io/oauth" oidc_client_id: "harbor-client" oidc_secret: "harbor-oidc-secret"
|
Harbor + Tekton(镜像构建推送)
Tekton Pipeline执行构建并将镜像推送至Harbor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| spec: steps: - name: git-clone image: alpine/git script: | git clone $(params.REPO_URL) $(params.REPO_DIR)
- name: build-image image: docker:latest script: | docker build -t $(params.IMAGE):$(params.TAG) $(params.REPO_DIR) docker tag $(params.IMAGE):$(params.TAG) \ harbor.example.io/gitops-demo/$(params.IMAGE):$(params.TAG)
- name: push-image image: docker:latest script: | docker login harbor.example.io -u $(params.HARBOR_USER) -p $(params.HARBOR_PASS) docker push harbor.example.io/gitops-demo/$(params.IMAGE):$(params.TAG)
|
Harbor + ArgoCD(镜像驱动部署)
ArgoCD Image Updater自动轮询Harbor镜像仓库,发现新Tag后更新配置并触发同步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: gitops-demo-app annotations: argocd-image-updater.argoproj.io/image-list: | demo=harbor.example.io/gitops-demo/demo-image argocd-image-updater.argoproj.io/demo.update-strategy: latest argocd-image-updater.argoproj.io/write-back-method: git spec: source: repoURL: https://github.com/your-org/gitops-configs.git path: apps/demo-app targetRevision: main destination: server: https://kubernetes.default.svc namespace: gitops-demo
|
8.4 安全集成要点
- 镜像签名链路:Tekton构建 → Notary签名 → 推送Harbor → 部署时验签,全链路可信;
- 漏洞扫描卡点:Harbor Trivy扫描未通过的CVE镜像(Critical/High),可配置阻止推送;
- 认证打通:Harbor与Gitea共用OIDC认证,实现统一身份管理;
- 网络隔离:Harbor仅通过Traefik 443端口暴露,K3s节点通过内部网络拉取镜像。
九、服务访问方式
9.1 集群内访问
- Web界面:
harbor-core.harbor.svc.cluster.local
- Registry API:
harbor-registry.harbor.svc.cluster.local
- ChartMuseum:
harbor-chartmuseum.harbor.svc.cluster.local
9.2 集群外访问
- Web界面:
https://harbor.example.io
- Registry:
harbor.example.io(Docker push/pull)
- Notary:
https://notary.example.io
十、日常运维命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| kubectl get all -n harbor
kubectl logs -f deployment/harbor-core -n harbor kubectl logs -f deployment/harbor-registry -n harbor kubectl logs -f deployment/harbor-portal -n harbor
kubectl rollout restart deployment -n harbor
kubectl exec -n harbor $(kubectl get pod -n harbor -l component=registry -o jsonpath='{.items[0].metadata.name}') -- tar czf /tmp/registry-backup.tar.gz /storage kubectl cp harbor/$(kubectl get pod -n harbor -l component=registry -o jsonpath='{.items[0].metadata.name}'):/tmp/registry-backup.tar.gz ./registry-backup-$(date +%Y%m%d).tar.gz
kubectl top pods -n harbor
|
十一、常见问题修复
| 问题现象 |
排查方向 |
修复方案 |
| Harbor无法启动 |
数据库连接失败 |
检查PostgreSQL连接,验证用户名密码 |
| 证书错误 |
证书配置/Secret |
检查cert-manager状态,验证证书Secret |
| 镜像推送失败 |
认证/网络 |
检查Docker登录状态,验证网络连通性 |
| PVC无法绑定 |
存储类/磁盘空间 |
检查local-path存储类,确认节点有足够空间 |
| Trivy扫描失败 |
网络/资源 |
检查Trivy网络连通性,增加资源限制 |
| Notary服务异常 |
证书/配置 |
检查Notary证书配置,验证域名解析 |
十二、配置参考
所有Harbor配置文件和部署脚本请参考:
https://gitee.com/Chemmy/kube-template/tree/master/devops/Harbor
该目录包含:
- Harbor Helm values配置
- 证书和路由配置
- 数据库初始化脚本
- 生产环境优化配置
- 集成配置示例
总结
本文完成了Harbor在K3s集群中的标准化部署,实现了镜像仓库的完整功能。Harbor作为GitOps环境的镜像存储中枢,为自动化构建和部署提供了可靠的镜像管理能力。
部署完成后,建议配置Tekton Pipeline实现自动镜像构建和推送,配置ArgoCD实现镜像更新自动同步。至此,GitOps环境的所有核心组件已部署完成,形成了完整的自动化流水线。