阿里巴巴的云原生应用开源探索与实践
导读:从拥抱开源、贡献开源、自主开源,到赋能开源,开源已升级为阿里技术战略之一,且正为开发者源源不断地输送切实可见的价值。云原生是阿里开源的重要领域,短短几年,以 K8s 为核心的云原生开源生态迅猛发展,这是全世界开发者合作杰出成果,也是开源力量的结晶。
阿里巴巴的应用架构演进
大家好,我是司徒放,目前在阿里巴巴负责阿里云的应用平台和微服务产品线。在和大家分享我们在云原生应用方面的探索之前,先和大家介绍一下阿里巴巴在整个应用架构方面的演进历程。
今年是阿里巴巴成立的二十周年,二十年前,阿里巴巴使用的这个应用的架构,还是单体应用模式,它有很多的业务模块都在一个应用里面,各个业务都在一个应用里面开发,这个架构的一个好处是简单,也非常容易部署,对小的创业公司来说是很方便的。它的缺点在于团队变大变多之后,不能满足快速迭代要求,因为每一个业务它需要去发布的时候,都需要在同一个应用上做修改、发布,当这个业务迭代非常快的时候,它同时的一个并发修改就非常多。
所以在 2008 年的时候,阿里巴巴就引进到了微服务架构,只是当时并不叫微服务,而是叫服务化架构。各个业务模式就按照服务的边界来拆分,这是比较松耦合的一种方式,一个微服务应用是无状态的,可以快速扩展实例。而且某个实例有异常比如宕机时会可以自动下线,不会影响整个服务架构的稳定性。微服务架构也比较容易推动整个互联网公司的快速迭代需求。
大概三年前,阿里巴巴就走向了云原生的架构。这是一个天然适合云的、能够充分利用云的弹性能力和标准云服务,给整个阿里巴巴的电商降低机器的准备成本,特别是类似于在大促双十一需要很多机器去支撑,但是大促结束之后,这些机器有一半以上就可以归还到云上。
这个时候,阿里巴巴就在往云原生的方向去迈进,而且通过整个云服务能够更快地加快整个阿里巴巴的技术构建。而且云原生架构,是一个比较开放、标准、没有侵入性的技术架构。
阿里巴巴在云原生的开源进程
在阿里巴巴进入到了云原生之后,我们看一下阿里巴巴在开源方面做了一些什么样的事情呢?
运维领域
首先,整个云原生架构里面最重要、最关键的一个基石就是 Kubernetes。
阿里巴巴在两年前,就在大规模的落地 Kubernetes 的整套技术用来做我们机器资源的调度和管理。在内部有数十万台级别的机器以及上百万级别的容器规模,直接拿开源的 Kubernetes 到这种生产规模下是用不起来的,所以我们在上面做了很多性能优化,包括针对规模上的改造,使得整个 Kubernetes 在阿里巴巴内部能够很顺畅地 run 起来,阿里巴巴也在不断地向上游去贡献我们内部实践和优化的代码。
除了 Kubernetes 之外,在整个云原生生态里还有像容器、etcd,我们也在不停地优化它的规模能力以及安全隔离方面的一些能力。同时,也开源了内部使用的蜻蜓(Dragonfly)用来做大规模的镜像快速分发。
开发领域
在开发领域,阿里巴巴很早就已经使用了微服务架构,也对外进行了开源,比如说 Apache Dubbo,这个是比较知名的 RPC 框架;还有去年开源的 Nacos ,作为阿里巴巴集团支撑大规模的服务注册发现、配置推送一个组件;另外,还有 Spring Cloud Alibaba,基于阿里开源的组件提供了一整套 Spring Cloud 最佳实现;还有像支撑整个阿里巴巴高可用的 Sentinel、以及 Apache RocketMQ 消息队列,都是我们在开发领域做的开源。
这些组件其实随着阿里巴巴进入云原生时代之后,也在逐步结合云原生做一些改进,比如说 Apache Dubbo,会更好地去适配我们未来的微服务 Service Mesh 架构,它会理解 Istio 的 xDS 协议,成为一种数据面;比如 Nacos,它为 Service Mesh 的 Istio 提供 MCP 协议的对接,成为云原生微服务和传统微服务互通的桥梁。
应用
在开发领域和运维领域之间,其实我认为还有一个很大的空缺,就是专门用来连接整个开发和运维的应用这一块。
对于开发阶段,写完代码之后交付的是一个应用包,而这个应用包也是整个运维系统上运行的一个基础颗粒。我们认为现在在云原生阶段,缺少了一个很好的应用交付和运维标准,大家在不同的公司会看到每个公司都有不一样的运维平台,应用的部署和交付都没有办法被标准化。我们现在进入云原生时代,推崇的是标准、开放,所以我们认为在这一块上面还有很大的机会去做进一步的应用标准建设,这是我接下来想要和大家重点分享的一个话题。
云上应用交付和运维的痛点
先看一下云原生在交付和运维方面有哪些痛点呢?
刚刚也讲到了,在进入到了微服务之后,我们面临的一个问题就是应用的实例数会越来越多,会到成百上千的规模不断往上增长;另外还有我们部署的环境也变得越来越多,比如说现在有不同的云厂商,以及我们有很多专有云的自建机房的输出;另外还有很多自建的环境,这些环境多样化以及我们应用在运行时它会以容器的方式去运行,可能还是以传统的虚拟机的方式去运行,或者它会以函数的方式去运行,但是运行时也会有很多不一致,比如不同的环境、或运行时的不一致,会导致整个分布式运维体系变得越来越复杂,它的监控、日志采集也是一个很大的挑战。
当这些应用已经放到云上去运行的时候,由于很多的云服务并没有被标准化,很多这种云的能力需要集成到应用上的时候,也会有很大集成的困难。而这些云上应用运维的痛点以前也有类似的,我们可以跟过往的解决方案做一个对比。
过往解决方案
首先,是类似 Ansible、Puppet 这些基础设施运维自动化的工具。这些工具对整个运维效率起到了很大的提升作用,减轻了运维同学的工作量,但是它使用的是一些自应用的模块,而且它的概念是偏向于脚本运维的方式,非常的底层。
随后出现了类似 Cloud Foundry 、Heroku 这种比较经典的应用平台,这些应用平台是以应用为中心去做运维和交付,往上把运维的工作进行了一个抽象,按照 buildpack 的方式去做运维和交付,通过 buildpack 的方式,可以简化整个应用运维的工作,但是 buildpack 本身覆盖的范围比较窄,在运维和交付方面,缺乏一些运维交付的标准,所以它的可扩展性是比较差的。
随着 Docker 容器的横空出世,打破了传统基于 buildpack 的应用交付模式,所以就出现了新一代的容器管理平台,而 Kubernetes 成为了云原生时代一个新的容器平台事实标准。Kubernetes 本身提供了很多基础服务抽象,比如说 Deployment、Service。在社区里面它有一句很著名的定位:“Kubernetes is the platform for platforms.”也就是说,Kubernetes 定位是构建平台的平台,能够简化构建应用平台的复杂度,它不会再去做上层基于应用的抽象。大家可以发现历史总是那么相似,从过去的运维工具到后来基于应用的抽象,到现在容器出现打破运维格局,重新对这个领域进行洗牌,自然,在云原生时代需要一个对应交付和运维应用的平台。
从过往解决方案引发的思考
关于云原生时代的应用抽象,我们要做一个思考:我们需要什么样的应用抽象呢?
首先,它需要解决我们运维交付的一个复杂度,以及屏蔽底层细节差异。无论什么时候,都是应用平台需要解决的问题。另外,参考我们过去比较传统的应用平台的问题,比如说 buildpack 这种方式,它存在不通用/不易于扩展的问题,我们认为接下来的应用抽象,它应该要具备在应用运维方面更加通用、可扩展的描述能力。
除此之外,我们在推广应用抽象的时候,还是要采用开源和社区的方式去推进,因为未来一定是更加标准和开放的,我们推广这个应用抽象,就是希望有更多开发和运维工作者,能够给这个标准提供更多的建议,能够通过整个社区进一步推动整个应用交付和运维标准的发展。
Open Application Model - 开放应用模型
在上个月中旬,阿里云和微软联合发布了“Open Application Model(开放应用模型)”这一个开源项目。我们希望通过这个开放应用模型,解决“在云原生时代缺乏一种应用交付标准”的问题。(“Open Application Model -开放应用模型”后面简称为“OAM”)
OAM 的三种角色
OAM 里面有三种不同的角色。
- 首先是应用开发。很明显,应用开发是负责编写业务逻辑的。比如说它会写 Spark、Wordpress、Spring Cloud 等微服务的程序,它写完这个微服务的程序之后呢,会按照 OAM 标准编写一段应用定义;
- 第二个是应用运维的角色,就是负责应用的交付与运维;
- 第三个角色是基础设施平台。基础设施平台在 OAM 里的一个重要定位,在于它要将自己的基础服务能力抽象成可被复用、被重用的模块,并提供给开发和运维人员去使用。
OAM 核心概念解读
下面为大家解读以上的三个角色对应的三个核心概念。
- 首先是 Component。它是被开发人员定义的一个可被重用的应用组件,这个应用组件描述的就是这个应用它运行的方式;
- 第二个重要概念是 Trait。它是一种应用的运维特征,是由基础设施平台这个角色定义的,而这个定义它包含了可组合的应用运维特征,这个特征是其实是这个平台可以提供出来的某种运维能力抽象;
- 最后一个是 ApplicationConfiguration。运维人员负责把 Component 和 Trait 两个绑定在一起,并且作为一个具体的实例化,生成了这个应用配置(ApplicationConfiguration)之后,就可以把应用部署起来。
用 OAM 描述的应用配置示意
接下来是一个具体的用 OAM 描述的应用配置文件(上图文件做了一定内容简化,具体以下面的 yaml 文本为准)。
apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
name: wordpress
spec:
workloadType: core.oam.dev/v1alpha1.Server
containers:
- name: test
image: docker/wordpress:latest
env:
- name: key1
fromParam: test-key
ports:
- type: tcp
containerPort: 9999
name: http
parameters:
- name: test-key
type: string
---
apiVersion: core.oam.dev/v1alpha1
kind: ApplicationConfiguration
metadata:
name: wordpress-app
spec:
components:
- name: wordpress
instanceName: wordpress-instance
parameterValues:
- name: replicas
value: 3
- name: test-key
value: value-from-ops
traits:
- name: service
parameterValues:
- name: portMapping
value:
- protocol: "TCP"
port: 52014
targetPort: 9999
- name: rollout
parameterValues:
- name: canaryReplicas
value: 1
由运维人员编写的 ApplicationConfiquration 文件,它将 Component 和 Trait 两个概念绑定在一起。首先里面描述运维要部署一个叫 wordpress-app的应用,它引用了一个叫 wordpress 的 Component。这是开发人员在另一个配置文件 Component 定义的,他除了定义 wordpress 应如何运行(比如配置镜像位置)以外,还允许运维配置运行实例的副本数以及运行时环境变量 test-key 的值。在 ApplicationConfiquration 里同时引用了两个运维特征,运维人员会填写这个应用需要一个负载均衡,要做外网的端口映射,部署时需要采用金丝雀发布策略。这个文件对应到实际上的部署阶段会变成如上图右侧所示,上面会有一个负载均衡,比如在云上运行时,就会使用 SLB 去做负载均衡的自动分发,会给它配置外网 IP 和内外端口映射。
通过这个简单的 yaml 文件,大家就可以了解到这个应用怎么做快速部署,并且描述运维要具备什么能力。
OAM 的设计理念
给大家总结一下,我所认为的 OAM 的重要的设计理念。
- 首先第一个是配置即代码。所有的 OAM 上面的运维和交付的操作都会使用配置的方式,完全通过 yaml 文件去完成所有的交付运维配置;
- 第二个是依赖倒置。这个依赖倒置有点像 JAVA Spring 开发者使用 IoC 或者 DI 的这种模式,在写这个应用配置的时候,只是依赖应用标准抽象,而这个标准抽象背后的实现实际上是由 OAM 的运行时去做“注入”,通过这个方式就使得我们的应用运维不依赖于我们具体的运行环境;
- 第三个是重要的设计理念就是角色关注点分离。刚刚上面讲过 OAM 里的三种不同的重要角色:开发、运维以及基础设置平台。这三种角色只需要编写对应不同的配置文件,互相解耦。这样开发不需要关心应用是怎么运维的,只需要把运行时需要的配置暴露并描述出来;基础平台只需要把平台能力提炼成 Trait;最终由运维人员把开发需要的参数和运维需要的能力进行结合。
- 第四个就是整个 OAM 的设计是一个可组合可扩展的方式。它会通过让我们刚刚说到的 Traits 能够按需组合、重用、移植和扩展。
EDAS & OAM
上面我们说了这么多其实都是比较一些概念性的东西,接下来我们看一下,在阿里巴巴的云产品 EDAS 对 OAM 所做一些落地方面的尝试,这也是第一个在实际生产上面基于 OAM 对外可开放使用的云产品。
下面会用 EDAS 为例,给大家做一个介绍,讲解一下 OAM 具体怎么运作。
EDAS 是什么?
首先介绍一下 EDAS 是阿里云上面的一个云产品,它扮演着我刚才讲到的类似于一个应用平台的一个角色:
- EDAS 从开发方面就提供了开发框架给我们云上的开发者去使用;
- 开发者开发完程序之后,会把应用交付到 EDAS 上面去进行部署;
- 与此同时 EDAS 会对这个应用进行监控诊断,根据容量情况进行实例弹性伸缩;
- EDAS 会对上面的微服务进行注册发现、服务治理;
- 提供应用的高可用保护,比如限流降级、熔断等。
这些是 EDAS 作为应用平台在阿里云上的产品定位。
EDAS 支持 OAM 的运行示意图
那么它在支持 OAM 在运行的时候又是什么样的呢?
如图所示,一个开发人员,他首先需要去编写一个按照 OAM 标准为参考去定义一个 Component。这个 Component 里面会定义如开发应用类型是什么样子,比如它的镜像路径、它需要多大的存储空间,以及它的环境变量是什么样子,这些都是开发人员在开发的时候需要去描述的内容。
对于阿里云来说,它是一个基础设施平台的身份。它在上面其实有很多运维的能力,比如说像监控报警、块存储、需要发布策略和弹性伸缩的策略。EDAS 会把这些平台能力抽象成一个一个独立的 Trait,开放给运维人员使用。
在需要部署应用的时候,运维人员会选择 EDAS 上提供的 Trait 并填写相关参数,同时也设置好开发人员的 Component 的参数,这作为一次应用部署,生成了 ApplicationConfiguration 提交给 EDAS。
EDAS 作为 OAM 的运行时,在读取到这份部署配置后,它会去实现 Trait 提供相应的运维特征动作,比如说运维描述需要一个块存储,那么 EDAS 会在阿里云上面去申请一个具体的块存储对象,并绑定到这个应用上面。同时 EDAS 会提供一个容器环境(如 Kubernetes)去运行开发者定义的 Component 的工作负载,比如购买 ECS,配置好容器环境,把环境变量传给容器,使 Component 能够正常运行。
以上就是整个 EDAS 支持 OAM 的一个运行示意图。
EDAS 支持 OAM 的对比
那么 EDAS 在支持 OAM 之后,它的使用情况又会发生怎样的变化呢?
在没有使用 OAM 的时候,客户需要和系统解释我要做些什么事情、我要怎么做这个事情。比如说,他需要申请 5G NAS 存储,并且要把它挂载到某个机器的某个目录上面;或者他还有一个监控的需求,他需要告诉系统现在有一个业务指标文件,需要被监控采集,他要去设置这个文件的指标处理规则,最后把这个指标存储成时间序列数据,并且设置报警阈值。在使用 OAM 之后,它就变成了描述式,他只要描述我需要什么东西就够了。比如开发者可以说这个目录上面需要有 5G 的外置可读写存储就够了,具体这 5G 存储怎么申请是由 OAM 运行时去帮助解决的。另外,在监控的时候,他只需要描述自己的这个应用需要被监控、哪个指标需要被监控并报警就够了,他不需要了解对接到具体是哪一个监控系统,他不需要去关心这些事情。
原来很多云产品或者原来很多自定义运维平台都是需要依赖特定的 API 或者 CLI 这种模式去做运维的,这个时候应用要迁移到另外一个运维平台,它的代码、镜像、二进制包可以带走,但是它的很多运维的设施、运维的配置包括监控的配置,这些东西都是只能留在这个平台上的,没有办法很容易地迁移到另外一个平台上面。而通过 OAM,可以将平台所有的运维配置以 yaml 导出,并且能够很快地导入到另外一个环境、甚至是另一个应用平台上,整个系统会变得更加标准。
在使用 OAM 以前,运维人员需要去学习很多知识,比如使用的是 Kubernetes,他需要去了解整个容器和 Kubernetes 的使用方式,他要做定制和拓展就需要去学习 Kubernetes。如果他是从虚拟机的模式切换到容器的运维模式,这个时候他就需要很多时间去理解容器和虚拟机运维之间的差异。迁移到 OAM 之后,相当于 OAM 屏蔽了整个平台底层的细节,所以使得整个运维平台的 OAM 配置没有多大差别。
最后一点就是定制的难度上面。刚刚也讲到过,这个是 OAM 的一个重要的目标,让整个运维的扩展能够更容易的被发现、被组合、被替换。在使用 OAM 之前,运维的逻辑都散落在脚本里面,或者说都在运维平台内部,这个时候很难去统一管理。而一套 OAM 的运行环境是可以自描述的,可以非常容易把平台提供的 Trait、Component 工作负载罗列出来,使用者可以替换或增加新的 Traits,在运行应用时可以自由选择和组合这些 Traits。
作者:司徒放(姬风) 阿里巴巴技术专家
本文为云栖社区原创内容,未经允许不得转载。