k8s 1.28.2 集群部署 harbor v2.11.1 接入 MinIO 对象存储

提前准备

什么是 Harbor

  • Harbor 官网
  • Harbor Github
  • Harbor 是一个开源的制品仓库
  • 相比较 docker registry,它可以通过策略和基于角色的访问控制来保护镜像
  • Harbor 是 CNCF 毕业项目,提供合规性、性能和互操作性,帮助您跨 Kubernetes 和 Docker 等云原生计算平台一致、安全地管理镜像

Harbor 架构描述

  • Architecture Overview of Harbor
  • Proxy
    • 由 Nginx Server 组成的反向代理,提供 API 路由能力
    • Harbor 的组件,如核心、注册中心、Web 门户和 Token 服务等,都位于这个反向代理的后面
  • Core
    • Harbor 的核心服务,主要提供以下功能
      • API Server:接受REST API请求并响应这些请求的HTTP服务器依赖于其子模块,如’身份验证和授权’,‘中间件’和’API处理程序’
      • Config Manager:涵盖所有系统配置的管理,如身份验证类型设置、电子邮件设置和证书等
      • Project Management:管理项目的基础数据和相应的元数据,创建该项目是为了隔离托管项目
      • Quota Manage:管理项目的配额设置,并在发生新推送时执行配额验证
      • Chart Controller:将 chart 相关请求代理到后端 chartmuseum,并提供多个扩展来改善 chart 管理体验
      • Retention Manager:管理标签保留策略并执行和监控标签保留流程
      • Content Trust:为后端 Notary 提供的信任能力添加扩展,以支持内容信任过程的顺利进行。目前仅支持对容器镜像进行签名
      • Replication Controller:管理复制策略和注册表适配器,触发和监控并发复制过程
      • Scan Manager:管理由不同提供商调整的多个已配置扫描程序,并为指定对象提供扫描摘要和报告
      • Notification Manager(webhook):在 Harbor 中配置的机制,以便可以将 Harbor 中的工件状态更改填充到 Harbor 中配置的 Webhook 终端节点。相关方可以通过侦听相关的 webhook 事件来触发一些后续操作
      • OCI Artifact Manager:用于管理整个 Harbor 注册表中所有 OCI Artifact 生命周期的核心组件。它提供了 CRUD 操作来管理制品的元数据和相关添加,例如扫描报告、容器镜像和自述文件的构建历史、依赖项以及 helm 图表的 value.yaml 等,它还支持管理制品标签和其他有用的操作的能力
      • Registry Driver:实现为 Registry Client SDK,用于与底层 Registry 进行通信(目前为 docker 分发)。“OCI Artifact Manager” 依赖此驱动程序从清单中获取其他信息,甚至从位于底层注册表的指定对象的配置 JSON 中获取其他信息
  • Job Service
    • 通用作业执行队列服务,允许其他组件 / 服务使用简单的 restful API 同时提交运行异步任务的请求
  • Log collector
    • 日志收集器,负责将其他模块的日志收集到一个地方
  • GC Controller:管理在线 GC 计划设置,并启动和跟踪 GC 进度
  • Chart Museum:提供图表管理和访问 API 的第三方图表存储库服务器
  • Docker Registry:第三方注册服务器,负责存储 Docker 镜像和处理 Docker 推送 / 拉取命令。由于 Harbor 需要对镜像实施访问控制,Registry 会将客户端定向到 Token 服务,以获取每个 pull 或 push 请求的有效 Token
  • Notary:第三方内容信任服务器,负责安全地发布和验证内容
  • Web Portal:一个图形用户界面,可帮助用户管理 Registry 上的镜像
  • 数据存储相关
    • k-v storage:由 Redis 组成,提供数据缓存功能,并支持临时持久化 Job 服务的 Job 元数据
    • data storage:支持多种存储,作为 Registry 和 Chart Museum 的后端存储进行数据持久化(比如 s3 的 MinIO)
    • Database:存储 Harbor 模型的相关元数据,如项目、用户、角色、复制策略、标签保留策略、扫描仪、图表和图像。采用 PostgreSQL
  • 下面是 Harbor 2.11.1 版本相关组件对应的版本
组件 版本
Postgresql 14.10
Redis 7.2.2
Beego 2.0.6
Distribution/Distribution 2.8.3
Helm 2.9.1
Swagger-ui 5.9.1

Harbor 安装的先决条件

硬件资源

硬件类型 最小配置 推荐配置
CPU 2 CPU 4 CPU
内存 4 GB 8 GB
磁盘存储 40 GB 160 GB

软件依赖

软件 版本 描述
Docker 20.10.10-ce+ Docker 安装手册
Docker Engine documentation
Docker Compose v1.18.0+ 或者
docker compose v2 (docker-compose-plugin)
Docker Compose 安装手册
Docker Compose documentation
OpenSSL 越新越好 用于为 Harbor 生成证书和密钥

端口依赖

端口可以在配置文件中定义

端口 协议 描述
443 HTTPS 用户访问页面和接口 api 的 https 请求
4443 HTTPS 与 Harbor 的 Docker Content Trust 服务的连接
80 HTTP 用户访问页面和接口 api 的 http 请求

Harbor 在 k8s 的高可用

  • Harbor 的大部分组件现在是无状态的。因此,我们可以简单地增加 Pod 的副本,以确保组件分布到多个 worker 节点,并利用 K8S 的 “Service” 机制来确保 Pod 之间的连接
  • 至于存储层,预计用户为应用程序数据提供高可用性的 PostgreSQL、Redis 集群,以及用于存储图像和图表的 PVC 或对象存储

在这里插入图片描述

Harbor 部署

Helm 编排

这块可以直接看官方文档,这边不做详细的操作:Deploying Harbor with High Availability via Helm

YAML 编排

因为我的 pvc 是 MinIO 提供的,直接用 helm 会有很多问题,这里只能通过 YAML 编排来慢慢调整,下面的 YAML 文件都是基于 helm template 生成后做的修改

创建 namespace

namespace 的名字大家可以自己定义,这个没有什么指定的

kubectl create ns registry
导入镜像

如果没有针对机器做规划的话,可以每个节点先都导入进去

ctr -n k8s.io image import harbor.v2.11.1.tar.gz

这个时候会有下面的报错

ctr: archive/tar: invalid tar header

通过 file 命令查看压缩包

file harbor.v2.11.1.tar.gz

可以看到是一个 gzip 压缩类型的,这个不是 ctr 支持的格式,ctr 要求的是无压缩类型的 tar 包

harbor.v2.11.1.tar.gz: gzip compressed data, was "harbor.v2.11.1.tar", last modified: Thu Aug 15 10:07:54 2024, from Unix, original size modulo 2^32 1811445248

这个时候需要解压,然后重新压缩

tar xvf harbor.v2.11.1.tar.gz
rm -f harbor.v2.11.1.tar.gz
tar cvf harbor.v2.11.1.tar.gz ./

可以用 file 命令检查一下,正常是返回类似下面这样的内容,然后重新 import 导入镜像就可以了

harbor.v2.11.1.tar.gz: POSIX tar archive (GNU)
部署 Redis
  • 问了下 GPT,因为 MinIO 是对象存储,并不提供完全符合 POSIX 标准的文件系统功能(比如常规文件系统的权限管理),而 Redis 依赖于传统文件系统(如 ext4、xfs 等)来存储其数据文件(RDB、AOF)
  • 由于是自己练习的,这里 Redis 就直接绑定节点,用 local pv 来处理持久化
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: data-harbor-redis-0
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 1Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: data-harbor-redis-0
    namespace: registry
  hostPath:
    path: /approot/k8s_data/harbor-redis
    type: DirectoryOrCreate
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - 192.168.22.125
---
# Source: harbor/templates/redis/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: harbor-redis
  namespace: registry
  labels:
    app: harbor
spec:
  ports:
    - port: 6379
  selector:
    app: harbor
    component: redis
---
# Source: harbor/templates/redis/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: harbor-redis
  namespace: registry
  labels:
    app: harbor
    component: redis
spec:
  replicas: 1
  serviceName: harbor-redis
  selector:
    matchLabels:
      app: harbor
      component: redis
  template:
    metadata:
      labels:
        app: harbor
        component: redis
    spec:
      securityContext:
        runAsUser: 999
        fsGroup: 999
      automountServiceAccountToken: false
      terminationGracePeriodSeconds: 120
      initContainers:
      - name: init-dir
        image: goharbor/redis-photon:v2.11.1
        imagePullPolicy: IfNotPresent
        command: ["sh", "-c", "chown -R 999:999 /var/lib/redis"]
        securityContext:
          runAsUser: 0
        volumeMounts:
        - name: data
          mountPath: /var/lib/redis
      containers:
      - name: redis
        image: goharbor/redis-photon:v2.11.1
        imagePullPolicy: IfNotPresent
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        livenessProbe:
          tcpSocket:
            port: 6379
          initialDelaySeconds: 300
          periodSeconds: 10
        readinessProbe:
          tcpSocket:
            port: 6379
          initialDelaySeconds: 1
          periodSeconds: 10
        volumeMounts:
        - name: data
          mountPath: /var/lib/redis
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: "1Gi"
部署 PostgreSQL

PostgreSQL 和 Redis 一样,数据持久化目录涉及权限问题,这里也先绑定节点

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: database-data-harbor-database-0
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 10Gi
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: database-data-harbor-database-0
    namespace: registry
  hostPath:
    path: /approot/k8s_data/harbor-database
    type: DirectoryOrCreate
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - 192.168.22.124
---
# Source: harbor/templates/database/database-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: harbor-database
  namespace: registry
  labels:
    app: harbor
type: Opaque
data:
  POSTGRES_PASSWORD: "Y2hhbmdlaXQ="
---
# Source: harbor/templates/database/database-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: harbor-database
  namespace: registry
  labels:
    app: harbor
spec:
  ports:
    - port: 5432
  selector:
    app: harbor
    component: database
---
# Source: harbor/templates/database/database-ss.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: harbor-database
  namespace: registry
  labels:
    app: harbor
    component: database
spec:
  replicas: 1
  serviceName: harbor-database
  selector:
    matchLabels:
      app: harbor
      component: database
  template:
    metadata:
      labels:
        app: harbor
        component: database
    spec:
      securityContext:
        runAsUser: 999
        fsGroup: 999
      automountServiceAccountToken: false
      terminationGracePeriodSeconds: 120
      initContainers:
      # with "fsGroup" set, each time a volume is mounted, Kubernetes must recursively chown() and chmod() all the files and directories inside the volume
      # this causes the postgresql reports the "data directory /var/lib/postgresql/data/pgdata has group or world access" issue when using some CSIs e.g. Ceph
      # use this init container to correct the permission
      # as "fsGroup" applied before the init container running, the container has enough permission to execute the command
      - name: "data-permissions-ensurer"
        image: goharbor/harbor-db:v2.11.1
        imagePullPolicy: IfNotPresent
        securityContext:
          runAsUser: 0
        command: ["sh", "-c", "mkdir -p /var/lib/postgresql/data/pgdata && chmod -R 700 /var/lib/postgresql/data/pgdata && chown -R 999:999 /var/lib/postgresql/data"]
        volumeMounts:
          - name: database-data
            mountPath: /var/lib/postgresql/data
            subPath:
      containers:
      - name: database
        image: goharbor/harbor-db:v2.11.1
        imagePullPolicy: IfNotPresent
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        livenessProbe:
          exec:
            command:
            - /docker-healthcheck.sh
          initialDelaySeconds: 300
          periodSeconds: 10
          timeoutSeconds: 1
        readinessProbe:
          exec:
            command:
            - /docker-healthcheck.sh
          initialDelaySeconds: 1
          periodSeconds: 10
          timeoutSeconds: 1
        envFrom:
          - secretRef:
              name: harbor-database
        env:
          # put the data into a sub directory to avoid the permission issue in k8s with restricted psp enabled
          # more detail refer to https://github.com/goharbor/harbor-helm/issues/756
          - name: PGDATA
            value: "/var/lib/postgresql/data/pgdata"
        volumeMounts:
        - name: database-data
          mountPath: /var/lib/postgresql/data
          subPath:
        - name: shm-volume
          mountPath: /dev/shm
      volumes:
      - name: shm-volume
        emptyDir:
          medium: Memory
          sizeLimit: 512Mi
  volumeClaimTemplates:
  - metadata:
      name: "database-data"
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: "1Gi"
部署 Harbor core
---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值