简介: Kubernetes 的CRD 机制(CustomResourceDefinition)反对通过自定义的controller来治理资源的生命周期,这样就能够像操作pod,deployment一样来不便的治理运维一些简单的资源对象。随同着云原生这股技术浪潮,lindorm-operator充分利用k8s底座的特点与劣势,在云环境(包含公共云、公有云和混合云)极大晋升了Lindorm数据库的生产和运维效率背景介绍: 随着 Kubernetes 应用的越来越宽泛,k8s治理的native的对象资源有时并不能满足用户的需要,为了进步可扩展性,自 v1.7 以来,Kubernetes 引入了 CRD 机制(CustomResourceDefinition),简略的来说它容许用户定义本人的对象资源注册到集群中,并且通过自定义的controller来治理这些资源的生命周期,这样就能够像操作pod,deployment一样来不便的治理运维一些简单的资源对象。随同着云原生这股技术浪潮,lindorm-operator充分利用k8s底座的特点与劣势,在云环境(包含公共云、公有云和混合云)极大晋升了Lindorm数据库的生产和运维效率。 本文以lindorm-operator我的项目为例,深刻介绍了如何在 Kubernetes 中基于 Operator 模式实现自定义资源对象和控制器。Lindorm部署架构演进史 Lindorm是面向物联网、互联网、车联网等设计和优化的云原生多模超交融数据库,反对宽表、时序、文本、对象、流、空间等多种数据的对立拜访和交融解决。
Lindorm的整个部署架构大抵能够分为三个阶段,On 物理机–> On ECS –> On K8S ,晚期输入时大部分是on 物理机的部署状态,在2020年私有云商业化时开始以On ECS状态输入,尽管实现服务全面上云,然而整个架构上并没有全面云原生化,到了2021年左右在混合云输入状态构建上开始全面拥抱云原生,所有组件都On k8s部署,生产层只依赖Operator,实现了真正意义上云原生化。尽管倒退工夫不长,然而管控架构基本上走的比拟靠前,充沛汲取云原生演进路线上的红利,让Lindorm生产效率越来越高。其余两种状态本文就不做重点介绍了,次要介绍On k8s模式的设计细节和实际。Operator技术体系 Operator 能够看成是 CRD 和 Controller 的一种组合特例,Operator 是一个特定的应用程序的控制器,通过扩大 Kubernetes API 资源以代表 Kubernetes 用户创立、配置和治理简单应用程序的实例,通常蕴含资源模型定义和控制器,通过 Operator 通常是为了实现某种特定软件(通常是有状态服务)的自动化运维。controller根本工作原理:
上图图展现了 controller 的工作原理,实际上是一个事件监听变更再变更的循环流程,以一个pod变更为例对照该图阐明下go-client的外围组件和咱们的controller是如何配合工作的:go-client在初始化时,Reflector 会先 List API 取得所有的 Pod,并放入本地缓存Informer 初始化实现之后,Reflector 开始监听 Pod变更相干的工夫;如果此时 pod_1 被删除,那么 Reflector 会监听到这个事件Reflector 将 pod_1 被删除 的这个事件的callbacks通过一个本地队列(DeltaFIFO) 存入workqueueworker(实际上就是咱们业务的controller)从队列中 取出事件处理Controller 通过比照资源对象的理论状态和最终状态的差别,执行业务逻辑,并一直调谐达到最终状态。 尽管client-go曾经封装了 controller-runtime 和 controller-tools,用于疾速构建 Operator,然而从头开始去构建一个 CRD 控制器并不容易,须要对 Kubernetes 的 API 有深刻理解,还须要本人实现和api-server的一些交互细节。为了解决这个问题,社区就推出了对应的简略易用的 Operator 框架,比拟支流的是 kubebuilder 和 Operator Framework,这两个框架的应用基本上差异不大,咱们能够依据本人习惯抉择一个即可。Lindorm+Operator的问题与挑战 Lindorm之前的部署状态是On ecs的,管控的架构基于pengine,通过工作流编排来实现实例的生命周期治理,这套架构须要管控侧须要感知很多调度细节。而Lindorm和Operator结合能把资源的调度,节点的弹性伸缩能力,平安隔离等个性更好的下沉到K8S集群,充分利用云原生技术红利实现一套Lindorm CR定义和一个Operator组件能在各种简单环境轻松交付lindorm实例。为达成这个指标,从相应零碎的设计,开发,构建,部署,交付,监控及运维等整个利用生命周期各环节都须要被重塑。从Lindorm集群自身的治理上看,外围要求次要有以下几个:体验降级: 实例创立,监控报警,排障定位等须要做到通顺与简略,整体流程要比之前效率更高弹性按需扩缩容能力: 依据业务负载灵便动态分配或开释资源容错&平安能力:宕机迁徙,故障隔离,负载平衡等可观测性:丰盛且细粒度的监控指标,可长久化的提供查问多状态集群兼容:目前Lindorm状态十分丰盛,有单机版,集群版,多可用区版本,基于存储池的serverless版本,须要在一套operator架构下实现多种状态编排 尽管K8S为咱们提供了根底的workload、存储,网络的调度和治理能力,然而如何将这些能力充分利用起来是Operator面临的挑战,LindormOperator是集群内实例生命周期治理和运维的入口,Lindorm集群的生产和运维就是Operator通过正当的编排调度K8S的原生资源来实现的,如下图所示operator会继续监听K8S原生资源和Lindorm CR的状态变动,并做出响应的动作,通过一直的reconcile使Lindorm集群最终达到咱们想要的状态,所以operator是Lindorm生产层的要害组件,对于workload,存储相干技术计划的选型和思考间接影响着Lindorm的性能是否在K8S上充分发挥,上面会围绕这些问题和挑战重点介绍lindorm-operator的一些次要设计逻辑和技术选型的一些思考。
技术计划整体架构 Lindorm的部署架构经验了物理机 -> 虚拟化(On ecs) -> 云原生化(On k8s)的逐渐演进,目前在私有云的售卖状态是On ECS,私有云基于存储池的On K8s云原生架构也已将上线,整体架构如下图所示:
其中,LindormCluster 是由 CRD(CustomResourceDefinition)定义的自定义资源,用于形容用户冀望的 Lindorm 集群状态, 集群的编排和调度逻辑则由下列组件负责:Lindorm-Controller是一组 Kubernetes 上的自定义控制器。这些控制器会一直比照 LindormCluste 对象中记录的冀望状态与 Lindorm 集群的理论状态,并调整 Kubernetes 中的资源以驱动 Lindorm 集群满足冀望状态;Lindorm-webhook 是一个 Kubernetes api的拦截器,会对外部传入的Lindorm CR做一些参数校验或者减少默认参数配置,也可拦挡局部高位操作,比方集群开释等。 实例部署拓扑&生命周期治理 实例资源编排肯定是基于部署拓扑的,为了保障内核组件架构的一致性,On K8S架构下内核组件的部署拓扑和私有云目前售卖状态根本保持一致,具体如下图所示:
实例创立和弹性变配都是通过批改Lindorm CR实现,只有通过kube api能够很不便的批改Lindorm资源,从管控视角和运维视角就有统一的体验,能够防止很多反复建设的工作,下图就是Lindorm实例变更时各个组件的交互逻辑。
以实例生产和变更流程为例,阐明外部的流程:用户通过API Server CURD LindormCluster,客户端能够是kubectl,也能够是其余各种状态的k8s ClientLindormCluster controller 依据用户写入的LindormCluster,依据依赖关系 别离创立出LindormZK, LindormStore ,LindormTable, LindormTSDB, LindormSearch资源子资源的Controller 组合出所需的configMap, StatefulSet, CommonService, HeadlessService, Ingress, 并顺次创立这些资源。子资源的controller 监听 各自资源(statefulSet, service,ingress) 的状态, 并通过API Server更新到etcdLindormCluster Cluster 承受到子资源的更新event,更新Lindorm Cluster 的Status,通过API Server 更新的etcd用户通过GET LindormCluster/status 获取到整个集群的状态信息
外围设计要点将Lindorm资源从部署拓扑角度进行拆分,每个组件都有独立的Controller,这样组件间的事件就互相独立,晋升reconcile流程的稳定性;Lindorm CRD定义尽量简化,对外只裸露资源相干的参数,将编排细节内聚在Operator外面充分利用K8S的调度策略实现pod的打散,保障同类引擎的pod扩散在不同pod,防止大量节点异样导致计算引擎服务异样对于有状态服务敞开驱赶策略,不容许pod漂移,这样能够尽量大量pod被删除的危险架构劣势节约老本通过Operator调度具备更高效的资源变配能力,疾速弹性可通过存储池化调度,大大降低存储老本体验降级交付老本大大降低,可实现标准化交付流程屏蔽底层硬件,升高运维老本,当节点出现异常时可通过pod漂移重布解决实例生产速度和效率大大晋升,用户体感更好充分利用底座调度能力,管控调度逻辑更清晰,让开发更丝滑升高复杂度晋升管控开发迭代效率,组件依赖缩小没有简单的元数据依赖关系技术选型的思考 Lindorm作为一款数据库产品在迁徙到k8s的过程中也遇到了不少问题,因为k8s的调度设计对无状态的服务是有人造的敌对性,但对于Lindorm这种重存储的产品来说会面临诸多挑战,上面别离从workload,存储和网络三个方面来介绍lindorm在k8s上实际的一些思考。Workload选型 在谈workload选型前咱们能够先思考下数据库这种重存储、有状态的服务对部署的根本要求有哪些,在我看来 最根本的个性次要有4个: (1) 稳固的网络: Pod须要具备稳固的网络标识,因为这个数据可能会被长久化; (2) 稳固的存储: 存储不随pod的状态变动而有所扭转; (3) 平安可控的降级:灰度可控的降级和重启 (4)运维可控:具备指定pod降级的能力,有状态节点运维会波及主从节点切换,须要按需降级K8S内置了 Pod、Deployment、StatefulSet 等负载类型(Workload)。 Pod是k8s最小的调度、部署单位,由一组容器组成,它们共享网络、数据卷等资源。通过 Pod 胜利将业务过程容器化了,然而 Pod 自身并不具备高可用、主动扩缩容、滚动更新等个性,因而为了解决以上挑战,Kubernetes 提供了更高级的 Workload,次要有Deployment和Statefuleset,前者次要针对无状态服务场景,生成的pod名称是变动的,无稳固的网络标识,而statefulset为每个 Pod 提供惟一的名称、固定的网络身份标识、长久化数据存储、有序的滚动更新公布机制。基于 StatefulSet 能够比拟不便的将 etcd、zookeeper 等组件较繁多的有状态服务进行容器化部署。 应用Statefulset益处是能够复用局部已有的能力,实现横向扩大的能力。然而业务诉求是多样化的,以Lindorm为例,Statefulset尽管能满足各个节点根本的部署和扩大需要,然而对于运维场景的非凡需要就无奈满足,比方Pod不重建、反对原地更新,或者按需降级等等。 为了满足业务上述的原地更新、指定Pod更新等高级个性需要,阿里的开源我的项目 Openkruise 就蕴含一系列 Kubernetes 增强型的控制器组件,包含 CloneSet、Advanced StatefulSet、SideCarSet等,CloneSet 是个专一解决无状态服务痛点的 Workload,反对原地更新、指定 Pod 删除、滚动更新过程中反对Partition, Advanced StatefulSet 顾名思义,是个加强版的 StatefulSet, 同时反对原地更新、暂停和最大不可用数。这些个性给运维带来了极大的便当,Lindorm在有状态节点的编排上也是用了Openkruise存储层技术选型 存储是Lindorm数据库系统十分重要的一部分,存储要求稳固、可用、性能、牢靠。在用户看来存储就是一块盘或者一个目录,用户不关怀盘或者目录如何实现,用户要求十分“简略”,就是稳固,性能好。为了可能提供稳固牢靠的存储产品,各个厂家推出了各种各样的存储技术和概念。无论是开源的存储我的项目还是商业的存储产品,评估办法具备普适性,次要从以下几个方面来思考:数据可靠性数据可靠性是指数据不失落的概率。通常状况下,存储产品会给出几个9的数据可靠性,或者给出最多容许故障盘/节点个数。存储采纳不同的数据冗余策略,提供的可靠性是不一样的。数据可用性数据可用性和数据可靠性很容易被混同,可用性指的是数据是否在线。比方存储集群断电,这段时间数据是不在线,然而数据没有失落,集群恢复正常后,数据能够失常拜访。存储性能次要分为容量型场景和时延敏感的在线场景 Lindorm在k8s上是容器化部署,可选的存储计划从大的方面能够分为本地存储和网络存储: 本地存储:如HostPath,emptyDir等,这种存储的特点是数据保留在集群的节点上,不能跟着pod漂移,节 点宕机数据不可用,然而长处是读写性能高; 网络存储:Ceph、Glusterfs、NFS,OSS等类型,这些存储卷的特点是数据不在集群的某个节点上,而是在远端的存储服务上,应用存储卷时须要将存储服务挂载到本地应用,性能上较本地存储差。 Lindorm作为一款高性能的多模数据库,网络存储会大大降低读写性能,而且网络存储的带宽也极易造成性能瓶颈,所以在这个大方向上Lindorm首选还是本地存储。然而选用本地存储就会丢失K8S对于存储pv治理的很多便利性,所以为了保障在应用本地盘的同时有能做到调度的便当,Lindorm在比照以下多种技术计划后应用了Pod独占本地盘的模式: HostPath模式:须要治理具体的物理盘,包含感知具体盘符,格式化,目录创立等,从目录创立到挂载是一个动态过程,也就是只能”写死“,扩展性太差,个别很少应用这种计划 Local PV:local pv的要害核心技术点是容量隔离(lvm、xfs quota)、IO隔离、动静provision等问题 (1)基于volumeGroup: VG屏蔽了多个物理磁盘,pod应用时只需思考空间大小的问题,帮咱们屏蔽了底层硬盘带来的复杂性。然而这种计划也导致一份残缺的数据被散布到多个磁盘上,任何一个磁盘上的数据都是不残缺,也无奈进行还原,一块磁盘的抖动影响面会成倍放大。 (2) pod独占盘:每个pod绑定的pv独占一块盘的存储,这种模式能够防止下面基于volumeGroup造成的数据扩散,pv数据与盘强相干,有利于故障隔离。比较简单的实现形式就是,为每一块盘创立一个独立的pv,pod申明对指定的pv的绑定,就能实现pod的单盘的独占。在K8S的实现角度能够通过动态PV或者动静pv实现这种绑定,然而动静PV须要依赖k8s csi插件的反对。 动态PV:
动静PV:
回到Lindorm的场景,咱们的数据节点根本要求是高性能和高牢靠,并且在存储池的部署场景下,存储节点是多租状态,对于故障隔离的要求尤其高,因而咱们抉择了本地盘独占的存储计划,在调度上,ASI上曾经实现了基于此种场景的CSI插件,能够满足此种场景;针对其余不满足条件的规范ACK,咱们也能够应用动态pv实现,只是须要提前创立好相干pv。网络技术选型 网络架构是Kubernetes中较为简单、让很多用户头疼的方面之一。Kubernetes网络模型自身对某些特定的网络性能有肯定要求,但在实现方面也具备肯定的灵活性。因而,业界已有不少不同的网络计划来满足特定的环境和要求。在基于 CNI 实现的各种 Kubernetes 的网络解决方案中(例如Flannel,Calico等),按数据包的收发模式实现可分为 underlay 和 overlay 两类。前者是间接基于底层网络,实现互联互通,领有良好的性能,后者是基于隧道转发,它是在底层网络的根底上,加上隧道技术,构建一个虚构的网络,因而存在肯定的性能损失。对于不同网络插件实现的技术细节本文就不扩大来讲了。
Lindorm在考量网络分案选型时充沛联合了Lindorm本身的业务特点和部署状态来思考,从技术上来看,以后风行的几种CNI的网络插件等都能满足lindorm的根本诉求,然而这种Overlay的网络会有肯定的性能损失,因而在综合性能和调度便利性上Lindorm在不同的部署场景心愿抉择的不同的网络计划。在基于Lindorm存储池状态下,因为存储池的Node是属于咱们强管控的资源,其网络资源都是提前布局好的,并且存储池Pod在部署状态上也充沛做了打散,数据节点独占Node,因而为了最大限度利用节点的网络性能,存储池没有用基于CNI的计划,间接应用HostNet,Operator可能在节点调度上保障不会存在端口抵触的场景。而引擎层因为基于弹性eci部署,应用了underlay网络terway。容错运维能力设计 Lindorm的局部容错能力曾经内置到内核中,例如故障主动转移,备份与复原都由内核实现,在日常运维中更多是重启局部节点或者调整集群参数来修复线上问题,目前反对的运维能力次要有根底运维和配置变更两类。根底运维 LindormOperator还没有配套的白屏化的运维控制台(能力正在建设中),次要的运维操作都通过黑屏形式操作;对于一些标准化的运维动作曾经实现了一个巡检CronJob,能够对集群的状态做巡检并做出对应的运维操作,例如集群的容量水位爱护就通过这种形式实现,水位超过90%会触发写爱护,爱护引擎不会被写挂,后续还会在此基础上反对更多的能力。
主动运维次要流程如下:1.集群中减少cronjob角色,由lindorm-operator创立,定期拉起pod运行巡检工作;2.cornjob检测异样下发lindorm-operator的customResource;3.加强sre能力,sre通通过拉取sre operator执行特定的运维动作;集群动静配置更新 在日常运维过程中大部分动作是批改集群的参数解决问题,基于此Lindorm-operator中实现一套动静配置更新的机制,惯例做法是登录到容器中批改配置而后重启容器,然而当节点比拟多时效率就会很低。实现思路如下图所示,LindormOperation的的CRD定义了具体的操作类型和操作的相干参数,并创立对应的资源,Lindorm的所有POD都会内置一个SER Container,这个Container实际上也是一个“小operator” ,会监听以后所在pod的operation事件,而后进行解决,配置的批改就是通过SRE Container批改和MainContainer共享的Volume下的配置文件实现,对于须要重启能力失效的配置变更,Sre还会触发MainContainer的重启。
Operator高可用建设Operator可观测性对于Operator的可观测次要蕴含两局部,一个是集群reconcile事件的trace,一部分是性能指标的监控Trace可观测性: 咱们对每一个组件的Controller的Trace日志都定义了一个独立的event,能依据trace检索每一次reconcile事件的步骤细节,能够帮忙研发疾速定位问题。Metric可观测性: Operator在启动的时候就开启了监控数据采集端口,反对promethues的servie monitor拉取operator的性能数据,次要包含根底的性能指标和Controller Runtime指标,并可根据此监控配置promethues报警,在集群呈现事件异样时能够提前感知。宕机复原 Lindorm Operator是一个齐全无状态的服务,通过Deployment部署到k8s集群中,具备readness和liveness检测,在服务异样时能够从新被拉起,同时所有的reconcile逻辑都做了幂等性保障,这样即便Operator异样宕机在复原后也能从新处理事件。Leader Election 在Kubernetes中,通常kube-schduler和kube-controller-manager都是多正本进行部署的来保障高可用,而真正在工作的实例其实只有一个。这里就利用到 leaderelection 的选主机制,保障leader是处于工作状态,并且在leader挂掉之后,从其余节点选取新的leader保障组件失常工作。Lindorm operator通过Kubebuiler构建,反对配置化的leadelection 基本原理其实就是利用通过Kubernetes中 configmap , endpoints 或者 lease 资源实现一个分布式锁,抢(acqure)到锁的节点成为leader,并且定期更新(renew)。其余过程也在一直的尝试进行抢占,抢占不到则持续期待下次循环。当leader节点挂掉之后,租约到期,其余节点就成为新的leader。通过这个个性就能够在Operator多正本部署时主动实现主备切换,大大晋升可用性。 总结 Lindorm作为一款多模数据库其组件数量和编排复杂度在数据库产品中是比拟少见的,之前的On ecs的架构整体编排逻辑十分重,而通过拥抱云原生技术,通过Operator将大部分编排细节大大简化了,通过Statefulset拉起外围组件,用ConfigMap治理配置,通过Service裸露服务,全面拥抱k8s技术生态让Lindorm的交付体系更加的标准化,可移植;能同时满足混合云和私有云场景输入。原文链接:https://click.aliyun.com/m/10…本文为阿里云原创内容,未经容许不得转载。
发表回复