专业的编程技术博客社区

网站首页 > 博客文章 正文

GreptimeDB 与 KubeBlocks 集成的实践经验

baijin 2024-10-29 13:09:52 博客文章 7 ℃ 0 评论

什么是 KubeBlocks?

KubeBlocks 是 ApeCloud 创建的开源云原生数据基础设施,旨在协助应用程序开发人员和平台工程师有效管理 Kubernetes 上的数据库和各种分析工作负载。

“KubeBlocks”这个名称源自“Kubernetes (K8s)”和“乐高积木”,旨在让 K8 上的数据基础设施管理像使用乐高积木进行构建一样高效、愉快。 KubeBlocks 支持多个云提供商,例如 AWS、Azure、Google Cloud Platform (GCP) 等,并提供声明式、统一的方式来提高 DevOps 效率。

目前,KubeBlocks 支持各种类型的数据库,包括关系型、NoSQL、向量、时间序列、图形和流处理系统。

为什么与 KubeBlocks 的集成很重要?

在 K8s 上构建数据基础设施变得越来越流行。 然而,这个过程中最具挑战性的障碍包括与各种云集成的困难、缺乏可靠的运营商以及 K8s 的陡峭学习曲线。

KubeBlocks 提供的开源解决方案不仅可以帮助应用程序开发人员和平台工程师为数据基础设施配置更丰富的功能和服务,还可以帮助非 K8s 专业人员快速构建全栈、生产就绪的数据基础设施。

通过与 KubeBlocks 集成,GreptimeDB 获得了更方便、更高效的集群部署方式。 此外,我们的用户还可以享受 KubeBlocks 提供的强大的集群管理功能,例如扩展、监控、备份和恢复。 那么为什么不充分利用它呢?

如何与 KubeBlocks 集成?

KubeBlocks 将集群所需的信息分为三类:

拓扑信息,即ClusterDefinition资源对象,定义了集群所需的组件以及这些组件如何部署。

版本信息,即ClusterVersion资源对象,定义了组件镜像的版本以及相关的配置信息。

资源信息,即集群资源对象,定义了CPU、内存、磁盘、副本数等资源。

KubeBlocks解耦了集群的拓扑、版本、资源信息,使得每个对象描述的信息更加清晰、集中。 这些对象的组合可以生成更丰富的簇。

描述集群的这三类对象之间的组成关系如下图所示:


其中,ComponentDef定义了集群中组件的部署信息,ComponentDefRef描述了对组件定义的引用。 在该参考中,可以定义与相应组件相关的各种对象信息(例如,在ClusterVersion的ComponentDefRef:A中,定义组件A使用的镜像版本为“最新”;在Cluster的ComponentDefRef:A中,定义组件A的副本计数) 分量 A 定义为 3,依此类推)。

基本上,集成 KubeBlocks 本质上是声明可以描述集群的拓扑、版本和资源的信息。

GreptimeDB集群整体架构

GreptimeDB集群架构由3个组件组成,分别是meta、frontend和datanode,请参见下图:



说明:

前端负责暴露不同协议的读写接口,将请求转发给datanode; 它属于无状态类型的组件。

datanode负责持久化存储数据; 它是有状态的。

元服务器负责前端和数据节点之间的协调; 它是无国籍的。 在本文中,我们假设meta使用的kv-store是etcd。

整合知识交流

要了解 GreptimeDB 与 KubeBlocks 的完整集成和操作细节,您可以参考以下 2 个 PR:

https://github.com/apecloud/kubeblocks/pull/4822

https://github.com/apecloud/kubeblocks/pull/4855

本文不会深入探讨详细的配置信息,只是分享一些集成过程中的经验,希望对您有所帮助。

跨组件引用

在集群中,可能存在一个组件引用另一组件的情况。 例如,在GreptimeDB集群中,前端组件引用元服务器和数据节点的服务地址。

KubeBlocks 引入了一个 componentDefRef 字段,方便跨组件值引用。 在下面所示的配置中,前端组件声明了对元组件的引用,该引用引用了元组件创建的服务名称。 该名称随后存储在 GREPTIMEDB_META_SVC 环境变量中,以便前端组件或其他相关组件可以访问它。 出于参考目的,可以使用 & 定义锚点,然后使用 * 调用。

componentDefs:
  - name: frontend
    componentDefRef:
      - &metaRef
        componentDefName: meta
        componentRefEnv:
          - name: GREPTIMEDB_META_SVC
            valueFrom:
              type: ServiceRef
    # ...
    containers:
      - name: frontend
        args:
          - --metasrv-addr
          - $(GREPTIMEDB_META_SVC).$(KB_NAMESPACE).svc{{ .Values.clusterDomain }}:3002
          # ...

  - name: datanode
    componentDefRef:
      - *metaRef
    podSpec:
      containers:
        - name: datanode
          args:
            - --metasrv-addr
            - $(GREPTIMEDB_META_SVC).$(KB_NAMESPACE).svc{{ .Values.clusterDomain }}:3002
            # ...

除了引用 Service 之外,KubeBlocks 还支持引用组件 Spec 或 Headless Services 中的 Field。

多个组件之间启动的顺序约束

通常,集群由多个组件组成,一个组件的启动可能取决于另一组件的状态。 以GreptimeDB集群为例,其四个组件(包括etcd)需要启动顺序为:etcd > meta > datanode > frontend。

当 KubeBlocks 部署集群时,它会同时启动所有组件。 由于每个组件的启动都是无序的,如果一个依赖组件在一个依赖它的组件之后运行,就会导致后者启动失败,触发重启事件。 例如,如果etcd在meta启动后运行,则会导致meta重新启动。 如果忽略组件的启动顺序,虽然集群最终能够成功部署,但是无疑增加了整体的部署时间,并且每个组件都会不必要地增加重启次数,这显然不太优雅。

考虑到K8s提供的Init Container功能,在需要对组件启动顺序进行顺序约束的场景下,可以引入initContainer来检测依赖组件的状态。 如下配置所示,与componentDefRef配合使用,meta server会等待etcd的Service创建完毕后才启动。

componentDefs:
  - name: meta
    componentDefRef:
      - &etcdRef
        componentDefName: etcd
        componentRefEnv:
          - name: GREPTIMEDB_ETCD_SVC
            valueFrom:
              type: ServiceRef
    podSpec:
      initContainers:
        - name: wait-etcd
          image: busybox:1.28
          imagePullPolicy: {{default .Values.images.pullPolicy "IfNotPresent"}}
          command:
            - bin/sh
            - -c
            - |
              until nslookup ${GREPTIMEDB_ETCD_SVC}-headless.${KB_NAMESPACE}.svc{{ .Values.clusterDomain }}; do
                echo "waiting for etcd"; sleep 2;
              done;
      # ...

敏捷的ConfigMap挂载

在ClusterDefinition的配置中,我们常常会不自觉地在组件的容器中挂载一个ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: greptimedb-meta
# ...
---
# ...
componentDefs:
  - name: meta
    podSpec:
      containers:
        - name: meta
          volumeMounts:
            - mountPath: /etc/greptimedb
              name: meta-config
            - 
          # ...
      volumes:
        - configMap:
            name: greptimedb-meta
          name: meta-config

仅当 Cluster、ClusterDefinition 和 ClusterVersion 对象位于同一命名空间内时,这种挂载方式才会生效。 如果它们在不同的命名空间中,那么ConfigMap的挂载就会失效,因为ConfigMap是Namespaced资源对象。

KubeBlocks 提供了 ConfigSpec Field 来解决上述问题。 如下配置所示,templateRef对应引用的ConfigMap的名称。

apiVersion: v1
kind: ConfigMap
metadata:
  name: greptimedb-meta
# ...
---
# ...
componentDefs:
  - name: meta
    configSpecs:
      - name: greptimedb-meta
        templateRef: greptimedb-meta
        volumeName: meta-config
        namespace: {{ .Release.Namespace }}
    podSpec:
      containers:
        - name: meta
          volumeMounts:
            - mountPath: /etc/greptimedb
              name: meta-config
          # ...

概括

本文分享了 GreptimeDB 与 KubeBlocks 集成的一些经验。 我们提出了集成过程中遇到的实际问题及其解决方案。

目前GreptimeDB仅集成了KubeBlocks的部署能力,还有很多丰富的功能尚未集成。 我们的目标是在未来集成更多的 KubeBlocks,我们欢迎您加入我们!

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表