明天给大家分享的内容是 Alluxio Operator 的一体化部署计划。我会将内容分成 4 个局部来给大家解说。
首先,介绍 Kubernetes 容器化部署和以后所面临的挑战。
而后,引入 operator 的概念,介绍以后业界对于 Kubernetes 容器化部署问题的支流解决方案。
接着,解说如何针对应用服务去实现对应的 operator。
最初用 Alluxio 作为理论案例展现 operator 是如何实现的。
一、Kubernetes 容器化部署所面临的挑战
目前 Kubernetes 曾经是业界比拟支流的容器化部署计划,次要因为它对当初的容器化反对十分好,然而同时它也存在一些问题。咱们具体看一下 Kubernetes 容器化部署的过程,以 Presto 为例,部署 Presto、将 Presto 上云,须要做哪些事件?
第一步:梳理组件上云之后须要部署哪些 Kubernetes 资源。咱们把利用打包成容器镜像,传到云仓库外面。
第二步:设计部署组件所须要的 Kubernetes 资源。如上图就展现了 Presto 在 Kubernetes 上的部署架构。因为 Presto 组件蕴含了 coordinator 和 worker 两个不同的角色,所以咱们针对这两个不同角色的配置须要有对应的 ConfigMap 资源,而且对 coordinator 和 worker 别离都须要有 Deployment 撑持部署。此外,为了买通 worker 与 coordinator 的网络通讯,咱们还须要一个 Service 资源。有了这样一个部署架构图之后,咱们还要去思考到底要按什么样的程序提交资源。比方对 Presto 来说,咱们须要提交 Service、Deployment,还有 ConfigMap,这些资源都是通过 yaml 文件形容的,它们之间有先后顺序,有肯定的依赖关系。比方在这个例子里,咱们要先提交 ConfigMap,再基于 ConfigMap 创立 Deployment,有了 Deployment 之后,咱们再去部署 Service。至此,咱们发现须要有先后顺序做部署组件,这样就带来了一些问题:
首先它带来的第一个问题就是所波及到的 Kubernetes 资源可能有多个,保护起来很不不便。尤其是对于很多大数据存储和计算畛域外面的中间件,可能波及到十分多的依赖,甚至包含一些上游上游的撑持组件。
在 Kubernetes 上要跑起来,须要多个 yaml 文件。比方以 Presto 为例,它须要的 yaml 文件有 5 个,咱们如果要去实现 Presto 上云,就要保护多个 yaml 文件,这就导致了第二个问题,当咱们须要批改某一个配置的时候,其实咱们不仅要批改某一个 yaml 文件,可能还要批改所波及到的跟它相关联的 yaml 文件。假如咱们要批改容器的镜像版本,咱们应该只须要批改某一个文件的镜像版本即可,但事实上,因为整个架构外面波及到多个 yaml 文件、多个 Kubernetes 资源,所以这就导致了至多批改两个文件,批改起来非常复杂。又假如咱们要批改服务的端口,从 8080 改成 8081,会导致保护的复杂度变高,要改多个文件。诸如此类的批改操作,就导致减少了运维复杂度。
第三个问题是一个组件其实是由多个资源独特撑持而实现,然而这些资源的状态又是互相独立的。咱们无奈从更形象更高维度的层级去监控所有资源的信息。比方刚刚提到的这些 Kubernetes 资源,独特组成了一个集群。但咱们无奈主动收集集群的应用状况,因为不同资源之间互相独立,而它们各自的日志只局限于本人自身。假如咱们想依据集群的状况进行主动扩缩容,这个时候须要手动依据集群的状况去做扩缩容。咱们只能晓得某一个资源在某个时刻产生了变更,但无奈晓得集群到底什么时候产生了变更,要获取到这些信息,须要在更形象的层级下能力实现。再比方,咱们无奈在集群的层面做主动备份容灾,如果忽然遇到了一个需要,要下线一批机器,须要对机器上的数据进行迁徙,那么这个时候只能手动做这些事件,通过手动调整 Kubernetes 的配置来实现。一方面须要很大的人力保护老本,另一方面即便可能通过手动实现,也很难跟踪到集群在何时做了哪些变更,只能看 Kubernetes 的内置日志,因而,咱们也无奈很好地做到弹性扩缩容。
诸如 Presto 这样的计算引擎,白天可能用的人较多,申请量很大,这时候须要的资源就比拟多,能够适当地给它裁减一些资源,然而到了早晨,或者是一个业务比拟闲置的状况下,其实大部分的资源就能够回收起来,去做一些别的事件。比方留给 spark 或者 Flink 做 ETL,节俭资源缩小耗费,也相当于是在省钱。
二、对于 Kubernetes 容器化部署问题的支流解决方案
咱们看到了诸多 Kubernetes 容器化部署所遇到的挑战,相应地,业界为了解决这些问题,提出了 Operator 的概念。咱们先来回顾一下,Kubernetes 的资源包含哪些货色?咱们要把一个利用部署到 Kubernetes 集群里,常常会用到的资源包含:PV、PVC、StatefulSet、CronJob、DaemonSet、ConfigMap、Secret 等。
这些资源在 Kubernetes 中属于内置资源,兴许咱们会有疑难,Kubernetes 为什么可能监听到咱们提交的这些资源?
上图展现了三个资源文件,别离是 Service、Deployment 和 ConfigMap,其中 Deployment 援用了 ConfigMap 中的属性内容,而 Service 则给 Deployment 提供了一个网络拜访的反对。Service、Deployment 和 ConfigMap 这三种资源类型都是 Kubernetes 内置的。
当用户通过 kubectl 创立一个 Deployment 资源时,kubectl 外部会通过 Kubernetes API Service 将申请提交到 Kubernetes 集群。此时,Kubernetes 内置的 Deployment Controller 监听到了用户提交创立 Deployment 资源的申请事件,并负责解决申请。所谓 Controller,能够了解为一个始终挂在集群中运行的守护过程。具体来说,用户提交的申请实际上会插入到一个被 Deployment Controller 监听的队列里,当队列中有新的申请进来时,Deployment Controller 就会负责解决。当 Deployment Controller 从队列中获取到申请事件之后,它会进一步解析资源中的属性,而后比照集群中的资源和用户提交的 Deployment 资源,判断状态、属性是否统一,当呈现不统一的时候,Deployment Controller 就会执行一些措施来扭转目前的状态,让它可能变成用户所冀望的状态。
比方,假如用户提交了一个 Deployment 资源,Deployment Controller 发现以后集群里不存在这样的一个资源,那么它就会创立新的 Deployment,依照申明里的正本数创立相应数量的 POD,并且依照所指定的镜像版本从镜像仓库里拉取镜像。当用户更新了 Deployment 时,在队列里相应地也会呈现一个 update 事件。
Deployment Controller 会比照现有 Department 的状态,如果它发现镜像的版本产生了变更,就会把原来的容器删掉,从新拉取新的镜像,用新的镜像创立新的容器。
上述就是内置 Kubernetes 资源 Controller 的原理,Kubernetes 里的每一种资源都有一种对应的 Controller,比方 Deployment 对应有 Deployment Controller,StatefulSet 对应有 StatefulSet Controller。
一般来说,部署一个服务利用会波及到很多不同的 Kubernetes 内置资源,正如方才介绍的部署 Presto 的例子,须要将 Kubernetes 提供的这些内置资源组合起来,借助这种组合的形式能力实现部署集群的目标。此时咱们无妨能够想一想,是否能够有一个自定义的定制资源来代替那些资源的组合呢?比方假如要部署 Presto,如果存在一个叫做 Presto 的资源,同时让 Kubernetes 具备一个 Presto Controller 来监控 Presto 资源,并且主动创立 ConfigMap、Deployment 和 Service,这样就省去手动创立、校验等步骤。此外,当咱们批改某一个配置时,也不须要同时批改相干的资源。
Kubernetes 为咱们提供了 customer resource 定制资源。customer resource 容许咱们创立一个自定义的资源,并且能够定义资源外面蕴含哪些属性(比方 image 属性)。单纯定义 customer resource 依然是不够的,因为当咱们将定义好的 customer resource commit 到 Kubernetes 之后,此时 Kubernetes 并不知道该如何去解决,它只能校验 customer resource 的定义是否非法。它并不知道如何依据 customer resource 的属性去创立 deployment ConfigMap 等内置资源。因而,咱们依然须要去实现这样一个自动化程序(即定制资源的 controller)。在此基础上,Operator 的概念就是一个定制资源加上绝对应定制资源的 controller。
方才咱们以 Deployment 为例解释了 Kubernetes 的 controller,介绍了它是如何和用户提交的 deployment 资源产生作用进而实现 Kubernetes Deployment 部署的。
同样地,如果咱们要定义一个名为 Presto 的 customer resource,首先须要提交一个 CRD 来定义这个名为 Presto 的 customer resource 蕴含哪些属性,CRD 也就是 custom resource 的 definition,它用于通知 Kubernetes customer resource 里有一个名为 Presto 的资源类型,同时定义了这个 Presto 资源类型外面有哪些属性。提交了 CRD 之后,Kubernetes 便能够辨认 Presto 这种 customer resource。此时如果用户提交了一个 Presto customer resource 到 Kubernetes,咱们还须要一个相似于 deployment controller 过程的自定义 controller,以同样的形式发现并解决 customer resource。
自定义的 controller 会获取到资源的形容,当它发现有人提交了一个名为 Presto 的资源,它须要依照肯定的程序创立对应的这些 kubernetes 资源:
1、依据 Presto 资源中定义的属性,先去创立一个 ConfigMap 来形容 JVM 配置;
2、创立一个 deployment,蕴含 Presto 具体的镜像版本;
3、创立一个 service,连通 Presto coordinator 和 Presto worker。
上述的 3 个步骤须要在 controller 过程里实现。因而,自定义的 controller 其实跟内置的 Kubernetes controller 原理一样。只不过自定义的 controller 须要咱们本人去实现本人的业务逻辑。当咱们创立了一个 Presto 资源后,自定义的 controller 依然要监控资源的状态,如果资源的状态被更新了(比方 Presto 的镜像被更新了),那么它也须要依据更新之后的状态和以后状态进行比照,之后 controller 要去做的事件就是自动更新它所创立的相干资源,而咱们则毋庸关怀要更新哪些内置的 deployment 和 service。至此,咱们就了解了实际上 Operator 通过一套解决方案自动化地缩小了咱们手工保护资源的步骤。
对于 Operator 来说,它的职责是帮咱们缩小人工的保护老本。以方才的 Presto 部署为例,如果咱们实现了一个 Presto controller,这个 controller 实际上是一个过程,咱们能够把它放在 Kubernetes 集群上的一个 pod 里运行。当它发现有一个 Presto 的 customer resource 提交到 Kubernetes 集群时,它就应该要按程序地创立对应的内置资源。原来这个创立的步骤是由人工创立的,当初变成由 Presto controller 负责创立。它会先创立 config map,再创立 deployment,再创立 service。
咱们能够看一下 Operator 的能力分级。首先,假如咱们抛开 Operator,回到最原始的 Kubernetes 部署形式,则所有的这些资源都须要咱们本人去创立和部署,并且按程序手工提交。所以如果有一个过程可能帮忙咱们依照程序创立这些资源,省去人工创立的步骤,那么这样就达到了 Level 1。相当于所有步骤都曾经被编排好,不再须要人工保护。
在此基础上,当咱们批改了 customer resource 中的某些属性,Operator 也应该负责更新相干的资源。比方如果镜像的版本产生了变更,此时天经地义地 Operator 也能帮咱们同时去批改那些相干的资源,这样一来,咱们也不须要保护外面这些资源之间的关系了。如果能做到这一点,就达到了 Level 2。
更进一步地,Operator 作为整个利用组件之上更形象的过程,其实它还能够帮咱们做一些利用集群之外的事件(比方存储的备份、容灾、主动迁徙等)。如果具备这样的能力,咱们就能够说 Operator 达到了 Level 3。
再有,咱们还能够在此之上收集一些对于利用组件或者集群的宏观信息,比方什么时候产生了扩缩容、什么时候做了配置变更等,再比方如果它进行了滚动降级,那咱们能够收集到无关 CPU 和内存的应用状况,晓得什么时候 CPU 的使用率高、内存资源应用得多,什么时候应用得少。这些信息在前期能够被进一步用来做优化,比方能够对资源进行调优,能够对整个集群的指标进行收集,甚至实现水位告警,发送一条短信或者是打电话或者用邮件来告诉用户,此时的 Operator 达到了 Level 4。
最初,假如在集群部署的利用组件可能在 Operator 根底上做到主动扩缩容,咱们就能够说它达到了 Level 5。比方,基于后面 Level 4 所收集的指标进行剖析后,发现利用在白天的申请较多,而早晨较少,则 Operator 能够主动依据申请的数目去做扩缩容,主动地去批改 pod 的正本数。在这样的状况下,Operator 实现了参数的主动调优。
上述的这 5 个 Level 的分级规范实际上来自于 Operator SDK 的官网。接下来咱们就以 Alluxio 为例论述如何实现 Alluxio Operator。咱们首先要思考的是,将 Alluxio 部署到 Kubernetes 须要哪些类型的资源做撑持。
三、如何针对应用服务实现对应的 Operator
一个 Alluxio 集群所须要的资源很多,其中还包含存储和网络相干的资源。咱们第一步先设计出如图所示的架构图。如图所示,部署 Alluxio 所需的资源能够分成 3 层:
1)第一层是配置和存储相干的资源。咱们须要一些 config map 专门配置 Alluxio 的根本配置信息,比方 jvm 配置、pv 存储配置。另外,因为 Alluxio 集群须要波及到存储,所以还须要 PVC 资源。
2)第二层是 workload。目前业界大部分的大数据组件都采纳了主从架构的设计,Alluxio 也一样,它存在 master 和 worker 两种角色,针对 master 和 worker 的部署,咱们别离应用 DaemonSet 和 StatefulSet,而针对 logserver(用于日志的收集)的部署,则应用 deployment。
3)第三层是 service。为了让所有节点之间能够网络互通,还要部署 service。
第二步是梳理出具体要创立哪些资源,以及每一种资源蕴含哪些属性。如图所示给出了所有部署 Alluxio 所需资源的 YAML 文件。
无论咱们是否采纳 Operator 的部署计划,都须要梳理出要创立哪些资源(对应如图所示的 YAML 文件)。Operator 的作用是在此基础上帮忙咱们实现自动化部署,罢黜了手工按程序提交这些 YAML 文件的操作。为了实现本人的 Operator,要先定义 customer resource,将波及到的资源属性形象进去,如图所示,在 Alluxio 的 customer resource 里把一些比拟要害的属性形象进去,比方 master 和 worker 的配置信息。
因为不同资源之间存在着先后依赖关系,所以咱们须要依照肯定程序逐个创立这些资源。首先要部署的是 ConfigMap 和存储相干的资源,第二步才去部署 workerload,第三步部署 services。因为显然咱们须要先创立出 deployment,才可能把 service 部署起来。即便咱们采纳手工部署的形式,也要遵循这样的程序,只不过咱们当初先把这个程序梳理进去,以便在实现 Operator 的时候,通过程序来主动依照这个程序创立资源。
实现 Operator 的逻辑其实就是通过 Operator 调用 kubernetes API 提供的接口,依照程序部署和更新资源。Operator SDK 是以后比拟风行的一个实现 Operator 的框架(https://sdk.operatorframework.io),它主体通过 golang 实现,框架内也提供了一些实用的例子。另一方面,目前在社区上也有相应的 Operator 仓库 (https://operatorhub.io),外面有相当丰盛的各个组件的 Operator 实现。Operator 这一概念被提出之后,业界也陆陆续续地针对支流大数据组件实现了一些社区版的 Operator,提供了一些绝对不便的容器化部署解决方案。
四、Alluxio Operator 如何更好地实现 Alluxio 的一体化部署
咱们最初再来回顾一下 Alluxio Operator 所创立的资源有哪些。Operator 帮咱们创立的资源能够分成三个级别:
1)配置信息相干的资源:包含 JVM 配置和 PV 存储,以及 worker、master 和 logserver 的 PVC。
2)Workload 资源:Alluxio Worker、Alluxio Master 和 Alluxio LogServer 的节点别离应用了 DaemonSet、SatefulSet 和 Deployment 进行部署。
3)Service 资源:Alluxio Master 和 Alluxio LogServer 所须要的 service。
截图中展现了 Alluxio Operator 创立和更新 Alluxio 集群的过程,Operator 运行在一个 POD 中,当用户提交了一个他本人的 customer resource 之后,集群外面就多了一个名为 Alluxio Cluster 的资源。
片刻之后,Operator 帮咱们创立了所需的资源,如图所示咱们能看到有很多 POD 被主动创立进去,包含 master 和 worker 相干的 POD,同时 config map 和 service 也被创立进去了。将来,其实还能够再做一些事件:
1)利用 Operator 做数据主动备份和负载平衡;
2)收集集群内 CPU 和内存的应用状况,实现节点的动静扩缩容,依据 CPU 内存的应用状况做弹性伸缩;
3)实现 UFS 的数据预缓存、预加载;
4)为 Alluxio 集群提供一个可视化的操作仪表板,对 UFS 进行状态跟踪。这些性能能够在将来为咱们大幅缩小 Alluxio 集群的保护老本。
问答环节
Q1:以后大数据平台个别是采纳 HDFS 作为底层分布式存储,如果想整体迁徙到 Kubernetes,是否有相似 HDFS Operator 的计划?
目前支流的 HDFS 部署形式仍然还是通过 YARN 来部署,因为这种形式曾经做得比拟成熟了,所以如果想整体迁徙到 Kubernetes,现阶段业界对于 HDFS Operator 这样的一些解决方案还是比拟少见,可能这种模式依然须要一段摸索的工夫。
Q2:Alluxio 作为一个分布式缓存组件,介于计算利用与底层存储之间,实现了数据缓存的减速。如果将 Alluxio、计算和存储组件部署在同一个 K8S 集群上,在架构层面上有什么倡议呢?
如果都是放在 Kubernetes,其实它们之间是绝对比拟独立的。Alluxio 其中一个十分重要的利用场景,就是在存算拆散的根底上来做实现性能晋升,因而往往 Alluxio 会跟计算集群部署在同一侧。目前 Kubernetes 的部署形式,更有利于 Alluxio 和计算利用端进行联合。
想要理解更多对于 Alluxio 的干货文章、热门流动、专家分享,可点击进入【Alluxio 智库】: