七牛云 | 孙宏亮:阿里巴巴 K8s 应用管理实践的经验教训
|
在 1 月 5 日 ECUG 大会上 ,来自阿里巴巴的技术专家孙宏亮为听众分享了阿里巴巴 K8s 应用管理实践的经验教训。
以下是演讲内容的实录整理。
今天我的大纲是这样的,第一方面是和大家介绍一下 Kubernetes 在应用管理上的挑战。不谈 Kubernetes 的好,今天主要是来辩证看待这些内容。第二方面是看研发和应用运维、基础设施运维多种不同角色的人员对Kubernetes 现在的需求都变成什么样了,原来我们可能是无欲无求,只要有一个好用的东西,我们就可以把它用得很爽,但现在大家对于美好生活的向往,对于美好IT基础能力的要求越来越刁钻,不断有新的需求诞生出来。在这个基础上我们也可以分享一下阿里在解耦研发和运维的过程当中遇到了什么样的情况。最后和大家分享一下我们现在在整个行业当中主推的以应用为中心,以 Kubernetes 为基础的应用模型。
说得很美好,现实是比较骨干的,大家用惯了 Kubernetes 之后,相处的时间长了,慢慢有一些缺点就逐渐体现出来了。首先对于业务研发而言,使用 Kubernetes,我相信这个问题大家肯定会遇到。如果我说 Kubernetes API是什么,可能一千个开发人员当中,一千个人不同,其中有一个共同点是太复杂。甚至很多人会问,我作为一个业务开发人员,我真的有必要了解这么多细节吗?现实肯定不是这样的。
在这张图当中,我们可以看一下这样一个文件,Kubernetes API 封装了很多东西,同时对应了多个不同级别的 IT 工程师。比如最上面这一块,其实是应用运维关心的东西,里面涉及到了我应用运行的过程当中,需要多少个 replicas,我的升级或者是发布的策略到底是怎样的。但是中间这一块是属于研发工程师需要关心的内容,研发工程师当然希望知道我自己这个应用交付出去是哪个镜像,我需要监听哪个端口,最终运行的过程当中需要哪些资源,这是研发需要关心的。
中间这些东西是什么?有人能看懂吗?我估计有人能看懂,因为你就是 Kubernetes 专家,肯定还有绝大多数人看不懂,因为这些东西跟你半毛钱关系都没有。这个情况说明了什么?说明 Kubernetes 的 API 向复杂人群同时暴露,导致用户友好性其实是存在一些问题的。当然 Kubernetes 的 API 不是不好,而是 Kubernetes 的定位就是给平台构建者使用的,所以自然要包含所有内容。
但是对于一个系统软件的维护人员来讲,他要知道 operator 是什么,operator 内部的细节是很多的,包括 informer、reflector 等等。Operator 维护人员看到这些都很恐惧,原本我只要把 zookeeper 管理好,但是你让我把 Kubernetes 里面的细节都要学会,看到了所有东西,很恐怖、很吓人。这暴露出业务在向 Kubernetes 转型过程中存在一个 gap。
另外一个方面,我们的 Kubernetes 如何来管理底层这么多的云资源。往往我们业务在用的过程当中,会将其写成一个 Helm 包,把自己的软件封装起来,来满足 Kubernetes 的部署 API。同时他会有一个 RDS 外部依赖的需求,但是对于我们的 Kubernetes 的专家而言,对于一些外部依赖,他的接入方式是没有的,这个时候就需要再去第三方的云资源管控平台上,去创建,创建完了之后再交给应用的维护人员,但这样一个职业,在我们看来是比较割裂的。
所以就会导致这样一个情况,每个公司,每个团队,每个云资源的一些提供方,都会针对自己的资源能力做一个抽象,通过 CRD 透传给上面的应用。但是这样的东西也有一定的问题,比如我们推出去的能力,比如有赞的一些能力,比如 pinterest 的能力,各自有各自的定义。这些定义你会发现无法在另一个团队、另一个公司进行复用,好用是好用,但只在你自己的公司里面好用,并不具备行业的可扩展性。
这时候我们需要做什么样的事情呢?说来说去就是这样一个演进路径,原来 Kubernetes 的 All-in-one API 向所有人统一无差别的对待,但是未来我们希望的是在 Kubernetes API 之上,能对不同种类的人群,不同种类的工程师进行区分化的对待,把研发域需要的应用描述 API 抽象出来给研发,把应用运维能力的模块化描述抽象出来给应用运维能力的工程师。同时在 K8s 对下资源对接的过程中,我们可以提供抽象的标准,让所有资源接入的时候可以做到无感知,但是又可以在每个地方无缝使用。这样之后,需要一个巨大的提升,在 Kubernetes 的基础上做一个巨大的效率提升。所以我们是做一个区分使用者角色的分层应用定义+模块化封装的运维能力,来建立这样一个应用模型。
这是回到了我们今天要和大家介绍的一个非常重要的模型叫做 Open application model,以应用为中心的 K8s API 分层模型,大概是这样的,大家可以感受一下。后面的细节,我请孙健波,也就是 OAM 的主导者来介绍一下 OAM 到底是什么方式。
然后我们就想了一个方式,就是 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 模型把整个的 Kubernetes 里面的各种 operator 可以拼装起来,我们构建成了一个 components 的 class。我们传统的应用在最上层用户看到的可能就是 component 那一层,component 那一层我要定义,我需要一个监控报警,那可能对应的是一个 promethus operator。我需要日志,可能下面就是一个 Elasticsearch operator。如果我还需要其他的,比如我需要云上的数据库组件,那可能底下对应的是一个 RDS 的 operator。这样我就可以通过 OAM 这样一个模型,让大家尽可能复用社区里面的资源,而不是说每一个 operator需要写一套这样的东西。
现在我们 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 的效果,大家就可以直接去使用了。这也是我们后面的计划,也欢迎大家一起参与进来,因为它是一个社区共建的项目,我们希望大家能跟我们一起共建。
|



有话要说