给 K8s API “作减法”:阿里巴巴云原生应用管理的挑战和实践

做者 | 孙健波(天元)  阿里巴巴技术专家python

本文整理自 11 月 21 日社群分享,每个月 2 场高质量分享,点击加入社群。git

早在 2011 年,阿里巴巴内部便开始了应用容器化,当时最开始是基于 LXC 技术构建容器,而后逐渐切换到 Docker,自研了大规模编排调度系统。到了 2018 年,咱们团队依托 K8s 体系开始推动“轻量级容器化”,同时投入了工程力量跟开源社区一块儿解决了诸多规模与性能问题,从而逐步将过去“类虚拟机”的运维链路和阿里巴巴总体应用基础设施架构升级到了云原生技术栈。github

到了 2019 年,Kubernetes 基础设施底盘在阿里巴巴经济体中已经覆盖了阿里巴巴方方面面的业务,规模化的接入了包括核心电商、物流、金融、外卖、搜索、计算、AI 等诸多头部互联网场景。这套技术底盘,也逐步成为了阿里巴巴支撑 61八、双11 等互联网级大促的主力军之一。数据库

目前,阿里巴巴与蚂蚁金服内部运行了数十个超大规模的 K8s 集群,其中最大的集群约 1 万个机器节点,而其实这还不是能力上限。每一个集群都会服务上万个应用。在阿里云 Kubernetes 服务(ACK)上,咱们还维护了上万个用户的 K8s 集群,这个规模和其中的技术挑战在全世界也是数一数二的。安全

咱们的 Kubernetes 面临的新挑战

在规模和性能等基础设施领域问题逐步解决的同时,规模化铺开 Kubernetes 的过程当中,咱们逐步发现这套体系里其实还有不少意想不到的挑战。这也是今天分享的主题。微信

第一个是 K8s 的 API 里其实并无“应用”的概念架构

并且,Kubernetes API 的设计把研发、运维还有基础设施关心的事情全都糅杂在一块儿了。这致使研发以为 K8s 太复杂,运维以为 K8s 的能力很是凌乱、零散,很差管理,只有基础设施团队(也就是咱们团队)以为 Kubernetes 比较好用。可是基础设施团队也很难跟研发和运维解释清楚 Kubernetes 的价值究竟是什么。app

咱们来看个实际的例子。less

1

就拿上图中的 replica 为 3 来讲,开发人员怎么知道实例数应该配几个呢?若是运维想要改replica,敢不敢改?能不能改?若是 replica 还能理解的话,那像 shareProcessNamespace 这种字段真是灵魂拷问了。 开发人员仅从字面意思知道这个可能跟容器进程共享有关,那么配置了这个应用会有什么影响呢?会不会有安全问题?运维

在阿里巴巴内部,不少 PaaS 平台只容许开发填 Deployment 的极个别字段。为何容许填的字段这么少?是平台能力不够强吗?其实不是的,本质缘由在于业务开发根本不想理解这众多的字段。

因此这个 PaaS 平台只容许用户填个别字段,其实反却是帮助业务开发人员避免了这些灵魂拷问。但反过来想,屏蔽掉大量字段真的就解决问题了吗?这种状况下,整个组织的基础设施能力还如何演进?应用开发和应用运维人员的诉求又该怎么传递给基础设施呢?

实际上,归根到底,Kubernetes 是一个 Platform for Platform 项目,它的设计是给基础设施工程师用来构建其余平台用的(好比 PaaS 或者 Serverless),而不是直面研发和运维同窗的。从这个角度来看,Kubernetes 的 API,其实能够类比于 Linux Kernel 的 System Call,这跟研发和运维真正要用的东西(Userspace 工具)彻底不是一个层次上的。你总不能让原本写 Java Web 的同窗天天直接调用着 Linux Kernel System Call,还给你点赞吧?

第二, K8s 实在是太灵活了,插件太多了,各类人员开发的 Controller 和 Operator 也很是多

这种灵活性,让咱们团队开发各类能力很容易,但也使得对于应用运维来讲, K8s 的这些能力管理变得很是困难。好比一个环境里的不一样运维能力,实际上有多是冲突的。

咱们来看一个例子,基础设施团队最近开发上线了一个新的插件,叫作 CronHPA,一个具体的 Spec 以下所示。

2

做为基础设施团队,咱们以为这种 K8s 插件很简单, CRD 也很容易理解。就像这个 CronHPA 的功能,从早上六点开始到下午七点钟这个实例最少有 20 个、最多有 25 个,到次日早上六点钟最少 1 个、最多有 9 个,在每一个阶段会根据 CPU 这个指标衡量调整实例数。

然而,就在咱们美滋滋的上线这个插件后不久,应用运维同窗就开始跟咱们抱怨了:

  1. “这个能力到底该怎么使用呢?它的使用手册在哪里?是看 CRD 仍是看文档呢?”
  2. “我怎么知道这个插件在某个集群里有没有装好呢?”
  3. “咱们运维不当心把 CronHPA 和 HPA 绑定给同一个应用,结果发现这个应用是会抽风的。为何大家 K8s 非要等到这种冲突发生的时候才报错呢?大家就不能设计个机制自动检查一下这些插件的使用过程有没有发生冲突吗?”其实这个咱们后来确实作了,解决方法是给咱们的 K8s 加了 20 多个 Admission Hook。

第三,也是阿里巴巴上云以后咱们团队特别痛的一个点。

咱们须要处理的应用的交付场景,除了公有云之外,还会有专有云、混合云、IoT 等各类复杂的环境。各类各样的云服务在这种复杂场景下,连 API 都是不统一的,这个时候咱们就须要专门的交付团队来进行弥补,一个一个的去对接、去交付应用。对他们来讲这是一件很是痛苦的事情:“不是说好的 Docker 化了以后就能‘一次打包、随处运行’了吗?”说白了,K8s 如今并无一个统一的、平台无关的应用描述能力。

阿里巴巴的解决办法

在 2019 年,咱们团队开始思考如何经过技术手段解决上述应用管理与交付相关的问题,到如今已经取得了必定的成果。

不过,在讲解阿里巴巴如何解决上述问题的方案以前,有必要先介绍一下咱们推动全部这些方案的理论基础。在这里,咱们主要遵循的是 CNCF 倡导的“应用交付分层模型”,以下图所示:

3

**这个模型的基础假设是:Kubernetes 自己并不提供完整的应用管理体系。**换句话说,基于 K8s 的应用管理体系,不是一个开箱即用的功能,而是须要基础设施团队基于云原生社区和生态本身构建出来的。这里面就须要引入不少开源项目或者能力。

而上面这个模型的一个重要做用,就是可以把这些项目和能力以及它们的协做关系,很是清晰地分类和表达出来。

  • 好比 Helm 就是位于整个应用管理体系的最上面,也就是第 1 层,还有 Kustomize 等各类 YAML 管理工具,CNAB 等打包工具,它们都对应在第 1.5 层;

  • 而后有 Tekton、Flagger 、Kepton 等应用交付项目,包括发布部署的流程,配置管理等,目前比较流行的是基于 GitOps 的管理,经过 git 做为“the source of truth”,一切都面向终态、透明化的管理,也方便对接,对应在第 2 层;

  • 而 Operator 以及 K8s 的各类工做负载组件(Deployment、StatefulSet 等),具体来讲就像某个实例挂了这些组件自动拉起来一个弥补上原来所须要三个的实例数,包括一些自愈、扩缩容等能力,对应在第 3 层;

  • 最后一层则是平台层,包括了全部底层的核心功能,负责对工做负载的容器进行管理、封装基础设施能力、对各类不一样的工做负载对接底层基础设施提供 API 等。

这些层次之间,经过相互之间的紧密协做,共同构建出一套高效、简洁的应用管理与交付体系。在这些层次当中,目前阿里巴巴在今年 KubeCon 时已经宣布开源了第三层的 OpenKruise 项目。最近,咱们则正在联合微软等更普遍的生态,和整个社区一块儿推动第一层“应用定义”相关的工做。

应用定义到底该怎么作?

其实,关于应用定义,不管是开源社区仍是在阿里巴巴内部,都已经作了很多尝试,好比一开始我提到 Docker 解决了单机应用交付,它就经过 Docker 镜像把单机应用定义的很好。

围绕 Kubernetes 咱们也试过使用 Helm 以及 Application CRD 来定义应用。可是如今的云原生应用,每每会依赖云上的资源,像数据库会依赖 RDS、访问会依赖 SLB,Helm 和 Application CRD 只是单纯地将 K8s 的 API 组合在一块儿,没法描述咱们对云上面资源的依赖,当咱们用 CRD 来描述云上资源依赖的时候,它实际上是 freestyle 的,没有一个很好的规范和约束,不管是用户、开发、运维仍是平台资源提供方都没有一个共识,天然也就没法协做和复用。

另外一方面,它们既然是简单的对 K8s API 的组合,那么 K8s API 自己“不面向应用研发和运维设计”的问题就依然存在,这并不符合咱们所但愿的“应用定义”应该走的方向。此外,像 Application CRD,它虽然是 K8s 社区的项目,可是却明显缺少社区活跃度,大多数修改都停留在一年前。

试了一圈,咱们发现“应用定义”这个东西,在整个云原生社区里实际上是缺失的。这也是为何阿里巴巴内部有不少团队开始尝试设计了本身的“定义应用”。简单地说,这个设计其实就是把应用自己的镜像、启动参数、依赖的云资源等等所有描述起来,分门别类的进行放置,并经过一个模板,最终渲染出一个配置文件,文件里有上千个字段,完整描述了一个应用定义的全部内容。这个配置文件大概长下面这个样子:

4

除了基本的 Deployment 描述字段,这种 in-house 应用定义每每还会包含云上资源的声明,好比使用哪一种 ECS 套餐、如何续费、使用的是哪一种磁盘和规格等等一系列额外的描述。这些资源的定义是一大块,而且上面的例子里咱们已经尽可能精简了;另外一大块就是运维能力的描述,好比自动扩缩容、流量切换、灰度、监控等,涉及到一系列的规则。

然而,你也不难看到,这种定义方式最终全部的配置仍是会所有堆叠到一个文件里,这跟 K8s API all-in-one 的问题是同样的,甚至还更严重了。并且,这些应用定义最终也都成为了黑盒,除了对应项目自己可使用,其余系统基本没法复用,天然就更没法使得多方协做复用了。

吸收了这些教训之后,咱们团队决定从另外一个方向开始设计一个新的应用定义。

具体来讲,相比于其余“应用定义”给 K8s 作加法、作整合的思路,咱们认为,真正良好的应用定义,应该给 K8s API 作“减法”。更准确的说,是咱们应该经过“作减法”,把开发者真正关心的 API 给暴露出来,把运维、平台关心的 API 给封装起来。

也就是说,既然 K8s API 为了方便基础设施工程师,已经选择把各方的关注点混在了一块儿。那么,当基础设施工程师想要基于 K8s 来服务更上层应用开发和运维人员时,其实应该考虑把这些关注点从新梳理出来,让应用管理的各个参与方从新拿到属于本身的 API 子集。

因此,咱们开始在 K8s API 的基础上增长了一层很薄的抽象,从而把原始的 K8s API 按照现实中的协做逻辑进行合理的拆分和分类,而后分别暴露给研发和运维去使用。这里的原则是:研发拿到的 API 必定是研发视角的、没有任何基础设施的概念在里面;而运维拿到的 API,必定是对 K8s 能力的模块化、声明式的描述。这样,在理想状况下,运维(或者平台)就可以对这些来自双方的 API 对象进行组合,好比:应用 A + Autoscaler X,应用 B + Ingress Y。这样组合完成后的描述对象,其实就能够完整的来描述“应用”这个东西了。

Open Application Model (OAM)

在同社区进行交流和验证中,咱们发现:上面的这个思路正好跟当时微软 Brendan Burns (Kubernetes 项目创始人)和 Matt Butcher (Helm 项目创始人)团队的思路不谋而合。因此咱们双方在面对面交流了几回以后,很快就决定共建这个项目并把它开源出来,跟整个社区生态一块儿来推动这件很是具备意义的事情。

今年 10 月 17 号,阿里云小邪和微软云 CTO Mark 共同对外宣布了这个项目的开源,它的官方名字叫作 Open Application Model(OAM),同时咱们还宣布了 OAM 对应的 K8s 实现——Rudr 项目

具体来讲,在设计 OAM 的时候,咱们但愿这个应用定义应该解决传统应用定义的三个问题:

  • 第一,不能有运行时锁定。一套应用定义,必须能够不加修改跑到不一样运行环境当中,不管是否是基于 K8s,这是解决咱们在应用交付时所遇到的问题的关键。这才是真正的“一次定义、随处运行”;

  • 第二,这个应用定义必需要区分使用角色,而不是继续延续 K8s 的 all-in-one API。 咱们已经深入了解到,咱们所服务的应用开发人员,实际上很难、也不想关心运维以及 K8s 底层的各类概念,咱们不该该让他们本来已经很苦逼的日子变得更糟;

  • 最后一个,这个应用定义必须不是在一个 YAML 里描述全部东西。一旦一个应用定义里把全部信息所有耦合在一块儿,就会形成应用描述和运维描述被杂糅在一块儿,从而致使这个定义的复杂度成倍提高,也会让这个定义彻底没法复用。咱们但愿这些不一样领域的描述可以分开,而后平台能够自由地组合搭配。

在这个思路下,咱们最后设计出来的应用定义主要分为三个大块:

  • 第一部分是应用组件的描述,包括应用组件怎么运行和该组件所依赖的各类资源。这个部分是开发负责编写的;

  • 第二部分是运维能力的描述,好比应用怎么 scale、怎么访问、怎么升级等策略。这个部分是运维负责编写的;

  • 第三部分是把上述描述文件组合在一块儿的一个配置文件。好比:“ 一个应用有两个组件,组件 A 须要运维能力 X 和能力 Y,组件 B 须要运维能力 X”。因此这个配置文件,其实才是最终的“应用”。这个配置文件,也是运维编写,而且提交给平台去运行的,固然,平台也能够自动生成这个文件。

下面咱们经过实例来看下以上三个部分对应的 YAML 文件到底长什么样子?它们究竟怎么玩儿?

备注:若是你想跟我同样实际操做体验这个流程,你只须要在 K8s 集群里装上 Rudr 项目就能够实操了。

第一部分:Component

5

首先咱们能够看到,Component 定义的是开发关心的事情,没有任何运维相关的概念。

它的 Spec 主要分为两大块:

第一个参数块是应用描述,包括 WorkloadType 字段,这个字段就是表达应用使用什么 Workload 运行,在咱们设计里有六种默认 Workload,分别是 Server、Worker、Job 以及他们对应的单例模式,Workload 也能够扩展。Server 表明这是一个能够自动伸缩的,而且有一个端口能够访问的模式。接下来就是容器的镜像、启动参数之类的,这部分包含完整的 OCI spec。

第二块是 parameters 如何运行可扩展的参数,如环境变量和端口号。这一块参数的特色是:它们虽然是开发定义的,可是都容许运维后续覆盖。这里的关键点是,关注点分离并不等于彻底割裂。因此,咱们设计了 parameters 列表,其实就是但愿开发能告诉运维,哪些参数后续能够被运维人员覆盖掉。这样的话就很好地联动起来了,开发人员能够向运维人员提出诉求,好比运维应该使用哪些参数、参数表明什么意思。

像这样一个 Component 能够直接经过 kubectl 安装到 K8s 中。

6

而后咱们能够经过 kubectl 工具查看到已经安装好的组件有哪些:

7

因此说,咱们当前的 K8s 集群,支持两种“应用组件”。须要指出的是,除了咱们内置支持的组件以外,开发本身能够自由定义各类各样的组件而后提交给咱们。Component Spec 里的 Workload Type 是能够随意扩展的,就跟 K8s 的 CRD 机制同样。

第二部分: Trait

说完了开发能用的 API,咱们再来看运维用的 API 长什么样。

在设计应用的运维能力定义的过程当中,咱们重点关注的是运维能力怎么发现和管理的问题。

为此,咱们设计了一个叫作 Trait 的概念。所谓 Trait,也就是应用的“特征”,其实就是一种运维能力的声明式描述。咱们能经过命令行工具发现一个系统里支持哪些 Traits(运维能力)。

8

这时候,运维要查看具体的运维能力该怎么使用,是很是简单的:

9

能够看到,他能够在 Trait 定义里清晰的看到这个运维能力能够做用于哪一种类型的 Workload,包括能填哪些参数?哪些必填?哪些选填?参数的做用描述是什么? 你也能够发现,OAM 体系里面,Component 和 Trait 这些 API 都是 Schema,因此它们是整个对象的字段全集,也是了解这个对象描述的能力“到底能干嘛?”的最佳途径(反正基础设施团队的文档写的也不咋地)。

上面这些 Trait 也都是用过 kubectl apply 就能够安装到集群当中的。

既然 Component 和 Trait 都是 Schema,那么它们怎么实例化成应用呢?

第三部分:Application Configuration

在 OAM 体系中,Application Configuration 是运维人员(或者系统自己也能够)执行应用部署等动做的操做对象。在 Application Configuration 里,运维人员能够将 Trait 绑定到 Component 上执行。

在 Application Configuration YAML 里面,运维能够把 Component 和 Trait 组装起来,从而获得一个能够部署的“应用”:

10

在这里咱们能够看到,运维实例化的应用里面包含了一个叫 hellowworld-python-v1 的 Component,它有两个参数:一个是环境变量 target,一个是port。须要注意的是,这两个参数是运维人员覆盖了原先 Component yaml 中开发定义的两个可覆盖变量。

同时,这个 Component 绑定了 2 个运维能力:一个是水平扩容,一个是 Ingress 域名访问。

运维人员经过 kubectl 便可把这样一个应用部署起来:

11

这时候在 K8s 里面,你就能够看到 OAM 插件会自动为你建立出对应的 Deployment。

12

同时,这个应用须要的 Ingress 也被自动建立起来了:

13

这里实际上是前面提到的 Rudr 插件在起做用,在拿到 OAM 的 Application Configuration 文件之后,识别出其中的 Component 和 Trait,将其映射到 K8s 上的资源并拉起,K8s 资源相应的生命周期都随着 OAM 的配置去管理。固然,因为 OAM 定义是平台无关的,因此除了 K8s 自己的资源,Rudr 插件的实现中也会加入外部资源的拉起。

OAM YAML 文件 = 一个自包含的软件安装包

最终咱们能够经过像乐高积木同样组装复用 OAM 的不一样模块,实例化出一个 OAM 的应用出来。更重要的是,这个 OAM 应用描述文件是彻底自包含的,也就是说经过 OAM YAML,做为软件分发商,咱们就能够完整地跟踪到一个软件运行所须要的全部资源和依赖。

14

这就使得如今对于一个应用,你们只须要一份 OAM 的配置文件,就能够快速、在不一样运行环境上把应用随时运行起来,把这种自包含的应用描述文件完整地交付到任何一个运行环境中。

这不只让咱们前面提到的软件交付难题获得了很好的解决,也让更多非 K8s 平台好比 IoT、游戏分发、混合环境软件交付等场景,能享受到云原生应用管理的畅快。

最后

OAM 是一个彻底属于社区的应用定义模型,咱们很是但愿你们都能参与进来。

15

钉钉扫码加入交流群

  • 一方面,若是你有任何场景感受 OAM 没法知足的,欢迎你在社区提出 issue 来描述你的案例;

  • 另外一方面,OAM 模型也正在积极的同各个云厂商、开源项目进行对接。

咱们期待能与你们一块儿共建这个全新的应用管理生态。

Q & A

Q1:OAM spec 中目前尚未看到属于 Infra Operator 的管理对象(补充:Component 是面向 App Developer,Traits 和 AppConfiguration 面向 App Operator,哪一个对象是面向 Infra Operator 的?) A1:OAM 自己就是基础设施运维手里的武器,包括 Kubernetes、Terraform 等一系列平台层的开源项目,基础设施运维能够经过这些开源项目构建 OAM 的实现(如 Rudr 基于 Kubernetes)。因此 OAM 的实现层就是基础设施运维提供的,他们不须要额外的对象来使用 OAM。

Q2:OAM Controller和 admission controller 的分工标准是什么? A2:OAM 项目中的 admission controller 用于转换和检验 spec,彻底等价于 K8s 中 admission controller。目前实现的功能包括转换 [fromVariable(VAR)] 这种 spec 中的函数,检验 AppConfig、Component、Trait、Scope 等 CR 是否符合规范,是否合法等。OAM Controller,即目前的开源项目 Rudr,就是整个 OAM 的实现层,它负责解释 OAM 的 spec 并转换为真实运行的资源,这里的资源能够是 K8s 原有的一些,也能够是像阿里云上的 RDS 这类云资源。目前 Rudr 项目是 Rust 语言写的,考虑到 K8s 生态大多数都是用 Go 语言写的,咱们后续也会开源一个 Go 语言编写的 OAM-Framework,用于快速实现像 Rrudr 这样的 OAM 实现层。

Q3:计划啥时候开源 Go 的 OAM-Framework 呀? A3:咱们须要一点时间进一步打磨 OAM-Framework ,让它适配你们的场景。可是应该很快就会跟你们见面。

Q4:阿里是如何下降 K8s 的复杂度来知足运维和研发一些共性诉求的?在 K8s 中的用户 user 角色多是开发也多是运维。 A4:目前咱们遇到的大多数场景都能区分哪些是运维要关心的,哪些是研发要关心的。OAM 下降 K8s 复杂度的主要方法就是关注点分离,给 K8s 的 API 作减法,尽可能让某一方能够少关注一些内容。若是你有这样一个没法分割的场景,其实咱们也很感兴趣,欢迎把 case 提出来一块儿探讨。另外一方面,咱们并非屏蔽掉 K8s,OAM Spec 预留了充足的扩展性,彻底能够把K8s原有的能力提供给用户。

Q5:我认为 OAM 是基于 K8s 针对于不一样应用上的抽象层,如今咱们有不少应用都是用 Helm 包包装好的,若是切换成 OAM 的话,咱们须要注意哪些地方呢? A5:其实咱们上半年一直在推广 Helm 在国内的使用,包括提供了阿里巴巴的 Helm 镜像站(https://developer.aliyun.com/hub)等,因此 OAM 跟 Helm 也是相辅相成的。简单的说,OAM 其实就是 Helm 包里面 template 文件夹里面的内容。Helm 是 OAM 作参数渲染(template)和打包(chart)的工具。若是切换到 OAM,Helm 的使用方式不须要变,里面的 spec 换成 OAM 的 spec 便可。

Q6:请问,Rudr 用起来了吗,效果如何。Rudr 的架构有没更丰富的资料? A6:Rudr 一直是能够用的,你们要是用不起来能够提 issue,想要什么方面的资料或者疑问也能够提 issue,咱们也在完善文档。目前相关的材料都在这里: https://github.com/oam-dev/rudr/tree/master/docs

**Q7:**咱们一直在用 Helm 打包咱们的应用,去作 gitops ,一个通用的 chart 对应不一样的 values.yaml 作到了复用。听了分享,很期待 OAM,固然还有 Openkruise。<br />**A7:**Openkruise 是开源的哈,你们能够关注 https://github.com/openkruise/kruise 咱们也一直在迭代。

Q8:OAM 有哪些公司在用?实际体验反馈如何? A8:OAM 刚刚发布一个月左右,具体有哪些公司已经在使用咱们尚未来得及统计。阿里巴巴和微软内部都已经在使用,而且都有对外的产品使用 OAM。就咱们接触到的用户来讲,不管是社区的用户仍是阿里巴巴内部,都对 OAM 的关注点分离等理念很是认同,也都在积极落地。


社群分享文章整理

Vol 1 : 当 K8s 集群达到万级规模,阿里巴巴如何解决系统各组件性能问题?

Vol 2 : 超大规模商用 K8s 场景下,阿里巴巴如何动态解决容器资源的按需分配问题?

Vol 3 : 备战双 11!蚂蚁金服万级规模 K8s 集群管理系统如何设计?

**Vol 4 **: 带你上手一款下载超 10 万次的 IEDA 插件

“ 阿里巴巴云原生微信公众号(ID:Alicloudnative)关注微服务、Serverless、容器、Service Mesh等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术公众号。”

相关文章
相关标签/搜索