参考链接:

官方:https://goharbor.io/docs/2.7.0/install-config/harbor-ha-helm/

https://blog.51cto.com/lidabai/5195706

1、先决条件

  • Kubernetes 集群 1.10+
  • 头盔 2.8.0+
  • 高可用入口控制器(Harbor 不管理外部端点)
  • 高可用 PostgreSQL 9.6+(Harbor 不处理数据库 HA 的部署)
  • 高可用Redis(Harbor不处理Redis的HA部署)
  • 可以跨节点或外部对象存储共享的 PVC

2、下载Chart并部署

  1. # 添加仓库(helm repo add repoName repoURL)
  2. helm repo add harbor https://helm.goharbor.io
  3. # 查看添加的仓库
  4. helm repo list
  5. # 删除已经添加的仓库(helm repo remove repoName)
  6. # 将本地所添加的chart仓库的最新信息缓存到本地(helm repo update)
  7. # helm列出所有版本:
  8. helm search repo harbor -l
  9. # helm 下载指定版本:
  10. # helm fetch harbor/harbor --version 1.7.2
  11. helm fetch harbor/harbor --untar # 拉取最新并解压

或者使用一下方式下载chart到不本地解压

  1. $ helm search repo harbor # 搜索chart包
  2. NAME CHART VERSION APP VERSION DESCRIPTION
  3. harbor/harbor 1.8.2 2.4.2 An open source trusted cloud native registry th...
  4. $ helm pull harbor/harbor # 下载Chart包
  5. $ tar zxvf harbor-1.8.2.tgz # 解压包
  • 这里可以使用使用默认配置直接部署
  1. helm install my-harbor harbor/
  • 这种方式不建议
  • 建议使用单独的名称空间和外部储存进行部署

3、创建harbor名称空间

  1. kubectl create namespace harbor

4、修改values.yaml配置

  • chart目录结构
  1. [root@k8s-node1 harbor]# ll
  2. 总用量 256
  3. drwxr-xr-x 2 root root 36 12 30 17:28 cert
  4. -rw-r--r-- 1 root root 569 12 30 17:28 Chart.yaml
  5. drwxr-xr-x 2 root root 58 12 30 17:28 conf
  6. -rw-r--r-- 1 root root 11357 12 30 17:28 LICENSE
  7. -rw-r--r-- 1 root root 204387 12 30 17:28 README.md
  8. drwxr-xr-x 16 root root 4096 12 30 17:28 templates
  9. -rw-r--r-- 1 root root 34194 12 30 17:28 values.yaml
  • values.yaml配置
  1. # 修改前建议先备份配置文件
  2. cp values.yaml valies.yaml-bak
  3. cat values.yaml
  4. expose:
  5. type: nodePort # 对外暴露方式(默认使用ingress),这里没有ingress环境使用NodePort
  6. tls:
  7. enabled: false # 关闭tls安全加密认证(如果开启需要配置证书)
  8. certSource: auto
  9. auto:
  10. commonName: ""
  11. secret:
  12. secretName: ""
  13. notarySecretName: ""
  14. ingress:
  15. hosts:
  16. core: core.harbor.domain
  17. notary: notary.harbor.domain
  18. controller: default
  19. kubeVersionOverride: ""
  20. className: ""
  21. annotations:
  22. ingress.kubernetes.io/ssl-redirect: "true"
  23. ingress.kubernetes.io/proxy-body-size: "0"
  24. nginx.ingress.kubernetes.io/ssl-redirect: "true"
  25. nginx.ingress.kubernetes.io/proxy-body-size: "0"
  26. notary:
  27. annotations: {}
  28. labels: {}
  29. harbor:
  30. annotations: {}
  31. labels: {}
  32. clusterIP:
  33. name: harbor
  34. annotations: {}
  35. ports:
  36. httpPort: 80
  37. httpsPort: 443
  38. notaryPort: 4443
  39. nodePort:
  40. name: harbor
  41. ports:
  42. http:
  43. port: 80
  44. nodePort: 30002
  45. https:
  46. port: 443
  47. nodePort: 30003
  48. notary:
  49. port: 4443
  50. nodePort: 30004
  51. loadBalancer:
  52. name: harbor
  53. IP: ""
  54. ports:
  55. httpPort: 80
  56. httpsPort: 443
  57. notaryPort: 4443
  58. annotations: {}
  59. sourceRanges: []
  60. externalURL: https://core.harbor.domain # 使用nodePort且关闭tls认证,则此处需要修改为http协议和expose.nodePort.ports.http.nodePort指定的端口号,IP即为kubernetes的节点IP地址
  61. externalURL: http://192.168.6.31:30002
  62. internalTLS:
  63. enabled: false
  64. certSource: "auto"
  65. trustCa: ""
  66. core:
  67. secretName: ""
  68. crt: ""
  69. key: ""
  70. jobservice:
  71. secretName: ""
  72. crt: ""
  73. key: ""
  74. registry:
  75. secretName: ""
  76. crt: ""
  77. key: ""
  78. portal:
  79. secretName: ""
  80. crt: ""
  81. key: ""
  82. chartmuseum:
  83. secretName: ""
  84. crt: ""
  85. key: ""
  86. trivy:
  87. secretName: ""
  88. crt: ""
  89. key: ""
  90. ipFamily:
  91. ipv6:
  92. enabled: true
  93. ipv4:
  94. enabled: true
  95. # 持久化存储配置部分
  96. persistence:
  97. enabled: true # 开启持久化存储
  98. resourcePolicy: "keep"
  99. persistentVolumeClaim: # 定义Harbor各个组件的PVC持久卷部分
  100. registry: # registry组件(持久卷)配置部分
  101. existingClaim: ""
  102. storageClass: "managed-nfs-storage" # StorageClass,其它组件同样配置
  103. subPath: ""
  104. accessMode: ReadWriteMany # 卷的访问模式,需要修改为ReadWriteMany,允许多个组件读写,否则有的组件无法读取其它组件的数据
  105. size: 5Gi
  106. annotations: {}
  107. chartmuseum: # chartmuseum组件(持久卷)配置部分
  108. existingClaim: ""
  109. storageClass: "managed-nfs-storage" #修改,同上
  110. subPath: ""
  111. accessMode: ReadWriteOnce
  112. size: 5Gi
  113. annotations: {}
  114. jobservice:
  115. jobLog:
  116. existingClaim: ""
  117. storageClass: ""
  118. subPath: ""
  119. accessMode: ReadWriteOnce
  120. size: 1Gi
  121. annotations: {}
  122. scanDataExports:
  123. existingClaim: ""
  124. storageClass: ""
  125. subPath: ""
  126. accessMode: ReadWriteOnce
  127. size: 1Gi
  128. annotations: {}
  129. database: # PostgreSQl数据库组件(持久卷)配置部分
  130. existingClaim: ""
  131. storageClass: "managed-nfs-storage" # 同上
  132. subPath: ""
  133. accessMode: ReadWriteMany # 同上
  134. size: 1Gi
  135. annotations: {}
  136. redis: # Redis缓存组件(持久卷)配置部分
  137. existingClaim: ""
  138. storageClass: "managed-nfs-storage" # 同上
  139. subPath: ""
  140. accessMode: ReadWriteMany # 同上
  141. size: 1Gi
  142. annotations: {}
  143. trivy: # Trity漏洞扫描插件(持久卷)配置部分
  144. existingClaim: ""
  145. storageClass: "managed-nfs-storage"
  146. subPath: ""
  147. accessMode: ReadWriteMany
  148. size: 5Gi
  149. annotations: {}
  150. imageChartStorage:
  151. disableredirect: false
  152. type: filesystem
  153. filesystem:
  154. rootdirectory: /storage
  155. azure:
  156. accountname: accountname
  157. accountkey: base64encodedaccountkey
  158. container: containername
  159. existingSecret: ""
  160. gcs:
  161. bucket: bucketname
  162. encodedkey: base64-encoded-json-key-file
  163. existingSecret: ""
  164. useWorkloadIdentity: false
  165. s3:
  166. region: us-west-1
  167. bucket: bucketname
  168. swift:
  169. authurl: https://storage.myprovider.com/v3/auth
  170. username: username
  171. password: password
  172. container: containername
  173. oss:
  174. accesskeyid: accesskeyid
  175. accesskeysecret: accesskeysecret
  176. region: regionname
  177. bucket: bucketname
  178. imagePullPolicy: IfNotPresent
  179. imagePullSecrets:
  180. updateStrategy:
  181. type: RollingUpdate
  182. logLevel: info
  183. harborAdminPassword: "Harbor12345" # admin初始密码,不需要修改(生产环境建议修改)
  184. caSecretName: ""
  185. secretKey: "not-a-secure-key"
  186. existingSecretSecretKey: ""
  187. proxy:
  188. httpProxy:
  189. httpsProxy:
  190. noProxy: 127.0.0.1,localhost,.local,.internal
  191. components:
  192. - core
  193. - jobservice
  194. - trivy
  195. enableMigrateHelmHook: false
  196. nginx:
  197. image:
  198. repository: goharbor/nginx-photon
  199. tag: v2.7.0
  200. serviceAccountName: ""
  201. automountServiceAccountToken: false
  202. replicas: 1
  203. revisionHistoryLimit: 10
  204. nodeSelector: {}
  205. tolerations: []
  206. affinity: {}
  207. podAnnotations: {}
  208. priorityClassName:
  209. portal:
  210. image:
  211. repository: goharbor/harbor-portal
  212. tag: v2.7.0
  213. serviceAccountName: ""
  214. automountServiceAccountToken: false
  215. replicas: 1
  216. revisionHistoryLimit: 10
  217. nodeSelector: {}
  218. tolerations: []
  219. affinity: {}
  220. podAnnotations: {}
  221. priorityClassName:
  222. core:
  223. image:
  224. repository: goharbor/harbor-core
  225. tag: v2.7.0
  226. serviceAccountName: ""
  227. automountServiceAccountToken: false
  228. replicas: 1
  229. revisionHistoryLimit: 10
  230. startupProbe:
  231. enabled: true
  232. initialDelaySeconds: 10
  233. nodeSelector: {}
  234. tolerations: []
  235. affinity: {}
  236. podAnnotations: {}
  237. serviceAnnotations: {}
  238. secret: ""
  239. secretName: ""
  240. xsrfKey: ""
  241. priorityClassName:
  242. artifactPullAsyncFlushDuration:
  243. gdpr:
  244. deleteUser: false
  245. jobservice:
  246. image:
  247. repository: goharbor/harbor-jobservice
  248. tag: v2.7.0
  249. replicas: 1
  250. revisionHistoryLimit: 10
  251. serviceAccountName: ""
  252. automountServiceAccountToken: false
  253. maxJobWorkers: 10
  254. jobLoggers:
  255. - file
  256. nodeSelector: {}
  257. tolerations: []
  258. affinity: {}
  259. podAnnotations: {}
  260. secret: ""
  261. priorityClassName:
  262. registry:
  263. serviceAccountName: ""
  264. automountServiceAccountToken: false
  265. registry:
  266. image:
  267. repository: goharbor/registry-photon
  268. tag: v2.7.0
  269. controller:
  270. image:
  271. repository: goharbor/harbor-registryctl
  272. tag: v2.7.0
  273. replicas: 1
  274. revisionHistoryLimit: 10
  275. nodeSelector: {}
  276. tolerations: []
  277. affinity: {}
  278. podAnnotations: {}
  279. priorityClassName:
  280. secret: ""
  281. relativeurls: false
  282. credentials:
  283. username: "harbor_registry_user"
  284. password: "harbor_registry_password"
  285. existingSecret: ""
  286. middleware:
  287. enabled: false
  288. type: cloudFront
  289. cloudFront:
  290. baseurl: example.cloudfront.net
  291. keypairid: KEYPAIRID
  292. duration: 3000s
  293. ipfilteredby: none
  294. privateKeySecret: "my-secret"
  295. upload_purging:
  296. enabled: true
  297. age: 168h
  298. interval: 24h
  299. dryrun: false
  300. chartmuseum:
  301. enabled: true
  302. serviceAccountName: ""
  303. automountServiceAccountToken: false
  304. absoluteUrl: false
  305. image:
  306. repository: goharbor/chartmuseum-photon
  307. tag: v2.7.0
  308. replicas: 1
  309. revisionHistoryLimit: 10
  310. nodeSelector: {}
  311. tolerations: []
  312. affinity: {}
  313. podAnnotations: {}
  314. priorityClassName:
  315. indexLimit: 0
  316. trivy:
  317. enabled: true
  318. image:
  319. repository: goharbor/trivy-adapter-photon
  320. tag: v2.7.0
  321. serviceAccountName: ""
  322. automountServiceAccountToken: false
  323. replicas: 1
  324. debugMode: false
  325. vulnType: "os,library"
  326. severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
  327. ignoreUnfixed: false
  328. insecure: false
  329. gitHubToken: ""
  330. skipUpdate: false
  331. offlineScan: false
  332. securityCheck: "vuln"
  333. timeout: 5m0s
  334. resources:
  335. requests:
  336. cpu: 200m
  337. memory: 512Mi
  338. limits:
  339. cpu: 1
  340. memory: 1Gi
  341. nodeSelector: {}
  342. tolerations: []
  343. affinity: {}
  344. podAnnotations: {}
  345. priorityClassName:
  346. notary:
  347. enabled: true
  348. server:
  349. serviceAccountName: ""
  350. automountServiceAccountToken: false
  351. image:
  352. repository: goharbor/notary-server-photon
  353. tag: v2.7.0
  354. replicas: 1
  355. nodeSelector: {}
  356. tolerations: []
  357. affinity: {}
  358. podAnnotations: {}
  359. priorityClassName:
  360. serviceAnnotations: {}
  361. signer:
  362. serviceAccountName: ""
  363. automountServiceAccountToken: false
  364. image:
  365. repository: goharbor/notary-signer-photon
  366. tag: v2.7.0
  367. replicas: 1
  368. nodeSelector: {}
  369. tolerations: []
  370. affinity: {}
  371. podAnnotations: {}
  372. priorityClassName:
  373. secretName: ""
  374. database:
  375. type: internal
  376. internal:
  377. serviceAccountName: ""
  378. automountServiceAccountToken: false
  379. image:
  380. repository: goharbor/harbor-db
  381. tag: v2.7.0
  382. password: "changeit"
  383. shmSizeLimit: 512Mi
  384. livenessProbe:
  385. timeoutSeconds: 1
  386. readinessProbe:
  387. timeoutSeconds: 1
  388. nodeSelector: {}
  389. tolerations: []
  390. affinity: {}
  391. priorityClassName:
  392. initContainer:
  393. migrator: {}
  394. permissions: {}
  395. external:
  396. host: "192.168.0.1"
  397. port: "5432"
  398. username: "user"
  399. password: "password"
  400. coreDatabase: "registry"
  401. notaryServerDatabase: "notary_server"
  402. notarySignerDatabase: "notary_signer"
  403. existingSecret: ""
  404. sslmode: "disable"
  405. maxIdleConns: 100
  406. maxOpenConns: 900
  407. podAnnotations: {}
  408. redis:
  409. type: internal
  410. internal:
  411. serviceAccountName: ""
  412. automountServiceAccountToken: false
  413. image:
  414. repository: goharbor/redis-photon
  415. tag: v2.7.0
  416. nodeSelector: {}
  417. tolerations: []
  418. affinity: {}
  419. priorityClassName:
  420. external:
  421. addr: "192.168.0.2:6379"
  422. sentinelMasterSet: ""
  423. coreDatabaseIndex: "0"
  424. jobserviceDatabaseIndex: "1"
  425. registryDatabaseIndex: "2"
  426. chartmuseumDatabaseIndex: "3"
  427. trivyAdapterIndex: "5"
  428. password: ""
  429. existingSecret: ""
  430. podAnnotations: {}
  431. exporter:
  432. replicas: 1
  433. revisionHistoryLimit: 10
  434. podAnnotations: {}
  435. serviceAccountName: ""
  436. automountServiceAccountToken: false
  437. image:
  438. repository: goharbor/harbor-exporter
  439. tag: v2.7.0
  440. nodeSelector: {}
  441. tolerations: []
  442. affinity: {}
  443. cacheDuration: 23
  444. cacheCleanInterval: 14400
  445. priorityClassName:
  446. metrics: # 是否启用监控组件(可以使用Prometheus监控Harbor指标),非必须操作
  447. enabled: true # 默认关闭
  448. core:
  449. path: /metrics
  450. port: 8001
  451. registry:
  452. path: /metrics
  453. port: 8001
  454. jobservice:
  455. path: /metrics
  456. port: 8001
  457. exporter:
  458. path: /metrics
  459. port: 8001
  460. serviceMonitor:
  461. enabled: false
  462. additionalLabels: {}
  463. interval: ""
  464. metricRelabelings:
  465. []
  466. relabelings:
  467. []
  468. trace:
  469. enabled: false
  470. provider: jaeger
  471. sample_rate: 1
  472. jaeger:
  473. endpoint: http://hostname:14268/api/traces
  474. otel:
  475. endpoint: hostname:4318
  476. url_path: /v1/traces
  477. compression: false
  478. insecure: true
  479. timeout: 10
  480. cache:
  481. enabled: false
  482. expireHours: 24

StorageClass部署手册:

https://www.yuque.com/geray-alxoc/bapt5y/ephx5o?singleDoc# 《7、k8s存储》

https://github.com/kubernetes-retired/external-storage/tree/master/nfs

  • 修改完成配置之后可以进行安装
  1. helm install harbor ./harbor -n harbor # 将安装资源部署到harbor命名空间

helm部署harbor高可用 - 图1

  1. # 查看chart状态
  2. helm status harbor -n harbor
  3. # 卸载chart
  4. helm uninstall harbor -nharbor
  • 默认情况下helm3只显示默认名称空间(default)下的发布

5、服务验证

1. 查看所有服务启动状态

  1. kubectl get pod -n harbor
  2. NAME READY STATUS RESTARTS AGE
  3. harbor-chartmuseum-5798db66df-kg7hm 1/1 Running 0 2m20s
  4. harbor-core-789d6c44f9-mgdlq 1/1 Running 0 2m20s
  5. harbor-database-0 1/1 Running 0 2m18s
  6. harbor-exporter-7948fc6669-lw58b 1/1 Running 0 2m20s
  7. harbor-jobservice-66bf498cc4-l8cfc 1/1 Running 3 (57s ago) 2m20s
  8. harbor-nginx-fc68874d5-hbd59 1/1 Running 0 2m20s
  9. harbor-notary-server-f95bc8f6d-kblng 1/1 Running 1 (65s ago) 2m20s
  10. harbor-notary-signer-98cc8c75f-gfmr6 1/1 Running 0 2m20s
  11. harbor-portal-b7d5d9558-hl9jx 1/1 Running 0 2m20s
  12. harbor-redis-0 1/1 Running 0 2m18s
  13. harbor-registry-5896d877fc-dbv7b 2/2 Running 0 2m20s
  14. harbor-trivy-0 1/1 Running 0 2m18s

2. 查看service

  1. kubectl get svc -nharbor
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. harbor NodePort 10.233.25.27 <none> 80:30002/TCP,4443:30004/TCP 15m
  4. harbor-chartmuseum ClusterIP 10.233.19.145 <none> 80/TCP 15m
  5. harbor-core ClusterIP 10.233.60.97 <none> 80/TCP,8001/TCP 15m
  6. harbor-database ClusterIP 10.233.48.217 <none> 5432/TCP 15m
  7. harbor-exporter ClusterIP 10.233.28.154 <none> 8001/TCP 15m
  8. harbor-jobservice ClusterIP 10.233.17.179 <none> 80/TCP,8001/TCP 15m
  9. harbor-notary-server ClusterIP 10.233.43.35 <none> 4443/TCP 15m
  10. harbor-notary-signer ClusterIP 10.233.38.126 <none> 7899/TCP 15m
  11. harbor-portal ClusterIP 10.233.46.136 <none> 80/TCP 15m
  12. harbor-redis ClusterIP 10.233.34.145 <none> 6379/TCP 15m
  13. harbor-registry ClusterIP 10.233.22.128 <none> 5000/TCP,8080/TCP,8001/TCP 15m
  14. harbor-trivy ClusterIP 10.233.62.176 <none> 8080/TCP 15m

3. 登陆访问测试

  1. # 查看状态,寻找访问方式
  2. helm status harbor -n harbor
  3. NAME: harbor
  4. LAST DEPLOYED: Wed Feb 8 09:30:07 2023
  5. NAMESPACE: harbor
  6. STATUS: deployed
  7. REVISION: 1
  8. TEST SUITE: None
  9. NOTES:
  10. Please wait for several minutes for Harbor deployment to complete.
  11. Then you should be able to visit the Harbor portal at http://192.168.6.31:30002
  12. For more details, please visit https://github.com/goharbor/harbor
  • 拉取镜像打标签推送测试
  1. # 添加私服地址
  2. vim /etc/docker/daemon.json
  3. "insecure-registries": ["192.168.6.31:30002"]
  1. docker pull nginx
  2. docker tag nginx:latest 192.168.6.31:30002/mid/nginx:latest
  3. docker push 192.168.6.31:30002/mid/nginx:latest

helm部署harbor高可用 - 图2

6、错误排查

  1. kubectl describe pod harbor-notary-server-54f99bd444-shxl6 -n harbor
  2. ...
  3. Normal Started 12m (x4 over 15m) kubelet Started container notary-server
  4. Normal Pulled 12m (x3 over 14m) kubelet Container image "goharbor/notary-server-photon:v2.7.0" already present on machine
  5. Warning Unhealthy 7m36s (x12 over 9m14s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 503
  6. Warning Unhealthy 104s (x6 over 14m) kubelet Readiness probe failed: Get "http://10.233.111.122:4443/_notary_server/health": dial tcp 10.233.111.122:4443: connect: connection refused

helm部署harbor高可用 - 图3

  1. kubectl describe pod harbor-notary-signer-5db9f5ff9-5rdtb -n harbor
  2. ...
  3. Normal Pulled 9m27s (x6 over 17m) kubelet Container image "goharbor/notary-signer-photon:v2.7.0" already present on machine
  4. Warning Unhealthy 3m31s (x7 over 17m) kubelet Readiness probe failed: Get "https://10.233.111.120:7899/": dial tcp 10.233.111.120:7899: connect: connection refused
  • 本以为是禁用了tls导致的,结果等了一会发现好了(自愈了)