随着我们服务的全面容器化,代码和配置都以 docker image 的形式存储在 docker registry 中。搭建高可用,安全的企业r私有 docker registy 就变得十分必要。
Harbor 作为 CNCF 托管的开药 docker registry 项目是我们的首先。它除了提供存储、签名、扫描镜像的功能,还有常用的功能如鉴权、授权、权限管理等来增强 docker registry 的安全性。
除此之外,Harbor 还有从其他 registry 复制镜像的功能,新版本集成了 chartmuseum 从而可以作为 Helm Charts 的 repository。Harbor 一个重要的特点是它是通过可插拔的方式来
集合第三方组件来提供不同的功能,比如用于镜像签名的 notary;镜像扫描的 clair; 镜像存储,推送和拉取的 docker registry;helm charts 存储,管理的 chartmuseum。
在之前我们其实已经通过 docker-compose 搭建了 Harbor。这里主要介绍的是 Harbor 的工作原理和在 k8s 中部署 Harbor。
首先,我们结合 Harbor 的架构来介绍一下各个组件的功能。
Harbor 架构
下面这张图是来自 Harbor github 的官方架构图,结合这张图我们介绍一下关键的组件
数据层
-
redis
用于数据缓存和定时,异步任务的临时存储
-
镜像存储
支持的方式非常多,比如本地磁盘,网络文件系统(NAS), 对象存储(S3, OSS)等等
-
数据库
新版本使用 PostgreSQL, 用来存储 Harbor 里创建的 projects, users, roles , replication policies, tag retention policies, clair 从各大开源社区获取的CVE漏洞缺陷数据以及镜像层的扫描结构数据
核心组件
-
proxy
用 nginx 作为反向代理,转发来自浏览器和 docker 客户端的请求到不同的后端服务,比如 core, registry, token service, 网页客户端入口服务等
-
core
核心模块,包括鉴权和授权;配置管理;项目管理;项目容量管理;代理 chartmuseum; 镜像复制管理; 镜像扫描管理;webhook 提供的回调等等
-
job service
处理定时任务和异步任务,主要包括镜像同步,镜像扫描任务
-
chart museum
第三方开源 chart repository, 提供 helm chart 的管理和 api 访问
-
docker registry
第三方 registry 服务, 镜像处理的核心组件,处理镜像的上传、下拉等,直接操作镜像存储服务,如 S3、nas 等
-
notary
第三方内容信任服务,用来保证镜像在 pull,push 和传输过程中的一致性和完整性
鉴权过程
这里我们重点描述一下 docker 客户端登录 Harbor 的过程
在客户端登录我们自然首先会输入以下命令
docker login harbor.abc.com
然后输入我们的用户名和密码
1.客户端首先发送一个 GET 请求 harbor.abc.com/v2 到 registry 服务
2.registry 服务配置的是通过 JWT token 鉴权,所以返回的是一个 401 错误码,并且同时会在 response 的 header
里通知客户端去获取 token 的真正地址。Harbor 里这个地址指向的是 core service
3.客户度收到 401 和 response, 接着发送获取 token 的请求到指定的 url, 这个 url 会是 harbor.abc.com/service.token,在 request 的
header 中包含用户民和密码
4.token service(被包含在 core 的容器中)接收到请求后,解析请求拿到用户民和密码,然后去数据库中验证用户的有效性。token service 可以
配置对接外部的 LDAP/AD 来进行认证。认证成功后,返回 200 并且 response body 中包含由私钥产生的 JWT token
5.docker 客户端收到 200 请求,则登录成功。打印出 Login Succeeded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
|---------------| |----------| |---------------|
| docker client | | registry | | token service |
|---------------| |----------| |---------------|
| 1. harbor.abc.com/v2 | |
|------------------------->| |
| 2. return 401 | |
|<-------------------------| |
| 3. harbor.abc.com/service/token |
|--------------------------------------------------->|
| 4. return 200 |
|<---------------------------------------------------|
| | |
| 5. login success | |
|
push 镜像的过程和登录类似,主要区别在
鉴权那一步,会具体检查用户是否有往对应项目推送 image 的权限。
k8s 部署
推荐使用 Helm 安装
-
下载 harbor helm chart
wget https://github.com/goharbor/harbor-helm/archive/v1.2.2.tar.gz
-
解压,复制一份 values.yaml 进行定制
推荐使用 ingress 对外暴露服务
主要需要修改的配置是数据持久化和镜像存储,这里我们使用 NAS 通过区分 subpath, 把同一个 PVC 挂载到不同的容器
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
|
# The persistence is enabled by default and a default StorageClass
# is needed in the k8s cluster to provision volumes dynamicly.
# Specify another StorageClass in the "storageClass" or set "existingClaim"
# if you have already existing persistent volumes to use
#
# For storing images and charts, you can also use "azure", "gcs", "s3",
# "swift" or "oss". Set it in the "imageChartStorage" section
persistence:
enabled: true
# Setting it to "keep" to avoid removing PVCs during a helm delete
# operation. Leaving it empty will delete PVCs after the chart deleted
resourcePolicy: "keep"
persistentVolumeClaim:
registry:
# Use the existing PVC which must be created manually before bound,
# and specify the "subPath" if the PVC is shared with other components
existingClaim: "harbor-nas"
# Specify the "storageClass" used to provision the volume. Or the default
# StorageClass will be used(the default).
# Set it to "-" to disable dynamic provisioning
storageClass: ""
subPath: "registry"
accessMode: ReadWriteOnce
size: 5Gi
chartmuseum:
existingClaim: "harbor-nas"
storageClass: ""
subPath: "chartmuseum"
accessMode: ReadWriteOnce
size: 5Gi
jobservice:
existingClaim: "harbor-nas"
storageClass: ""
subPath: "jobservice"
accessMode: ReadWriteOnce
size: 1Gi
# If external database is used, the following settings for database will
# be ignored
database:
existingClaim: "harbor-nas"
storageClass: ""
subPath: "database"
accessMode: ReadWriteOnce
size: 10Gi
# If external Redis is used, the following settings for Redis will
# be ignored
redis:
existingClaim: "harbor-nas"
storageClass: ""
subPath: "redis"
accessMode: ReadWriteOnce
size: 1Gi
|
NAS PVC, 前提是在阿里云中开通了 NAS 并且集群中要创建 alicloud-nas-controller(具体可参照阿里云 NAS 文档)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: alicloud-nas
mountOptions:
- nolock,tcp,noresvport
- vers=3
parameters:
volumeAs: subpath
server: "xxxxx"
provisioner: alicloud/nas
reclaimPolicy: Delete
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: harbor-nas
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: alicloud-nas
|
1
2
3
4
5
6
7
8
9
|
NAME READY UP-TO-DATE AVAILABLE AGE
harbor-chartmuseum 1/1 1 1 2d1h
harbor-clair 1/1 1 1 2d1h
harbor-core 1/1 1 1 2d1h
harbor-jobservice 1/1 1 1 2d1h
harbor-notary-server 1/1 1 1 2d1h
harbor-notary-signer 1/1 1 1 2d1h
harbor-portal 1/1 1 1 2d1h
harbor-registry 1/1 1 1 2d1h
|