Skip to content

Commit e090818

Browse files
authored
Merge pull request #1002 from merico-dev/feat-harbor
Docs: Rewrite the Document of Plugin `harbor`
2 parents 77caefb + b88dfbf commit e090818

6 files changed

Lines changed: 294 additions & 57 deletions

File tree

docs/plugins/harbor.zh.md

Lines changed: 281 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,285 @@
11
# harbor 插件
22

3-
这个插件使用 helm 在已有的 k8s 集群上安装 [harbor](https://goharbor.io/)
3+
`harbor` 插件用于部署、管理 [Harbor](https://goharbor.io/) 应用
44

5-
## 使用方法
5+
Harbor 的主流部署方式有2种:**docker compose****helm**
6+
现在 DevStream 有2个插件 `harbor-docker``harbor` 分别支持这2种部署方式,但是目前以 helm 方式为主。
7+
在不久的将来,这两个插件将会被合并成一个。
68

7-
### 测试环境
9+
## 1、前置要求
810

9-
如果你想在**本地测试插件**, 可以使用如下 `values_yaml` 配置。
11+
- 有一个可用的 Kubernetes 集群,版本 1.10+
12+
13+
## 2、部署架构
14+
15+
Harbor 本身并不关注如何实现存储高可用和 PostgreSQL、Redis 的高可用。
16+
所以 Harbor 支持通过 PVCs 的方式持久化数据,支持对接外部 PostgreSQL 和 Redis。
17+
18+
Harbor 部署架构整体如下图所示(图片来自 Harbor 官网):
19+
20+
![Harbor Architecture](./harbor/ha.png)
21+
22+
## 3、开始部署
23+
24+
下文将介绍如何配置 `harbor` 插件,完成 Harbor 应用的部署。演示环境为一台装有以 minikube 方式部署的单节点 k8s 集群的 Linux 云主机。
25+
26+
### 3.1、快速开始
27+
28+
如果仅是用于开发、测试等目的,希望快速完成 Harbor 的部署,可以使用如下配置快速开始:
29+
30+
```yaml
31+
--8<-- "harbor.yaml"
32+
```
33+
34+
在成功执行 `dtm apply` 命令后,我们可以在 harbor 命名空间下看到下述主要资源:
35+
36+
- **Deployment** (`kubectl get deployment -n harbor`)
37+
38+
```shell
39+
NAME READY UP-TO-DATE AVAILABLE AGE
40+
harbor-core 1/1 1 1 2m56s
41+
harbor-jobservice 1/1 1 1 2m56s
42+
harbor-nginx 1/1 1 1 2m56s
43+
harbor-portal 1/1 1 1 2m56s
44+
harbor-registry 1/1 1 1 2m56s
45+
```
46+
47+
可以看到几乎所有 Harbor 相关服务都是以 Deployment 方式在运行。
48+
49+
- **StatefulSet** (`kubectl get statefulset -n harbor`)
50+
51+
```shell
52+
NAME READY AGE
53+
harbor-database 1/1 3m40s
54+
harbor-redis 1/1 3m40s
55+
```
56+
57+
这两个 StatefulSet 资源对应的是 Harbor 所依赖的 PostgreSQL 和 Redis。
58+
换言之,当前部署方式会自动完成 PostgreSQL 和 Redis 的部署,但是同时需要注意 PostgreSQL 和 Redis 并不是高可用的。
59+
60+
- **Service** (`kubectl get service -n harbor`)
61+
62+
```shell
63+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
64+
harbor NodePort 10.99.177.6 <none> 80:30002/TCP 4m17s
65+
harbor-core ClusterIP 10.106.220.239 <none> 80/TCP 4m17s
66+
harbor-database ClusterIP 10.102.102.95 <none> 5432/TCP 4m17s
67+
harbor-jobservice ClusterIP 10.98.5.49 <none> 80/TCP 4m17s
68+
harbor-portal ClusterIP 10.105.115.5 <none> 80/TCP 4m17s
69+
harbor-redis ClusterIP 10.104.100.167 <none> 6379/TCP 4m17s
70+
harbor-registry ClusterIP 10.106.124.148 <none> 5000/TCP,8080/TCP 4m17s
71+
```
72+
73+
可以看到默认情况下 Harbor 通过 NodePort 方式暴露服务时,端口是 30002。
74+
75+
- **PersistentVolumeClaim** (`kubectl get pvc -n harbor`)
76+
77+
```shell
78+
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
79+
data-harbor-redis-0 Bound pvc-5b6b5eb4-c40d-4f46-8f19-ff3a8869e56f 1Gi RWO standard 5m12s
80+
database-data-harbor-database-0 Bound pvc-d7ccaf1f-c450-4a16-937a-f55ad0c7c18d 1Gi RWO standard 5m12s
81+
harbor-jobservice Bound pvc-9407ef73-eb65-4a56-8720-a9ddbcb76fef 1Gi RWO standard 5m13s
82+
harbor-registry Bound pvc-34a2b88d-9ff2-4af4-9faf-2b33e97b971f 5Gi RWO standard 5m13s
83+
```
84+
85+
从这里可以看到 Harbor 所需要的存储卷有4个,其中也包括了 PostgreSQL 和 Redis 的存储。
86+
87+
- **PersistentVolume** (`kubectl get pv`)
88+
89+
```shell
90+
pvc-34a2b88d-9ff2-4af4-9faf-2b33e97b971f 5Gi RWO Delete Bound harbor/harbor-registry standard 5m22s
91+
pvc-5b6b5eb4-c40d-4f46-8f19-ff3a8869e56f 1Gi RWO Delete Bound harbor/data-harbor-redis-0 standard 5m22s
92+
pvc-9407ef73-eb65-4a56-8720-a9ddbcb76fef 1Gi RWO Delete Bound harbor/harbor-jobservice standard 5m22s
93+
pvc-d7ccaf1f-c450-4a16-937a-f55ad0c7c18d 1Gi RWO Delete Bound harbor/database-data-harbor-database-0 standard 5m22s
94+
```
95+
96+
我们并没有配置 StorageClass,所以这里用的是集群内的 default StorageClass 完成的 pv 创建。
97+
98+
在我的环境里,default StorageClass 如下(`kubectl get storageclass`):
99+
100+
```shell
101+
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
102+
standard (default) k8s.io/minikube-hostpath Delete Immediate false 20h
103+
```
104+
105+
这个 StorageClass 对应的 Provisioner 会以 hostPath 的方式提供 pv。
106+
107+
到这里,我们就可以通过 http://127.0.0.1:3002 访问到 Harbor 登录页面了,如下:
108+
109+
![Harbor Login](./harbor/login.png)
110+
111+
默认登录账号/密码是 `admin/Harbor12345`。登录后,可以看到默认首页如下:
112+
113+
![Harbor Dashboard](./harbor/dashboard.png)
114+
115+
如果是在云主机上部署的 Harbor,可以通过 `kubectl port-forward` 命令来暴露服务:
116+
117+
```shell
118+
ip=YOUR_HOST_IP
119+
kubectl port-forward -n harbor service/harbor --address=${ip} 80
120+
```
121+
122+
需要注意的是这里得使用主机真实网卡 ip,而我们在浏览器上输入的 ip 是云主机的公网 ip,两者并不一样。
123+
124+
### 3.2、最小化配置
125+
126+
`harbor` 插件的配置项默认值如下表:
127+
128+
| key | default value | description |
129+
| ---- | ---- | ---- |
130+
| chart.chart_name | harbor/harbor | helm chart 包名称 |
131+
| chart.timeout | 10m | helm install 的超时时间 |
132+
| chart.upgradeCRDs | true | 是否更新 CRDs(如果有) |
133+
| chart.release_name | harbor | helm 发布名称 |
134+
| chart.wait | true | 是否等待部署完成 |
135+
| chart.namespace | harbor | 部署的命名空间 |
136+
| repo.url | https://helm.goharbor.io | helm 仓库地址 |
137+
| repo.name | harbor | helm 仓库名 |
138+
| create_namespace | false | 是否需要 dtm 来新建命名空间 |
139+
140+
目前除了 `values_yaml` 字段和默认配置,其它所有示例参数均为必填项。 因此,我们也可以使用如下最小化配置达到和上面配置文件一样的效果:
141+
142+
```yaml
143+
tools:
144+
- name: harbor
145+
instanceID: default
146+
dependsOn: [ ]
147+
options:
148+
create_namespace: true
149+
chart:
150+
values_yaml: |
151+
externalURL: http://127.0.0.1
152+
expose:
153+
type: nodePort
154+
tls:
155+
enabled: false
156+
chartmuseum:
157+
enabled: false
158+
notary:
159+
enabled: false
160+
trivy:
161+
enabled: false
162+
```
163+
164+
### 3.3、持久化存储数据
165+
166+
前面我们已经看到了如果不配置 StorageClass,Harbor 会使用集群内的 default StorageClass。比如在当前演示环境下,harbor-registry 所使用的 pv 配置大致如下:
167+
168+
```yaml
169+
apiVersion: v1
170+
kind: PersistentVolume
171+
metadata:
172+
name: pvc-34a2b88d-9ff2-4af4-9faf-2b33e97b971f
173+
spec:
174+
accessModes:
175+
- ReadWriteOnce
176+
capacity:
177+
storage: 5Gi
178+
claimRef:
179+
apiVersion: v1
180+
kind: PersistentVolumeClaim
181+
name: harbor-registry
182+
namespace: harbor
183+
hostPath:
184+
path: /tmp/hostpath-provisioner/harbor/harbor-registry
185+
persistentVolumeReclaimPolicy: Delete
186+
storageClassName: standard
187+
volumeMode: Filesystem
188+
status:
189+
phase: Bound
190+
```
191+
192+
可见数据其实挂在到了主机的 `/tmp/hostpath-provisioner/harbor/harbor-registry` 目录下了。
193+
194+
Harbor 支持3种持久化存储数据配置方式:
195+
196+
1. 配置 StorageClass(默认使用 default StorageClass);
197+
2. 使用已经存在的 pvc(手动创建);
198+
3. 对接 azure、gcs、s3、swift、oss 等实现镜像和 Charts 云端存储。
199+
200+
我们暂时只介绍第一种方式,也就是指定 StorageClass 实现存储数据持久化。
201+
registry、jobservice、chartmuseum、database、redis、trivy 等组件都可以单独指定 StorageClass。
202+
假设我们现在有一个新的 StorageClass 叫做 nfs,这时候要实现前面部署的 Harbor 所有数据持久化到外部 pv,我们可以这样配置:
10203

11204
```yaml
12-
values_yaml: |
13-
externalURL: http://127.0.0.1
14-
expose:
15-
type: nodePort
16-
tls:
17-
enabled: false
18-
chartmuseum:
19-
enabled: false
20-
clair:
21-
enabled: false
22-
notary:
23-
enabled: false
24-
trivy:
25-
enabled: false
205+
tools:
206+
- name: harbor
207+
instanceID: default
208+
dependsOn: [ ]
209+
options:
210+
create_namespace: true
211+
chart:
212+
values_yaml: |
213+
persistence:
214+
persistentVolumeClaim:
215+
registry:
216+
storageClass: "nfs"
217+
accessMode: ReadWriteOnce
218+
size: 5Gi
219+
jobservice:
220+
storageClass: "nfs"
221+
accessMode: ReadWriteOnce
222+
size: 1Gi
223+
database:
224+
storageClass: "nfs"
225+
accessMode: ReadWriteOnce
226+
size: 1Gi
227+
redis:
228+
storageClass: "nfs"
229+
accessMode: ReadWriteOnce
230+
size: 1Gi
26231
```
27232

28-
在该配置下
233+
### 3.4、服务暴露
234+
235+
Harbor 可以以 ClusterIP、LoadBalancer、NodePort 和 Ingress 等方式对外暴露服务。我们前面使用的就是 NodePort 方式:
29236

30-
- helm 会自动创建依赖的 Postgresql 和 Redis;
31-
- 数据挂载的磁盘默认会使用集群上机器的本地磁盘;
32-
- 只安装 `harbor` 主程序而不会安装其余的插件;
33-
- 通过 `NodePort` 对外暴露服务,可使用 `http://{{k8s 节点ip}}:30002` 域名来访问,默认账号名密码为 admin/Harbor12345 (生产环境请替换默认账号密码)。
237+
```yaml
238+
tools:
239+
- name: harbor
240+
instanceID: default
241+
dependsOn: [ ]
242+
options:
243+
create_namespace: true
244+
chart:
245+
values_yaml: |
246+
externalURL: http://127.0.0.1
247+
expose:
248+
type: nodePort
249+
```
34250

35-
### 生产环境
251+
本文我们再介绍一下如何使用 Ingress 方式暴露服务:
36252

37-
Harbor的大部分组件都是无状态的。因此我们可以通过增加 `Pod` 的副本来确保组件被部署到多个工作节点,并使用 `Kubernetes` 的 `Service` 机制来确保跨 `Pod` 的网络连接。
253+
```yaml
254+
tools:
255+
- name: harbor
256+
instanceID: default
257+
dependsOn: [ ]
258+
options:
259+
create_namespace: true
260+
chart:
261+
values_yaml: |
262+
externalURL: http://127.0.0.1
263+
expose:
264+
type: ingress
265+
tls:
266+
enabled: false
267+
hosts:
268+
core: "core.harbor.domain"
269+
```
38270

39-
#### 外部存储
271+
注意:如果没有开启 TLS,这种方式暴露 Harbor 服务后 docker push/pull 命令必须带上端口。
40272

41-
> Harbor 正常运行依赖 Postgresql 和 Redis
273+
### 3.5、PostgreSQL 和 Redis 高可用
42274

43-
- Postgresql:生产环境建议使用外部高可用的 Postgresql 集群,具体配置可参考 [config](https://github.com/goharbor/harbor-helm#configuration) 中的 Database 选项
44-
- Redis: 生产环境建议使用外部高可用的 Redis 集群,具体配置可参考 [config](https://github.com/goharbor/harbor-helm#configuration) 中的 Redis 选项
275+
Harbor 依赖 PostgreSQL 和 Redis 服务,默认情况下自动部署的 PostgreSQL 和 Redis 服务都是非高可用模式
276+
换言之如果我们单独部署高可用的 PostgreSQL 和 Redis 服务,Harbor 是支持去对接外部 PostgreSQL 和 Redis 服务的
45277

46-
#### 磁盘存储
47-
请将配置中的 `storageClass` 修改为已存在的 StorageClass,集体配置可参考 [config](https://github.com/goharbor/harbor-helm#configuration) 中的 Persistence 选项。
278+
TODO(daniel-hutao): 本节待细化
48279

49-
#### 网络层配置
50-
该插件支持 `Ingress`, `ClusterIP`, `NodePort`, `LoadBalancer` 对外暴露的模式,可以基于需求进行选择。
280+
### 3.6、https 配置
51281

52-
#### 证书配置
282+
TODO(daniel-hutao): 本节待细化
53283

54284
- 使用自签名证书
55285
1. 将 `tls.enabled` 设置为 `true`,并编辑对应的域名 `externalURL`;
@@ -60,24 +290,22 @@ Harbor的大部分组件都是无状态的。因此我们可以通过增加 `Pod
60290
2. 将 `tls.enabled` 设置为 `true`,并编辑对应的域名 `externalURL`;
61291
3. 配置 `tls.secretName` 使用该公共证书。
62292

63-
### 配置
293+
## 4、典型场景
64294

65-
```yaml
66-
--8<-- "harbor.yaml"
67-
```
295+
// TODO(daniel-hutao): 本节待补充
296+
297+
### 4.1、HTTP
298+
299+
#### 4.1.1 HTTP + Registry + Internal Database + Internal Redis
300+
301+
#### 4.1.2 HTTP + Registry + Chartmuseum + Internal Database + Internal Redis
302+
303+
#### 4.1.3 HTTP + Registry + Chartmuseum + External Database + External Redis
304+
305+
### 4.2、HTTPS
306+
307+
#### 4.1.1 HTTPS + Registry + Internal Database + Internal Redis
308+
309+
#### 4.1.2 HTTPS + Registry + Chartmuseum + Internal Database + Internal Redis
68310

69-
#### 默认配置
70-
71-
| key | default value | description |
72-
| ---- | ---- | ---- |
73-
| chart.chart_name | harbor/harbor | helm 包名称 |
74-
| chart.timeout | 10m | 等待部署成功的时间 |
75-
| chart.upgradeCRDs | true | 默认更新 CRD 配置(如果存在的话) |
76-
| chart.release_name | harbor | helm 发布名称 |
77-
| chart.wait | true | 是否等待部署完成 |
78-
| chart.namespace | harbor | helm 部署的命名空间名称 |
79-
| repo.url | https://helm.goharbor.io | helm 官方仓库地址 |
80-
| repo.name | harbor | helm 仓库名 |
81-
| create_namespace | false | 是否需要新建命名空间 |
82-
83-
目前除了 `values_yaml` 字段和默认配置,其它所有示例参数均为必填项。
311+
#### 4.1.3 HTTPS + Registry + Chartmuseum + External Database + External Redis

docs/plugins/harbor/dashboard.png

476 KB
Loading

docs/plugins/harbor/ha.png

152 KB
Loading

docs/plugins/harbor/login.png

69.4 KB
Loading

internal/pkg/plugininstaller/helm/installer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func DealWithNsWhenInstall(options plugininstaller.RawOptions) error {
7272
return nil
7373
}
7474

75-
// DealWithNsWhenInterruption will Delete namespace by input options
75+
// DealWithNsWhenInterruption will Delete the namespace just created if options.create_namespace==true in Config
7676
func DealWithNsWhenInterruption(options plugininstaller.RawOptions) error {
7777
opts, err := NewOptions(options)
7878
if err != nil {

internal/pkg/show/config/plugins/harbor.yaml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ tools:
2626
timeout: 10m
2727
# whether to perform a CRD upgrade during installation
2828
upgradeCRDs: true
29-
# values_yaml: |
30-
# serviceaccount:
31-
# enabled: true
29+
values_yaml: |
30+
externalURL: http://127.0.0.1
31+
expose:
32+
type: nodePort
33+
tls:
34+
enabled: false
35+
chartmuseum:
36+
enabled: false
37+
notary:
38+
enabled: false
39+
trivy:
40+
enabled: false

0 commit comments

Comments
 (0)