)(仓库access_secret
仓库access_secret
仓库access_secret
仓库access_key
仓库状态
仓库状态
仓库名称
在Harbor中仓库的唯一ID
仓库credential类型
仓库access_secret
仓库access_key
Harbor边缘部署文档
1,生成CA证书私钥
$ openssl genrsa -out ca.key 4096
2,生成CA证书
# 将yourdomain.com修改为需要配置的域名,本文当中使用cedhub.com
$ openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com" \
-key ca.key \
-out ca.crt
1,生成服务器私钥
$ openssl genrsa -out tls.key 4096
2,生成CSR(Certificate signing request)
# 将yourdomain.com修改为需要配置的域名,本文当中使用cedhub.com
$ openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com" \
-key tls.key \
-out tls.csr
3,生成x509 v3扩展文件
# 将yourdomain.com修改为需要配置的域名,本文当中使用cedhub.com
$ cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=yourdomain.com
EOF
4,使用v3扩展文件为Harbor生成证书
$ openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in tls.csr \
-out tls.crt
$ helm repo add harbor https://helm.goharbor.io
# 查看可以安装的chart(包含历史版本)
$ helm search repo harbor -l
# 安装1.8.1版本的Chart(2.4.1版本的Harbor)
$ helm fetch harbor/harbor --untar --version 1.8.1
# kubectl create namespace harbor
若使用http提供服务,则需要修改Docker配置文件并重启,故使用https提供服务,故需配置tls
# 创建secret,将第一步生成的证书导入
kubectl create secret generic cedhub-tls --from-file=tls.crt --from-file=tls.key --from-file=ca.crt -n harbor
# 配置value.yaml
...
tls:
# Enable the tls or not.
# Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress"
# Note: if the "expose.type" is "ingress" and the tls
# is disabled, the port must be included in the command when pull/push
# images. Refer to https://github.com/goharbor/harbor/issues/5291
# for the detail.
enabled: true
# The source of the tls certificate. Set it as "auto", "secret"
# or "none" and fill the information in the corresponding section
# 1) auto: generate the tls certificate automatically
# 2) secret: read the tls certificate from the specified secret.
# The tls certificate can be generated manually or by cert manager
# 3) none: configure no tls certificate for the ingress. If the default
# tls certificate is configured in the ingress controller, choose this option
certSource: secret
auto:
# The common name used to generate the certificate, it's necessary
# when the type isn't "ingress"
commonName: ""
secret:
# The name of secret which contains keys named:
# "tls.crt" - the certificate
# "tls.key" - the private key
secretName: "cedhub-tls"
# The name of secret which contains keys named:
# "tls.crt" - the certificate
# "tls.key" - the private key
# Only needed when the "expose.type" is "ingress".
notarySecretName: "cedhub-tls"
...
边缘Harbor仅供集群内部使用,故使用clusterIP暴露服务
expose:
# Set the way how to expose the service. Set the type as "ingress",
# "clusterIP", "nodePort" or "loadBalancer" and fill the information
# in the corresponding section
type: clusterIP
...
即使用cllient登录Harbor使用的地址,作用:生成portal界面展示的docker/helm命令;生成返回给docker/notaryclient的token service地址
# The external URL for Harbor core service. It is used to
# 1) populate the docker/helm commands showed on portal
# 2) populate the token service URL returned to docker/notary client
#
# Format: protocol://domain[:port]. Usually:
# 1) if "expose.type" is "ingress", the "domain" should be
# the value of "expose.ingress.hosts.core"
# 2) if "expose.type" is "clusterIP", the "domain" should be
# the value of "expose.clusterIP.name"
# 3) if "expose.type" is "nodePort", the "domain" should be
# the IP address of k8s node
#
# If Harbor is deployed behind the proxy, set it as the URL of proxy
externalURL: https://cedhub.com
在Node上创建文件夹
mkdir -p /data/disks/{disk1-5G,disk2-5G,disk3-1G,disk4-1G,disk5-1G,disk6-5G}
如果没有提供StorageClass来动态提供持久化,则手动分配,创建hostPath类型的PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk1
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk1-5G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk2
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk2-5G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk3
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk3-1G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk4
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk4-1G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk5
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk5-1G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk6
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
hostPath:
path: "/data/disks/disk6-5G"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cvm-lrxdi7pm
创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk1-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk2-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk3-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk4-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk5-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk6-pv-claim
namespace: harbor
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
配置values.yaml持久化存储部分
···
# 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
# (this does not apply for PVCs that are created for internal database
# and redis components, i.e. they are never deleted automatically)
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: "disk1-pv-claim"
# 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: ""
accessMode: ReadWriteOnce
size: 5Gi
chartmuseum:
existingClaim: "disk2-pv-claim"
storageClass: ""
subPath: ""
accessMode: ReadWriteOnce
size: 5Gi
jobservice:
existingClaim: "disk3-pv-claim"
storageClass: ""
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
# If external database is used, the following settings for database will
# be ignored
database:
existingClaim: "disk4-pv-claim"
storageClass: ""
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
# If external Redis is used, the following settings for Redis will
# be ignored
redis:
existingClaim: "disk5-pv-claim"
storageClass: ""
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
trivy:
existingClaim: "disk6-pv-claim"
storageClass: ""
subPath: ""
accessMode: ReadWriteOnce
size: 5Gi
···
配置values.yaml持久化存储部分
···
# 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
# (this does not apply for PVCs that are created for internal database
# and redis components, i.e. they are never deleted automatically)
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: "
# 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: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 5Gi
chartmuseum:
existingClaim: ""
storageClass: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 5Gi
jobservice:
existingClaim: ""
storageClass: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
# If external database is used, the following settings for database will
# be ignored
database:
existingClaim: ""
storageClass: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
# If external Redis is used, the following settings for Redis will
# be ignored
redis:
existingClaim: ""
storageClass: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 1Gi
trivy:
existingClaim: ""
storageClass: "storageClassName"
subPath: ""
accessMode: ReadWriteOnce
size: 5Gi
···
# 在harbor目录下
$ helm install --namespace harbor my-harbor .
$ helm uninstall my-harbor -n harbor
采用主从(Active-Standy)模式的高可用方案,边缘集群的Harbor提供服务,云端的TCR处于待用(Standby)状态
private_key.pem和root.crt文件
Harbor在客户端认证流程中,提供了证书和私钥文件供Distribution创建和校验请求中的Bearer token。在多实例Harbor的高可用方案中,多实例之间需要做到任何一个实例创建的Bearer token都可被其他实例识别并校验,也就是说,所有实例都需要使用相同的private_key.pem和root.crt文件。
csrf_key
为防止跨站攻击(Cross Site RequestForgery),Harbor启用了csrf的token校验。Harbor会生成一个随机数作为csrf的token附加在cookie中,用户提交请求时,客户端会从cookie中提取这个随机数,并将其作为csrf的token一并提交。Harbor会依据这个值是否为空或者无效来拒绝该访问请求。那么,多实例之间需要做到任何一个实例创建的token都可被其他任意实例成功校验,也就是需要统一各个实例的csrf token私钥值。
暂不实现
Docker守护进程会将.crt文件解析为CA证书,.cert文件解析为client证书
$ openssl x509 -inform PEM -in tls.crt -out tls.cert
创建Docker证书存储目录
# 将yourdomain.com修改为需要配置的域名,本文当中使用cedhub.com
# 如果将默认的443端口映射为其他端口,则需创建/etc/docker/certs.d/yourdomain.com:port或/etc/docker/certs.d/harbor_IP:port
$ mkdir -p /etc/docker/certs.d/yourdomain.com/
拷贝证书到Docker证书存储目录
# 将yourdomain.com修改为需要配置的域名,本文当中使用cedhub.com
cp tls.cert /etc/docker/certs.d/yourdomain.com/
cp tls.key /etc/docker/certs.d/yourdomain.com/
cp ca.crt /etc/docker/certs.d/yourdomain.com/
添加registry secret
# docker-server为service harbor的域名
kubectl create secret docker-registry registry-secret --namespace=default \
--docker-server=cedhub.com \
--docker-username=admin \
--docker-password=Harbor12345
配置Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
appname: nginx
spec:
selector:
matchLabels:
appname: nginx
replicas: 3
template:
metadata:
labels:
appname: nginx
spec:
containers:
- name: nginx
image: cedhub.com/preheat/nginx:latest # 边缘镜像地址
ports:
- containerPort: 80
imagePullSecrets: # 使用边缘Harbor的secret
- name: registry-secret
配置Service
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
appname: nginx
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
1,边端无StorageClass,使用hostPath类型的持久化存储时,进行数据备份
使用pgcli将元数据备份到其他节点
1,测试仓库连通性
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
$ curl -k -v -i -X 'POST' 'https://cedhub.com/api/v2.0/registries/ping' -H 'accept: application/json' -H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU=' -H 'Content-Type: application/json' -d '{
"access_key": "AKIDNa7NM5WgZBWaNvEH3XliOoywd3D6i37v",
"access_secret": "YpujHYYHkwrUqvjGWVDdngj6LL4WhJgm",
"description": "",
"insecure": false,
"name": "test",
"type": "tencent-tcr",
"url": "https://preheat-test.tencentcloudcr.com"
}'
2,添加远端仓库
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
$ curl -k -v -i -X 'POST' 'https://cedhub.com/api/v2.0/registries' -H 'accept: application/json' -H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU=' -H 'Content-Type: application/json' -d '{
"credential": {
"access_key": "AKIDNa7NM5WgZBWaNvEH3XliOoywd3D6i37v",
"access_secret": "YpujHYYHkwrUqvjGWVDdngj6LL4WhJgm",
"type": "basic"
},
"description": "",
"insecure": false,
"name": "test",
"type": "tencent-tcr",
"url": "https://preheat-test.tencentcloudcr.com"
}'
3,获取远端仓库列表
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
$ curl -k -v -i -X 'GET' 'https://cedhub.com/api/v2.0/registries?page=1&page_size=10' -H 'accept: application/json' -H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU='
把资源由远端仓库拉到本地
{
"name": "sync_test",
"description": "",
"src_registry": {
"creation_time": "2022-02-23T04:01:40.344Z",
"credential": {
"access_key": "AKIDNa7NM5WgZBWaNvEH3XliOoywd3D6i37v",
"access_secret": "*****",
"type": "basic"
},
"id": 1,
"name": "test",
"status": "healthy",
"type": "tencent-tcr",
"update_time": "2022-02-23T04:01:40.344Z",
"url": "https://preheat-test.tencentcloudcr.com"
}
"dest_registry": null,
"dest_namespace": "library",
"dest_namespace_replace_count": 1,
"trigger": {
"t15pe": "manual",
"trigger_settings": {
"cron": ""
}
},
"enabled": true,
"deletion": false,
"override": false,
"speed": -1,
"filters": [
{
"type": "name",
"value": "preheat/**"
},
{
"type": "tag",
"decoration": "matches",
"value": "latest"
},
{
"type": "resource",
"value": "image"
}
]
}
参数说明
参数 | 参数说明 |
---|---|
name | 复制规则名称 |
description | 复制规则描述 |
src_registry | 源仓库信息,可以从获取远端仓库列表接口获取 |
filters | 源资源过滤器列表 |
dest_registry | 目标仓库,pull-based模式下为null |
dest_namespace | 目标命名空间,指定目标命名空间,如果不填,资源会被放到和源相同的命名空间下(没有对应的命名空间则会直接创建) |
dest_namespace_replace_count | 目标仓库扁平化层级 |
trigger | 触发模式 |
speed | 带宽(Kbps) |
src_registry(源仓库信息)说明
"src_registry": {
"creation_time": "2022-02-23T03:49:16.652Z",
"credential": {
"access_key": "AKIDNa7NM5WgZBWaNvEH3XliOoywd3D6i37v",
"access_secret": "*****",
"type": "basic"
},
"id": 7,
"name": "test",
"status": "healthy",
"type": "tencent-tcr",
"update_time": "2022-02-23T03:49:16.652Z",
"url": "https://preheat-test.tencentcloudcr.com"
},
参数 | 说明 |
---|---|
creation_time | 仓库创建时间 |
credential.access_key | 仓库access_key |
credential.access_secret | 仓库access_secret |
credential.type | 仓库access_secret |
id | 仓库access_secret(自动创建) |
name | 仓库名称 |
status | 仓库状态 |
type | 仓库类型 |
update_time | 仓库状态更新时间 |
url | 仓库URL |
filters(过滤器)说明
"filters": [
{
"type": "name",
"value": "preheat/**"
},
{
"type": "tag",
"decoration": "matches",
"value": "latest"
},
{
"type": "resource",
"value": "image"
}
]
参数 | 说明 |
---|---|
type | name,即名称过滤器 |
value | 过滤资源名字,不填或填写“**”,匹配所有资源;“library/**”只匹配library下的资源 |
参数 | 说明 |
---|---|
type | tag,即tag过滤器 |
decoration | matches/excludes(匹配/排除) |
value | 过滤资源的tag/version。不填写或“”,匹配所有;“1.0*”只匹配以“1.0“开头的tag/version |
参数 | 说明 |
---|---|
type | resource,即类型过滤器 |
value | 过滤资源类型,image/char/不填(镜像/helm chart/全部) |
trigger(触发模式)
参数 | 说明 |
---|---|
type | manual/scheduled/(手动/定时) |
trigger_settings.trigger_settings.cron | cron表达式 |
1,创建远程复制策略
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
# 需要从获取远端仓库列表接口获取src_registry信息
$ curl -k -v -i -X 'POST' \
'https://cedhub.com/api/v2.0/replication/policies' \
-H 'accept: application/json' \
-H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU=' \
-H 'Content-Type: application/json' -d '
{
"name": "test_sync",
"description": "",
"src_registry": {
"creation_time": "2022-02-23T04:01:40.344Z",
"credential": {
"access_key": "AKIDNa7NM5WgZBWaNvEH3XliOoywd3D6i37v",
"access_secret": "*****",
"type": "basic"
},
"id": 1,
"name": "test",
"status": "healthy",
"type": "tencent-tcr",
"update_time": "2022-02-23T04:01:40.344Z",
"url": "https://preheat-test.tencentcloudcr.com"
},
"dest_registry": null,
"dest_namespace": "",
"dest_namespace_replace_count": 1,
"trigger": {
"type": "manual",
"trigger_settings": {
"cron": ""
}
},
"enabled": true,
"deletion": false,
"override": true,
"speed": -1,
"filters": [
{
"type": "name",
"value": "preheat/**"
}
]
} '
2,列出远程复制策略
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
$ curl -k -v -i -X 'GET' \
'https://cedhub.com/api/v2.0/replication/policies?page=1&page_size=10' \
-H 'accept: application/json' \
-H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU='
3,手动触复制规则
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
# 需要从列出远程复制策略接口获取policy信息
$ curl -k -v -i -X 'POST' \
'https://cedhub.com/api/v2.0/replication/executions' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU=' \
-d '{
"policy_id": 1
}'
4,列出远程复制任务的执行记录
# -k允许curl不验证证书
# -v详细输出,输出Headers等信息
# -i输出Response Body
# authorization: Basic 配置经base64编码的用户名密码,格式为:username:password
# 需要从列出远程复制策略接口获取policy信息
$ curl -k -v -i -X 'GET' \
'https://cedhub.com/api/v2.0/replication/executions?page=1&page_size=10&policy_id=1' \
-H 'accept: application/json'\
-H 'authorization: Basic YWRtaW46SGFyYm9yMTIzNDU='
1 https://helm.sh/zh/docs/intro/install/
2 https://www.daimajiaoliu.com/daima/60ec4c05cee6803
3 https://www.qikqiak.com/post/harbor-quick-install/
4 https://www.cnblogs.com/longgor/p/11203820.html
5 https://cloud.tencent.com/developer/article/1754686
6 https://goharbor.io/docs/2.1.0/install-config/configure-https/
7 https://goharbor.io/docs/2.4.0/install-config/harbor-ha-helm/
8 http://www.361way.com/harbor-install/6511.html
9 https://tuxnotes.github.io/2021/09/02/Harbor-HA.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。