前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在TKE集群搭建harbor仓库

在TKE集群搭建harbor仓库

原创
作者头像
马凌鑫
修改2020-03-03 09:40:04
1.6K2
修改2020-03-03 09:40:04
举报
文章被收录于专栏:云知识学习云知识学习

前言

本次带来的分享是在TKE集群上搭建harbor私有仓库,另外推荐腾讯云的容器镜像服务TCR

TCR具备以下特性:

安全管理:支持 Docker 镜像、Helm Chart 存储分发及镜像安全扫描,并为企业级客户提供了细颗粒度的访问权限管理和网络访问控制。

业务拓展:支持镜像全球同步及触发器,可满足企业级客户拓展全球业务使用容器 CI/CD 工作流的需求。

极速部署:支持具有上千节点的大规模容器集群并发拉取 GB 级大镜像,可保障容器业务的极速部署。

Harbor

Harbor是由VMware公司开源的企业级的Docker Registry管理项目,可以理解为harbor是Docker Registry的更高级的版本,除了提供友好的可视化界面,还能基于角色、用户进行访问控制、镜像漏洞扫描、行为审计、与企业LDAP集成等等。相比起Docker Hub、Registry提供的简单存储功能,Harbor的出现可以说是解决企业级别对于镜像仓库的功能需求。

这里还有个有趣的说法,harbor是港湾的意思,把容器比喻成集装箱,集装箱放在港湾,生动又形象。

那么废话不多说直接进入主题

Harbor其核心的组件有:

Job Service: 一种通用执行队列服务,允许其他组件/服务通过简单的静态API同时提交运行异步任务的请求

Logs: Log collector, 日志收集器,负责将其他模块的日志收集到一个地方。

GC Controller: 管理在线GC计划设置,并启动和跟踪GC进度。

Chart Museum: 提供chart管理和访问API的chart存储服务器,即helm存储。

Docker Registry: 第三方注册表服务器,负责存储Docker镜像并处理Docker推/拉命令。由于Harbor需要强制执行对图像的访问控制,因此注册表将引导客户端使用令牌服务,以便为每个请求请求提供有效的令牌。

Notary: 第三方内容信任服务器,负责安全地发布和验证内容

Web Portal: 图形化用户界面,可帮助用户管理注册表上的图像

Architecture-Overview-of-Harbor

前提条件

Kubernetes集群 1.10+(本次教程用的集群为1.16.3)

helm 2.8.0+ (本次教程用的helm为2.10.0)

Ingress(nginx-ingress chart:1.20.0)

storageclass (配置存储)

集群

通过TKE创建一个1.16版本的托管集群,这里不赘述了,在平台上点几下即可创建集群

托管集群意思是master、etcd由腾讯云提供,只需购买node即可,无需运维master层面,省事、便捷。

helm

通过tke的控制面板安装helm,点击申请开通后会自动安装helm2,下发tiller、swift至集群中

配置helm client

这里还需额外配置 helm client 客户端,后续拉取Harbor Chart 会用到

登录节点配置即可

代码语言:javascript
复制
#下载helm 客户端

curl -O https://storage.googleapis.com/kubernetes-helm/helm-v2.10.0-linux-amd64.tar.gz
tar xzvf helm-v2.10.0-linux-amd64.tar.gz
sudo cp linux-amd64/helm /usr/local/bin/helm

#执行以下命令,将 Helm 配置为 Client-only。

helm init --client-only

下载过程中因网速等不可控问题,可能会导致下载helm-v2.10.0-linux-amd64.tar.gz缓慢

本地 Helm 客户端连接集群

Ingress

这里使用nginx-ingress,使用helm 一键安装,过程就略过了~

为什么使用nginx-ingress,而不使用tke-ingress,因为在使用tke-ingress配置ingress tls时,还需在腾讯云先导入证书,并且tke-ingress不支持service的类型为clusterip,在后续的配置中需要改动很多,这里为了方便读者理解,暂时先将部署过程简单化。

harbor

1. 添加harbor的helm库

添加harbor的helm库

代码语言:javascript
复制
$ helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories

2. 将harbor下载到本地

代码语言:javascript
复制
$ helm fetch harbor/harbor
$ tar -xvf harbor-1.3.1.tgz 
harbor/Chart.yaml
harbor/values.yaml
harbor/templates/NOTES.txt
...
$ ls harbor/
cert  Chart.yaml  conf  LICENSE  README.md  templates  values.yaml

3. 配置value.yaml

helm harbor会提供一个默认的value,里面申明了各项配置,如secret、externalURL、pvc、imagetag等等。

无需过多的修改,这里我们关心核心的几个参数,其余参数可在配置列表configuration一一对应

3.1 配置host,并指定ingress类型为nginx

配置对应域名,并且需要在ingress的annotations中声明kubernetes.io/ingress.class: nginx

代码语言:javascript
复制
  ingress:
    hosts:
      core: harbor.tke.com
      notary: harbor.tke.com
    controller: default
    annotations:
      ingress.kubernetes.io/ssl-redirect: "true"
      ingress.kubernetes.io/proxy-body-size: "0"
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-body-size: "0"
      kubernetes.io/ingress.class: nginx

externalURL: https://harbor.tke.com

若没有声明kubernetes.io/ingress.class: nginx,创建ingress时,会走tke-ingress-controller的控制器逻辑,导致创建CLB,并且会找不到证书

3.2 配置数据卷

这里默认配置的是空的参数,如果有先创建好的pvc,需要在existingClaim参数里配置好对应的pvc 名称,否则会创建新的pvc出来。

若需指定pvc的,请先创建好对应的pvc,并在existingClaim填写好对应的pvc name,如下所示:

代码语言:javascript
复制
persistence:
  enabled: true
  resourcePolicy: "keep"
  persistentVolumeClaim:
    registry:
      storageClass: ""
      subPath: ""
      accessMode: ReadWriteOnce
      size: 5Gi
    chartmuseum:
      existingClaim: "harbor-chart"
      storageClass: ""
      subPath: ""
      accessMode: ReadWriteOnce
      size: 5Gi
    jobservice:
      existingClaim: "harbor-jobservice"
      storageClass: ""
      subPath: ""
      accessMode: ReadWriteOnce
      size: 1Gi
    database:
      existingClaim: "harbor-database"
      storageClass: ""
      subPath: ""
      accessMode: ReadWriteOnce
      size: 1Gi
    redis:
      existingClaim: "harbor-redis"
      storageClass: ""
      subPath: ""
      accessMode: ReadWriteOnce
      size: 1Gi

若是想使用其他storageclass可这么配置(如果有自己的storageclass,则把类名换成对应类名)

代码语言:javascript
复制
persistence:
  enabled: true
  resourcePolicy: "keep"
  persistentVolumeClaim:
    registry:
      storageClass: "cbs"
    chartmuseum:
      storageClass: "cbs"
    jobservice:
      storageClass: "cbs"
    database:
      storageClass: "cbs"
    redis:
      storageClass: "cbs"

在value中有注释说明,这里省略了,一些关键点注释如,在配置前务必先将value的注释过一遍

如不想指定existingClaim,就不用配置,省略,后续创建harbor时会自动创建对应的pvc,并且配置为保留属性,harbor后续删除了也不会将pvc删除,保留数据盘。

由于整个value文件很长,上述只贴了个人认为比较核心的配置,在搭建过程中建议浏览一遍value文件。

精简过后的value 文件如下:

代码语言:javascript
复制
$ cat harbor-value.yaml

expose:
  type: ingress
  tls:
    enabled: true
  ingress:
    hosts:
      core: harbor.tke.com
      notary: harbor.tke.com
    annotations:
      ingress.kubernetes.io/ssl-redirect: "true"
      ingress.kubernetes.io/proxy-body-size: "0"
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-body-size: "0"
      kubernetes.io/ingress.class: nginx

externalURL: https://harbor.tke.com
persistence:
  enabled: true
  resourcePolicy: "keep"
  persistentVolumeClaim:
    registry:
      storageClass: "cbs"
    chartmuseum:
      storageClass: "cbs"
    jobservice:
      storageClass: "cbs"
    database:
      storageClass: "cbs"
    redis:
      storageClass: "cbs"

注意,在tke中若不指定storageclass,默认会使用cbs storageclass,此处起示范作用,在实际过程中可用其他 storageclass替换

3.3 创建harbor

代码语言:javascript
复制
#若是创建了精简的文件请用类似以下的命令
$ helm install --name harbor -f harbor-value.yaml ./harbor

#若是直接在value.yaml中修改的就无需加-f 参数指定
$ helm install --name harbor  --namespace default ./harbor
NAME:   harbor
LAST DEPLOYED: Tue Feb 25 17:04:37 2020
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME                         TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)            AGE
harbor-harbor-chartmuseum    ClusterIP  172.16.253.254  <none>       80/TCP             1s
harbor-harbor-clair          ClusterIP  172.16.252.131  <none>       8080/TCP           1s
harbor-harbor-core           ClusterIP  172.16.253.19   <none>       80/TCP             1s
harbor-harbor-database       ClusterIP  172.16.254.228  <none>       5432/TCP           1s
harbor-harbor-jobservice     ClusterIP  172.16.253.191  <none>       80/TCP             1s
harbor-harbor-notary-server  ClusterIP  172.16.255.135  <none>       4443/TCP           1s
harbor-harbor-notary-signer  ClusterIP  172.16.252.60   <none>       7899/TCP           1s
harbor-harbor-portal         ClusterIP  172.16.254.108  <none>       80/TCP             1s
harbor-harbor-redis          ClusterIP  172.16.254.13   <none>       6379/TCP           1s
harbor-harbor-registry       ClusterIP  172.16.253.232  <none>       5000/TCP,8080/TCP  1s

==> v1/Deployment
NAME                         DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
harbor-harbor-chartmuseum    1        1        1           0          1s
harbor-harbor-clair          1        1        1           0          1s
harbor-harbor-core           1        1        1           0          1s
harbor-harbor-jobservice     1        0        0           0          1s
harbor-harbor-notary-server  1        1        1           0          1s
harbor-harbor-notary-signer  1        0        0           0          1s
harbor-harbor-portal         1        0        0           0          1s
harbor-harbor-registry       1        0        0           0          1s

==> v1/StatefulSet
NAME                    DESIRED  CURRENT  AGE
harbor-harbor-database  1        1        0s
harbor-harbor-redis     1        1        0s

==> v1beta1/Ingress
NAME                   HOSTS                          ADDRESS  PORTS  AGE
harbor-harbor-ingress  harbor.tke.com,harbor.tke.com  80, 443  0s

==> v1/Pod(related)
NAME                                          READY  STATUS             RESTARTS  AGE
harbor-harbor-chartmuseum-85b75674f6-zpnn2    0/1    Pending            0         1s
harbor-harbor-clair-84b5864556-6rr54          0/2    ContainerCreating  0         1s
harbor-harbor-core-884766589-2t84b            0/1    ContainerCreating  0         1s
harbor-harbor-jobservice-577d9f4df7-9z858     0/1    Pending            0         1s
harbor-harbor-notary-server-789d854975-hpdzw  0/1    ContainerCreating  0         1s
harbor-harbor-notary-signer-6ccfd745bb-ccqls  0/1    ContainerCreating  0         1s
harbor-harbor-portal-5cbc6d5897-lr9rp         0/1    ContainerCreating  0         1s
harbor-harbor-registry-5fb56db945-xh7hp       0/2    Pending            0         0s
harbor-harbor-database-0                      0/1    Pending            0         0s
harbor-harbor-redis-0                         0/1    Pending            0         0s

==> v1/Secret
NAME                         TYPE    DATA  AGE
harbor-harbor-chartmuseum    Opaque  1     1s
harbor-harbor-clair          Opaque  3     1s
harbor-harbor-core           Opaque  7     1s
harbor-harbor-database       Opaque  1     1s
harbor-harbor-jobservice     Opaque  1     1s
harbor-harbor-notary-server  Opaque  5     1s
harbor-harbor-registry       Opaque  2     1s

==> v1/ConfigMap
NAME                       DATA  AGE
harbor-harbor-chartmuseum  23    1s
harbor-harbor-core         41    1s
harbor-harbor-jobservice   1     1s
harbor-harbor-registry     2     1s

==> v1/PersistentVolumeClaim
NAME                       STATUS   VOLUME  CAPACITY  ACCESS MODES  STORAGECLASS  AGE
harbor-harbor-chartmuseum  Pending  cbs     1s
harbor-harbor-jobservice   Pending  cbs     1s
harbor-harbor-registry     Pending  cbs     1s


NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://core.harbor.domain.
For more details, please visit https://github.com/goharbor/harbor.

3.4 查看ingress

由于这里创建的nginx-ingress用了loadbancer模式,所以创建了EXTERNAL-IP ,这时我们只要把域名的解析指向129.226.98.183 ,再通过域名即可访问harbor。

代码语言:javascript
复制
# kubectl get ingress
NAME                    HOSTS                           ADDRESS   PORTS     AGE
harbor-harbor-ingress   harbor.tke.com,harbor.tke.com             80, 443   21s

# kubectl get svc -l app=nginx-ingress
NAME                                    TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)                      AGE
ingress-nginx-ingress-controller        LoadBalancer   172.16.253.162   129.226.98.183   80:30377/TCP,443:30399/TCP   13m
ingress-nginx-ingress-default-backend   ClusterIP      172.16.252.178   <none>           80/TCP                       13m

4 访问harbor地址

如果你有真实的域名,可以直接把域名解析至ingress-controller的EXTERNAL-IP,由于为了方便演示,没有用真实的域名,直接把地址映射进了 /etc/hosts 文件

代码语言:javascript
复制
$ echo 129.226.98.183 harbor.tke.com >> /etc/hosts

windows也是直接映射即可。win10的地址存放在C:\Windows\System32\drivers\etc\

映射完成后,在浏览器输入harbor.tke.com,就能访问到熟悉的harbor Portal界面了

这里的用户名密码是默认的admin / Harbor12345,在value.yaml中有声明也可修改

5 docker login

harbor Portal 已经可以访问了,接来下要在节点上docker login harbor.tke.com

跟第四条一样,如果没有映射域名是无法login的

代码语言:javascript
复制
# docker login harbor.tke.com
Username: admin
Password: 
Error response from daemon: Get https://harbor.tke.com/v2/: x509: certificate signed by unknown authority

遇到上面的问题时,需要把证书保存在本地。

https://github.com/goharbor/harbor/blob/master/docs/1.10/install-config/configure-https.md

https://docs.docker.com/engine/security/certificates/

代码语言:javascript
复制
1. 创建存放证书目录
mkdir -pv /etc/docker/certs.d/harbor.tke.com

2. 从k8s中导出证书

kubectl get secret harbor-harbor-ingress -o jsonpath="{.data.ca\.crt}"|base64 --decode > /etc/docker/certs.d/harbor.tke.com/ca.crt

3. 测试登录

# docker login harbor.tke.com
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

测试推送镜像

代码语言:javascript
复制
$ docker tag busybox harbor.tke.com/library/busybox
$ docker push harbor.tke.com/library/busybox
The push refers to repository [harbor.tke.com/library/busybox]
195be5f8be1d: Pushed 
latest: digest: sha256:edafc0a0fb057813850d1ba44014914ca02d671ae247107ca70c94db686e7de6 size: 52

推送完成后,可以在harbor的界面看到这个镜像

还可以测试拉取镜像

代码语言:javascript
复制
$ docker rmi harbor.tke.com/library/busybox
Untagged: harbor.tke.com/library/busybox:latest
Untagged: harbor.tke.com/library/busybox@sha256:edafc0a0fb057813850d1ba44014914ca02d671ae247107ca70c94db686e7de6
$ docker pull harbor.tke.com/library/busybox
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:edafc0a0fb057813850d1ba44014914ca02d671ae247107ca70c94db686e7de6
Status: Downloaded newer image for harbor.tke.com/library/busybox:latest
$ docker images | grep harbor.tke.com/library/busybox
harbor.tke.com/library/busybox                               latest                           6d5fcfe5ff17        2 months ago        1.22MB

kubernetes 配置secret拉取镜像

若要使k8s pod可以拉取harbor私有的镜像,还需创建secret,并在workload中指定ImagePullSecrets

将config.json转换成 base64,然后写入到secret中

代码语言:javascript
复制
# 前提需先docker login harbor.tke.com

$ cat /root/.docker/config.json | base64 -w 0
ewoJImF1dGhzIjogewoJCSJoYXJib3IudGtlLmNvbSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOC4wNi4zLWNlIChsaW51eCkiCgl9Cn0=

$ cat harborkey.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: harborkey
type: kubernetes.io/dockerconfigjson
data:
    .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJoYXJib3IudGtlLmNvbSI6IHsKCQkJImF1dGgiOiAiWVdSdGFXNDZTR0Z5WW05eU1USXpORFU9IgoJCX0KCX0sCgkiSHR0cEhlYWRlcnMiOiB7CgkJIlVzZXItQWdlbnQiOiAiRG9ja2VyLUNsaWVudC8xOC4wNi4zLWNlIChsaW51eCkiCgl9Cn0= 

然后在yaml中声明imagePullSecrets

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: test-busybox
spec:
  containers:
  - name: test-busybox
    image: harbor.tke.com/library/busybox
  imagePullSecrets:
  - name: harborkey

总结

通过tke 以及helm工具,我们快速的创建出一个k8s集群并通过helm工具快速的部署了nginx-ingress、harbor,数据持久化存放在cbs中。由于大多数的组件以无状态(Deployment)的形式运行,若集群资源充足,可多启动几个副本并打散在不同作为高可用。其中database和redist以有状态(StatefulSet)运行。

可能会踩到的坑:

- 下载harbor镜像失败

例如节点在拉取镜像时,可能会因为不可抗拒的网络问题导致下载镜像失败的。在测试过程中用的是中国香港地域的节点,所以在拉取镜像时没有遇到问题,若在部署过程中遇到下载镜像失败的,通过其他方式拉取到镜像,再推送到国内的镜像仓库中,手动替换下workload中image的配置

- 使用自己的https证书

harbor的https证书是可以用自己申请的,默认helm chart中也有一个证书,若没有指定证书,则使用chart中提供的证书。若使用自带的证书,还需先将其转换成secret,并在value中指定secret namevalue.yaml:

代码语言:javascript
复制
  tls:
    # Enable the tls or not. Note: if the 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
     #如果要使用自己的TLS证书,请填写secret名称。
     #机密必须包含名为:
     #“ tls.crt”-证书
     #“ tls.key”-私钥
     #“ ca.crt”-CA的证书
     #如果未设置“ secretName”,这些文件将自动生成
    secretName: "harbor-tls-secret"

在创建harbor前先把secret创建好

代码语言:javascript
复制
$ kubectl create secret generic harbor-tls-secret --from-file=tls.crt=tls.crt --from-file=tls.key=tls.key --from-file=ca.cre=ca.crt

- storageclass

如果storageclass没有申请到存储资源,会导致pod无法正常启动

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Harbor
  • 前提条件
  • 集群
  • helm
    • 配置helm client
    • Ingress
    • harbor
      • 1. 添加harbor的helm库
        • 2. 将harbor下载到本地
          • 3. 配置value.yaml
            • 3.1 配置host,并指定ingress类型为nginx
              • 3.2 配置数据卷
                • 3.3 创建harbor
                  • 3.4 查看ingress
                    • 4 访问harbor地址
                      • 5 docker login
                      • kubernetes 配置secret拉取镜像
                      • 总结
                      相关产品与服务
                      容器镜像服务
                      容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档