资讯首页 新闻资讯 云计算测评 云服务商动态 技术频道
上云无忧 > 云计算资讯  > 云服务商动态 > 七牛云 | 孙宏亮:阿里巴巴 K8s 应用管理实践的经验教训

七牛云 | 孙宏亮:阿里巴巴 K8s 应用管理实践的经验教训

发布时间: 2020-01-26 15:55:58 |浏览量:685| 评论: 0

在 1 月 5 日 ECUG 大会上 ,来自阿里巴巴的技术专家孙宏亮为听众分享了阿里巴巴 K8s 应用管理实践的经验教训。


以下是演讲内容的实录整理。



大家好!很高兴又有机会跟大家分享一些知识,这已经是我第五次在 ECUG 这个舞台上和大家分享。


今天我要介绍的议题跟 Golang 很相关,大家是否听说过现在一个云原生的应用平台叫做 Kubernetes,听说过的请举手。这基本上是一个大家认识的平台,它的伟大离不开 Golang。我今天主要跟大家分享一下阿里巴巴阿里云在使用 Kubernetes 管理过程中遇到的情况,有哪些经验可以跟大家分享,甚至在这个过程当中,我们发现Kubernetes 的模型在适用各种场景的时候,未必是完美的。所以在这个过程当中,我们应该抽象出什么样的原型,希望跟整个行业一起来共建。


今天我的大纲是这样的,第一方面是和大家介绍一下 Kubernetes 在应用管理上的挑战。不谈 Kubernetes 的好,今天主要是来辩证看待这些内容。第二方面是看研发和应用运维、基础设施运维多种不同角色的人员对Kubernetes 现在的需求都变成什么样了,原来我们可能是无欲无求,只要有一个好用的东西,我们就可以把它用得很爽,但现在大家对于美好生活的向往,对于美好IT基础能力的要求越来越刁钻,不断有新的需求诞生出来。在这个基础上我们也可以分享一下阿里在解耦研发和运维的过程当中遇到了什么样的情况。最后和大家分享一下我们现在在整个行业当中主推的以应用为中心,以 Kubernetes 为基础的应用模型。

在这之前,其实很多人都已经介绍过阿里巴巴在大规模容器化过程中的历程,在 2013 年 docker 还没有诞生的时候,阿里巴巴就使用了 T4 第一代游戏引擎来进行容器化的事情,到了 2019 年,「双十一」很大的流量已经在 Kubernetes 上,很多业务方已经完全围绕在 Kubernetes 这个生态在构建自己的技术栈,构建自己的工具链,构建自己的业务。


说得很美好,现实是比较骨干的,大家用惯了 Kubernetes 之后,相处的时间长了,慢慢有一些缺点就逐渐体现出来了。首先对于业务研发而言,使用 Kubernetes,我相信这个问题大家肯定会遇到。如果我说 Kubernetes API是什么,可能一千个开发人员当中,一千个人不同,其中有一个共同点是太复杂。甚至很多人会问,我作为一个业务开发人员,我真的有必要了解这么多细节吗?现实肯定不是这样的。

另外一个方面,对于应用运维人员来讲,这里面又有一个分层的概念,Kubernetes 的能力基本上会有一个核心的基础设施团队掌控,在它的基础之上去构建可扩展能力。但是这些可扩展能力最终肯定还是要暴露给业务层用户,我们的应用运维怎么去利用 Kubernetes 的扩展能力来实现业务的主要需求呢?这个是比较难上手的。

第三个问题,对于阿里云的场景比较贴近一点,为什么呢?作为 Kubernetes 的管理团队,其实对下感受到了无数多的基础设施,网络、存储、搜索等等业务,非常多资源。尤其是对于一个企业而言,如果企业的基础设施,一些系统软件,它的构建都是烟囱式的,其实不太利于类似于中台的技术架构来统一对上提供能力。我们需要对底层能力进行模块化的封装,统一抽象了之后,慢慢的一步一步往上传递,这才是更好的一个平台化的构建思路。

我们首先来看第一个问题,大家觉得 K8s API 太复杂吗?Kubernetes API 是真的太复杂了,对于它的描述,我已经精简了百分之八九十,但是还有这么多字段在这里。如果你是应用的开发人员,你愿意看到这些东西吗?太过于复杂,我整天已经被老板逼着写业务程序了,我还要来了解这些东西,对我来讲无疑是一个负担。


在这张图当中,我们可以看一下这样一个文件,Kubernetes API 封装了很多东西,同时对应了多个不同级别的 IT 工程师。比如最上面这一块,其实是应用运维关心的东西,里面涉及到了我应用运行的过程当中,需要多少个 replicas,我的升级或者是发布的策略到底是怎样的。但是中间这一块是属于研发工程师需要关心的内容,研发工程师当然希望知道我自己这个应用交付出去是哪个镜像,我需要监听哪个端口,最终运行的过程当中需要哪些资源,这是研发需要关心的。


中间这些东西是什么?有人能看懂吗?我估计有人能看懂,因为你就是 Kubernetes 专家,肯定还有绝大多数人看不懂,因为这些东西跟你半毛钱关系都没有。这个情况说明了什么?说明 Kubernetes 的 API 向复杂人群同时暴露,导致用户友好性其实是存在一些问题的。当然 Kubernetes 的 API 不是不好,而是 Kubernetes 的定位就是给平台构建者使用的,所以自然要包含所有内容。


技术要迭代发展,对这样的 API 我们怎么样演进呢?后面一步一步来看。

有些人可能会想,API 太过于复杂,我根本不想给应用开发者暴露,我肯定很简单,继续再做一层封装,再去进行抽象,把应用开发者关心的东西暴露出去不就行了吗?我相信很多企业针对 Kubernetes 都自己定制化了一套既面向开发又面向运维的一套解释器一样的东西,把角色分开。类似这样的 PaaS 平台,这个 PaaS 平台最终对Kubernetes 的 API 进行了遮掩,或者说提炼,最终露出了 5 个 Deployment 字段来让用户填写,相信很多企业都会这么做。


这样做了之后,针对简单无状态应用是可以很好处理的。但是针对有状态的复杂应用管理,这少量的描述就心有余力不足了。另一方面,基础设施能力在演进,这个平台是固化的。这个时候出现这样一个中转站性质的封装,底层平台的能力可能就会因为中转站的灵活性不够而受限。

在 Kubernetes 生态当中,大家都说 Kubernetes 的扩展能力很好,你想做任何的事情,都可以通过 CRD 来帮你抽象一种模型,通过 operator 的方式可以把一些软件的运维做得很好。比如说以 zookeeper 的开发、维护人员来看,我们了解一下 zookeeper 这样一个软件落在 Kubernetes 之上它的流程是怎样的。对于 zookeeper 的维护人员说,我的 zookeeper 该用哪种 workload 来接入呢?K8s 专家会说很简单,写一个 operator 就行了。


但是对于一个系统软件的维护人员来讲,他要知道 operator 是什么,operator 内部的细节是很多的,包括 informer、reflector 等等。Operator 维护人员看到这些都很恐惧,原本我只要把 zookeeper 管理好,但是你让我把 Kubernetes 里面的细节都要学会,看到了所有东西,很恐怖、很吓人。这暴露出业务在向 Kubernetes 转型过程中存在一个 gap。

再来说应用运维如何上手 Kubernetes 的扩展能力,我是一个应用的运维人员,我知道 Kubernetes 的专家们已经提供了很多抽象化的能力给我了,我怎么用呢?比如说怎么知道扩展能力怎么用,包括扩展能力之间存在冲突怎么解决,比如这边有一张图,我们实现了一个 cron 的 HPA。这里可以多提一句,当我们一个应用需要在某个时间点定期进行横向伸缩的时候,我们就可以把它抽象成一个 CronHPA,比如很多电商业务跟社会上人群的购买时间段是非常相关的,我们是不是可以实现早上 8 点之后,可以自动地横向伸缩,扩展到 500 个实例。到了晚上 2 点之后,是不是可以做到自动的伸缩缩到只剩 30 个实例,看上去功能很美好,但是当我们把 CronHPA 和 HPA 绑定到同一个应用的时候,应用就出故障了。原来不同的 CRD Operator 出现了冲突。


另外一个方面,我们的 Kubernetes 如何来管理底层这么多的云资源。往往我们业务在用的过程当中,会将其写成一个 Helm 包,把自己的软件封装起来,来满足 Kubernetes 的部署 API。同时他会有一个 RDS 外部依赖的需求,但是对于我们的 Kubernetes 的专家而言,对于一些外部依赖,他的接入方式是没有的,这个时候就需要再去第三方的云资源管控平台上,去创建,创建完了之后再交给应用的维护人员,但这样一个职业,在我们看来是比较割裂的。


通过这种方式,现在我们可以把各种能力通过 CRD 来做统一的编写,统一的罗列。罗列完了之后,可以通过把 CRD 的能力透传到用户手里的文件,最终 CRD 搞定一切。在这个文件当中会体现到 RDS、SLB、VPC 等各种各样的资源。我们是针对一个场景解决了一类问题,但是解决方式通过 CRD 大家会发现,并不是一种通用的方式。RDS 是这样写的,MYSQL 或者说其他的提供了一个 CRD 是不是标准的,给客户提供的字段是不是统一的这样的信息,没人知道。


所以就会导致这样一个情况,每个公司,每个团队,每个云资源的一些提供方,都会针对自己的资源能力做一个抽象,通过 CRD 透传给上面的应用。但是这样的东西也有一定的问题,比如我们推出去的能力,比如有赞的一些能力,比如 pinterest 的能力,各自有各自的定义。这些定义你会发现无法在另一个团队、另一个公司进行复用,好用是好用,但只在你自己的公司里面好用,并不具备行业的可扩展性。


这时候我们需要做什么样的事情呢?说来说去就是这样一个演进路径,原来 Kubernetes 的 All-in-one API 向所有人统一无差别的对待,但是未来我们希望的是在 Kubernetes API 之上,能对不同种类的人群,不同种类的工程师进行区分化的对待,把研发域需要的应用描述 API 抽象出来给研发,把应用运维能力的模块化描述抽象出来给应用运维能力的工程师。同时在 K8s 对下资源对接的过程中,我们可以提供抽象的标准,让所有资源接入的时候可以做到无感知,但是又可以在每个地方无缝使用。这样之后,需要一个巨大的提升,在 Kubernetes 的基础上做一个巨大的效率提升。所以我们是做一个区分使用者角色的分层应用定义+模块化封装的运维能力,来建立这样一个应用模型。


这是回到了我们今天要和大家介绍的一个非常重要的模型叫做 Open application model,以应用为中心的 K8s API 分层模型,大概是这样的,大家可以感受一下。后面的细节,我请孙健波,也就是 OAM 的主导者来介绍一下 OAM 到底是什么方式。

孙健波:感谢孙宏亮老师,前面讲得很好,我下面给大家介绍一下 OAM 相关的细节,其实刚刚也说到了我们阿里在交付应用管理的整个演进过程当中,遇到了 Kubernetes API 的一些问题,因为我们发现 Kubernetes API 是All-in-one 的,因为 Kubernetes 的定位是 Platform for Platform builerd。什么意思呢?Kubernetes 定位是给平台构建者来用的,所以它必须把所有的东西放在那里,这样平台构建者才能把底下所有的基础设施统一起来,让你把这个基础设施用一个统一的方式去供应出来。
而且 Kubernetes 现在也确实做到了这一点,基本上成为了一个社区事实上的标准。大家无论是阿里云还是其他云,基本上都有一个 Kubernetes 的托管服务,大家都可以把应用跑在 Kubernetes 上面,然后再去调用底下不同的云资源。


我们在演进的过程中就发现 All-in-one 的 API 其实面向用户,面向最终端的用户不是很合适,因为会有刚刚说到的各种诉求,研发他们会觉得我不需要去理解那么复杂的 YAML 文件。运维又会觉得我的扩展性,K8s 的扩展性虽然灵活,但是我去用的时候感觉很难上手,因为我根本不知道怎么用。然后底下 K8s 的团队又觉得就应该通过 K8s 去暴露出能力来,因为我在上面如果封装一些层,那这些层把这些能力给它框架限死住,我很难跟上下面 K8s 的演进。


然后我们就想了一个方式,就是 OAM 的应用模型,通过分层,研发通过描述 component 组件,业务运维通过模块化的运维能力和这个组件绑定起来,成为 App Config 就是应用完整配置,底下是一个基于 K8s 原生 API 的翻译器,翻译成现实中不同的资源。也就是说当用了这套模型以后,我们希望做到的就是无论这个应用底下的托管资源到底是不是 K8s,都可以通过这样一个模型来统一描述,最终达到以应用为中心的角度。


看一下具体模型,首先刚开始讲的简单无状态应用,确实我只需要定义镜像和环境变量等等不到 5 个字段就可以了。所以在 OAM 里面,有一个 workloadType,这个定义的是你的组件到底是基于哪种应用架构的,就是所谓的 workload,用哪种应用架构来运行的。常规应用架构在 K8s 生态里面也定义好了,像 Deployment,StatefulSet 还有 job 等等一系列预置的workload,已经表达了一些常规的甚至 80% 无状态应用、简单应用,到底应该是怎么玩的。实际上 OAM 也会为用户提供这样一个内置的 workload,当用户选了这个内置的 workload 以后,我只要填简单的几个镜像就可以了。填好以后跟底下的 OAM 实现说,这是 server 架构,要一个可访问的 Service,可以水平扩容,应该以守护进程的方式运行,通过这种方式来解决我简单无状态应用的问题。


如果遇到复杂的应用怎么办?复杂的应用,现在社区主流的玩法都是通过 operator 来实现的。在 OAM 里面,我们也通过把 operator 对接进来的方式实现。在 workloadType 这边,刚刚我们填写的是 server,就是内置的workload。针对 Operator,我们就可以填写一个扩展的 workload,扩展的 workload 是什么呢?它的实现就是一个 Operator 的 CRD,大家可以看到这个用 workloadType 统一描述了一下 CRD,那个 group 和 kind 是什么,底下就是它的具体 spec 定义。我们通过这种 workloadType 的方式,就定义了我底下运行实际应用的架构是 OpenFaaS,通过 name、image 等等把配置文件写上去,这样我们就把简单和复杂的应用都通过 component 组件的形式统一表达了,然后用 workloadType 来定义了底下运行的组件架构是什么,无论是内置的平台直接给你运行起来的,还是需要装一个 operator 插件来定义的,都可以无缝统一起来。


刚刚说到运维很难掌握运维能力,尤其是我们刚刚提到了我如果有一个定时的 HPA,和 K8s 原生的 HPA 有一些冲突等等,其实是很难发现的。我们在刚刚组件定义完了以后,组件定义得比较简单,组件的时候,总归是需要一些能力的。举例来说,我如果是一个 MYSQL 的组件,我肯定希望我的数据里面有一些地方是可以做数据备份的,现在社区里面去做 operator 的时候,可能你就得自己把备份的能力也写在你的 operator 里面,这样就导致你的 K8s operator 功能显得非常复杂,非常冗长。实际上这里面有很多东西是可以拿出来共用的。

 

再比如我的web 后端,我可能需要一个 ingress,这个能力现在 K8s 已经原生提供了这样一个 Controller 大家用就行了。但实际上如果我有类似的能力,比如我有一个自动扩缩容的能力,其实和它是对等的,这些很多的能力,K8s 上可能提供了,可能没有提供。但是本质上你都可以通过 operator 的能力,它不是一个业务特定的需要的能力,但是如果你自己去写一个 operator,你什么都要自己去写。通过 Trait 的这种描述方式,你就可以把这些通用的能力抽离出来,那些公共的能力,你去用别的 operator 就可以了。


我们来看 Trait 统一来控制以后,我们可以有一些很大的好处,比如说我可以直接通过 kubectl get traits,可以看到到底我这个平台支持哪些运维的能力,比如说刚刚说到的定时的扩缩容,自动的扩缩容,都可以通过这个定义。然后我通过 kubectl get tratits 看到具体的 Trait 是什么,把这个 YAML 文件拿到,我就可以看到这个字段应该怎么写,应该怎么配置,可以运行在哪种 workload 上面,这个 apply To 大家可以关注到,我就可以看到这个运维能力到底运行在哪种 workload 上面。

然后我们再来看这张图,如果我在一个 Application Configuration 上面定义了两个 Trait,这两个 Trait 如果出现冲突,我可以第一时间由我底下接收这个配置文件的翻译层,提前看到这样一个冲突出现,这样的话运维能力冲突的管理也就非常简单了。


我们再跳到一个整体的概念来看看这个模型到底是怎么样的。这个模型我们可以看到,它是把左边我们刚刚说到的那几个概念,很好地结合起来、组装起来,就变成了一个跟 K8s 那个 YAML 的描述,以完全一致的 API,本身是一个自包含的,里面有哪些组件,我都可以通过这些名字实际地找到那些细节。同时它也是面向中态的。然后我们通过这样一个翻译层,把这个应用描述翻译成实际对应的资源,比如说这边组件定义了一个 database,那可能实际上就是云上面的一个 RDS 数据库。如果我还定义了一个 ingress 的话,那它可能就是一个 SLB 等等。

这个翻译的过程,就是对 OAM 这个模型的一层实现。这个实现大家可以在公司内部自己去实现这样一个 OAM 的模型,去解释它到底应该翻译成什么资源。在社区上也可以找到这样一个开源项目叫 Rudrhttps://github.com/oam-dev/rudr 。

刚刚提到很多写法都是 operator,其实 operator 和 OAM 的描述是可以无缝衔接的,比如左边的是 function 的 CRD 定义。右边就是 OAM 里面 workloadType。
然后 CronHPA 的 CRD 定义,也可以通过变成 Trait 来做。Trait 和 workloadType 其实就可以完全对等现在社区里面的很多 operator 的写法。


最终我们的效果是通过 OAM 模型把整个的 Kubernetes 里面的各种 operator 可以拼装起来,我们构建成了一个 components 的 class。我们传统的应用在最上层用户看到的可能就是 component 那一层,component 那一层我要定义,我需要一个监控报警,那可能对应的是一个 promethus operator。我需要日志,可能下面就是一个 Elasticsearch operator。如果我还需要其他的,比如我需要云上的数据库组件,那可能底下对应的是一个 RDS 的 operator。这样我就可以通过 OAM 这样一个模型,让大家尽可能复用社区里面的资源,而不是说每一个 operator需要写一套这样的东西。


理论基础:我们在 CNCF 有一个管应用交付的小组。他们提出了这样一个应用模型,最上层就应该是一个应用定义,应用打包的过程。第二层是应用部署、交付。下一层是 operator 以及 K8s 里面的 workload,最下面是一个平台层,这个平台层可以是 K8s 也可以是其他的,比如现在流行的 Serverless、FaaS 等等。


现在我们 OAM 的模型,可以用 helm 来管理,rudr 本身也是可以通过 HELM 来安装的。区别就是 HELM 里面原来只是 K8s 的 YAML 文件,现在就可以通过 OAM 来定义。通过 Helm 安装完了以后会出现一些 CRD,里面包括我刚刚说的 workloadType、Trait 以及 Application Configuration 等等概念。下面讲一下后面 OAM 这块的计划。


因为 OAM 这个项目,Rudr 是用 rust 语言写的,可能大家接受度不是很高,虽然它很优美,有兴趣也可以学一下。因为云原生社区,大家都是用 Go 语言的,所以我们也开发了一个 OAM Go 的 SDK,大家通过这个就可以非常快速地构建出我刚刚说的翻译层,然后底下接各种实际的 K8s 的 operator,所以我们的计划里面也有 K8s 的 operator 一键接入,包括 CRD 的 registry,以及底下不同平台的,比如说 OpenFaaS 管函数的,terraform 管云资源的,Knative 就是 servreless 的效果,大家就可以直接去使用了。这也是我们后面的计划,也欢迎大家一起参与进来,因为它是一个社区共建的项目,我们希望大家能跟我们一起共建。


我的分享就到这里,期待能在未来的 ECUG 大会上再和大家分享!

更多【云服务商动态】相关文章

有话要说

全部评论

暂无评论
官方微信
联系客服
400-826-7010
7x24小时客服热线
分享
  • QQ好友
  • QQ空间
  • 微信
  • 微博
返回顶部