k8s中部署Harbor私有容器仓库

写在前面:源自工作压力和对职业前景的迷茫,好久没更新技术文章了,以及售前岗对技术上手操作越来越少,写的笔记到也有不少,但都比较零散(只记录遇到的故障了)。


Harbor简介

Harbor 是VMware开源的一个私有化部署的注册表,是 CNCF 毕业项目,主要用于企业或个人搭建私有的容器镜像仓库,同时也支持作为 helmchart 仓库服务。

docker架构

部署规划

1. 部署规划

K8S部署高可用性Harbor

1.1. 应用访问入口规划

  1. 使用traefik ingress作为应用入口
  2. 启用https:通过traefik ingress启用https

1.2. 数据存储规划

  1. 使用外部PostgreSQL数据库,数据库已创建完成
  2. 使用内部Redis
  3. 使用S3存储 docker 镜像和 Helm charts 包
  4. 使用NFS创建Storage Class
序号 存储类型 存储信息 存储用途及备注
1 PostgreSQL13.11 主机:192.168.xxx.xxx:5432
数据库名:harbor
用户名:harbor
密码:*****
数据库
2 Redis 主机:
数据库名:
用户名:
密码:*****
缓存
3 s3存储 regionendpoint:https://s3.xdpai.site:8443
bucket:harbor
accesskey: pVEEWhUZx8NmIY9J
secretkey: zU6Yqz4op7i3z4dKo7NUPzFZMFdDuNQT
存储 docker 镜像和 Helm charts 包
4 Storage Class和PVC Storage Class的NFS服务地址:192.168.xxx.xxx
共享路径:/mnt/data01/k3s-nfs-sc01
harbor 本身服务(JobService 和 trivy 等)使用
  • 备注:
    • harbor 2.8.1部署时,PostgreSQL版本不能过高,否则notary-server和notary-signer容器内部报”Error starting postgres driver: pq: unknown authentication response: 10“错误。

2. 先决条件准备

  1. traefik ingress部署已完成
  2. 数据库、存储准备已完成
  3. 本章节重点配置存储类,创建harbor 本身服务存储使用的pv及pvc

2.1. 安装NFS CSI驱动器

  1. Kubernetes 不包含内部 NFS 驱动,k8s官方手册推荐使用“NFS subdir external provisioner”和“NFS Ganesha server and external provisioner”作为外部驱动,本次案例使用外部的NFS服务,所以provisioner使用“NFS subdir external provisioner”。

    2024年8月更新:最新发现k8s官方手册改为推荐“csi-driver-nfs”作为nfs的驱动程序,它的 CSI 插件名为 nfs.csi.k8s.io。

    注:网络不好的,请多次尝试或科学上网。

    1)通过kubectl联网安装(kubectl命令在脚本中,也可以用helm安装)
    root@op[~]# curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.9.0/deploy/install-driver.sh | bash -s v4.9.0 --
    或者:通过kubectl本地安装
    root@op[~]# git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
    root@op[~]# cd csi-driver-nfs
    ./deploy/install-driver.sh v4.9.0 local
  2. 检查 Pod 状态:

    root@op[~]# kubectl -n kube-system get pod -o wide -l app=csi-nfs-controller
    root@op[~]# kubectl -n kube-system get pod -o wide -l app=csi-nfs-node
  3. 查看 Kubernetes 集群中支持的所有 CSI 驱动程

    root@op[~]# kubectl get csidrivers
    NAME             ATTACHREQUIRED   PODINFOONMOUNT   STORAGECAPACITY   TOKENREQUESTS   REQUIRESREPUBLISH   MODES        AGE
    nfs.csi.k8s.io   false            false            false                      false               Persistent   0d

2.2. 创建存储类(StorageClass)

  1. 创建存储类

    1) 创建yaml文件
    root@op[~]# cat nfs-sc01.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
     name: nfs-client
     annotations:
       # 此操作是1.25的以上的一个alpha的新功能,是将此storageclass设置为默认
       storageclass.kubernetes.io/is-default-class: "true"
    # 此处指定了csidrivers的名称
    provisioner: nfs.csi.k8s.io
    parameters:
     # NFS的Server
     server: 192.168.xxx.xxx
     # NFS的存储路径
     share: /mnt/data01/nfs-sc01
     # csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
     # csi.storage.k8s.io/provisioner-secret-name: "mount-options"
     # csi.storage.k8s.io/provisioner-secret-namespace: "default"
    reclaimPolicy: Retain
    volumeBindingMode: Immediate
    mountOptions:
     # 这里不只可以配置nfs的版本
     - nfsvers=4.1
    2)通过yaml创建存储类资源
    root@op[~]# kubectl apply -f nfs-sc01.yaml
  2. 查看存储类

    root@op[~]# $ kubectl get sc
    NAME                   PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
    nfs-client (default)   nfs.csi.k8s.io   Retain          Immediate           false                  38d

2.3. PVC创建

harbor多个服务对应的存储可选择独立pvc;也可以选择共用一个pvc,通过子路径的方式区别不同服务的存储。本次使用共享pvc的方式,所以需要手动创建pvc

  1. 创建一个用于安装Harbor的Kubernetes命名空间。可以使用以下命令:

    root@op[~]# kubectl create namespace harbor
  2. 创建PVC的yaml文件

    root@op[~]# cat harbor-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
     name: harbor-pv-claim
     namespace: harbor
    spec:
     storageClassName: nfs-client  #从上述的存储类中自动申请pv并绑定
     accessModes:
       - ReadWriteOnce
     resources:
       requests:
         storage: 30Gi
  3. 创建PVC资源

    root@op[~]# kubectl apply -f harbor-pvc.yaml 

在 K8S 上部署 Harbor

安装Harbor可以使用Kubernetes Helm Chart来简化部署过程。以下是在Kubernetes上安装Harbor的基本步骤:

  1. 添加Harbor Helm Chart的仓库。可以使用以下命令:

    1. 首次安装执行:
    root@op[~]# helm repo add harbor https://helm.goharbor.io
    2. 如果之前添加过,请更新可用chart的信息,否则最新版查询不到
    root@op[~]# helm repo update harbor   //说明:此命令harbor是之前添加库的名称
  2. 查找harbor

    root@op[~]# helm search repo harbor -l     // -l参数显示每个chart的每个版本,不加-l参数将显示最新版本
    NAME            CHART VERSION   APP VERSION DESCRIPTION
    harbor/harbor   1.12.1          2.8.1       An open source trusted cloud native registry th...
    harbor/harbor   1.12.0          2.8.0       An open source trusted cloud native registry th...
    harbor/harbor   1.11.2          2.7.2       An open source trusted cloud native registry th...
    harbor/harbor   1.11.1          2.7.1       An open source trusted cloud native registry th...
    harbor/harbor   1.11.0          2.7.0       An open source trusted cloud native registry th...
  3. 从Helm Chart中提取配置文件。可以使用以下命令:

    root@op[~]# helm fetch harbor/harbor --version= --untar
    • 这里需要将<version>替换为您要安装的Harbor版本号,安装最新版本可省略此参数。
  4. 配置Harbor:可以编辑values.yaml文件以根据您的需要更改配置。一些重要的配置项包括Harbor的域名和数据库设置。

    #服务公开配置
    expose:
      # 设置如何公开服务,设置类型支持“ingress”、“clusterIP”、“nodePort”或“loadBalancer”,本项目以traefik ingress为例
      type: ingress
      tls:
        # 启用TLS.
        enabled: true
        # traefik ingress配置了默认的tls证书,所以不用配置入口TLS证书,certSource配置为none即可
        certSource: none
      ingress:
        hosts:
          core: harbor.xdpai.site
          notary: notary.xdpai.site
        # 设置 ingress 控制器类型:
        # 1. 大多数的 ingress 控制器使用 default 即可.
        # 如果使用 GCE ingress 控制器,设置为 gce
        # 如果使用 NCP (NSX-T Container Plugin) ingress 控制器,设置为 ncp
        # 如果使用 ALB ingress 控制器,设置为 alb
        # 如果使用 F5 BIG-IP ingress 控制器,设置为 f5-bigip
        controller: default
        annotations:
          # 不同的 ingress 控制器可能需要不同的ssl-redirect注释,这里以 traefik ingress 为例
          ingress.kubernetes.io/ssl-redirect: "true"
          ingress.kubernetes.io/proxy-body-size: "0"
          kubernetes.io/ingress.class: traefik
          traefik.ingress.kubernetes.io/router.entrypoints: websecure
          traefik.ingress.kubernetes.io/router.tls: "true"
          traefik.ingress.kubernetes.io/router.tls.certresolver: default
    
    # Harbor core 服务的外部URL,就是我们web界面访问的地址,也是 docker/helm 命令使用的地址
    # 格式: protocol://domain[:port]. 通常来说:
    # 1) 如果 "expose.type" 是 "ingress", 上述格式的 "domain" 的值是 "expose.ingress.hosts.core"
    # 2) 如果 "expose.type" 是 "clusterIP", 上述格式的 "domain" 的值是 "expose.clusterIP.name"
    # 3) 如果 "expose.type" 是 "nodePort", 上述格式的 "domain" 的值是 k8s 节点的 IP 地址
    # 如果Harbor部署在代理后面,则将其设置为代理的URL
    externalURL: https://harbor.xdpai.site
    
    # 存储配置
    persistence:
      enabled: true
      # 将其设置为 "keep" 以避免在 helm 删除过程中删除 PVC,但不包含内部数据库和 redis 组件创建的 PVC
      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-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: "registry"
          accessMode: ReadWriteOnce
          size: 5Gi
          annotations: {}
        chartmuseum:
          existingClaim: "harbor-pv-claim"
          storageClass: ""
          subPath: "chartmuseum"
          accessMode: ReadWriteOnce
          size: 5Gi
          annotations: {}
        jobservice:
          jobLog:
            existingClaim: "harbor-pv-claim"
            storageClass: ""
            subPath: "jobservice"
            accessMode: ReadWriteOnce
            size: 1Gi
            annotations: {}
        # If external database is used, the following settings for database will
        # be ignored
        database:
          existingClaim: "harbor-pv-claim"
          storageClass: ""
          subPath: "database"
          accessMode: ReadWriteOnce
          size: 1Gi
          annotations: {}
        # If external Redis is used, the following settings for Redis will
        # be ignored
        redis:
          existingClaim: "harbor-pv-claim"
          storageClass: ""
          subPath: "redis"
          accessMode: ReadWriteOnce
          size: 1Gi
          annotations: {}
        trivy:
          existingClaim: "harbor-pv-claim"
          storageClass: ""
          subPath: "trivy"
          accessMode: ReadWriteOnce
          size: 5Gi
          annotations: {}
      # Define which storage backend is used for registry and chartmuseum to store
      # images and charts. Refer to
      # https://github.com/docker/distribution/blob/master/docs/configuration.md#storage
      # for the detail.
      imageChartStorage:
        # Specify whether to disable redirect for images and chart storage, for
        # backends which not supported it (such as using minio for s3 storage type), please disable
        # it. To disable redirects, simply set disableredirect to true instead.
        # Refer to
        # https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect
        # for the detail.
        disableredirect: false
        # Specify the "caBundleSecretName" if the storage service uses a self-signed certificate.
        # The secret must contain keys named "ca.crt" which will be injected into the trust store
        # of registry's and chartmuseum's containers.
        # caBundleSecretName:
    
        # Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift",
        # "oss" and fill the information needed in the corresponding section. The type
        # must be "filesystem" if you want to use persistent volumes for registry
        # and chartmuseum
        type: s3
        s3:
          # Set an existing secret for S3 accesskey and secretkey
          # keys in the secret should be AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for chartmuseum
          # keys in the secret should be REGISTRY_STORAGE_S3_ACCESSKEY and REGISTRY_STORAGE_S3_SECRETKEY for registry
          #existingSecret: ""
          region: us-west-1   #必须填写,否则registry容器会异常,如果minio没有配置地区(region),填写默认的us-west-1即可
          bucket: harbor
          accesskey: pVEEWhUZx8NmI2dJ
          secretkey: zU6Y123op7i3z4dKo7NUPzFZ321DuNQT
          regionendpoint: https://s3.xdpai.site:8443
          encrypt: false
          #keyid: mykeyid
          secure: true
          #skipverify: false
          v4auth: true
          #chunksize: "5242880"
          rootdirectory: /
          #storageclass: STANDARD
          #multipartcopychunksize: "33554432"
          #multipartcopymaxconcurrency: 100
          #multipartcopythresholdsize: "33554432"
    
    # The initial password of Harbor admin. Change it from portal after launching Harbor
    harborAdminPassword: "Harbor1245"
    
    database:
      # if external database is used, set "type" to "external"
      # and fill the connection informations in "external" section
      type: external
      external:
        host: "192.168.xxx.xxx"
        port: "5432"
        username: "harbor"
        password: "xxxxxxxxxxxxxxxx"
        coreDatabase: "registry"
        notaryServerDatabase: "notary_server"
        notarySignerDatabase: "notary_signer"
    
    redis:
      # if external Redis is used, set "type" to "external"
      # and fill the connection informations in "external" section
      type: internal
  5. 安装Harbor:可以使用以下命令:

    root@op[~]# helm install harbor harbor/harbor -n harbor -f values.yaml
    • 这里的-n harbor表示将Harbor安装到名为harbor的Kubernetes命名空间中,-f values.yaml表示使用先前配置的值。
  6. 等待Harbor安装完成。可以使用以下命令检查Harbor是否已完全安装:

    root@op[~]# kubectl get pods -n harbor
    • 一旦所有Harbor的pod都处于"Running"状态,就可以访问Harbor了。
  7. 配置域名。如果您在values.yaml文件中设置了Harbor的域名,请将该域名解析到Harbor的IP地址上。

现在,您可以使用浏览器访问Harbor,并开始上传和管理容器

QA's

Q1:k8s中使用私有仓库x509问题

  • 解决方案:

    1. 下载harbor的ca证书
    2. 将harbor的ca.crt文件上传到所有k8s节点的/etc/ssl/certs目录,重启containerd服务即可
    root@op[~]# mv ca.crt /etc/ssl/certs/harbor.crt
    root@op[~]# systemctl restart containerd.service

微信扫一扫,分享到朋友圈

k8s中部署Harbor私有容器仓库
0
别把想做的事情,留给遥不可及的未来!

发表评论

您的电子邮件地址不会被公开。 必填项已用 * 标注

提示:点击验证后方可评论!

插入图片
返回顶部