- 浏览: 110665 次
- 性别:
- 来自: 北京
最新评论
阿里巴巴基于 Kubernetes 的实践经验
本文整理自孙健波在 ArchSummit 大会 2019 北京站演讲稿记录。首先介绍了阿里巴巴基于 Kubernetes 项目进行大规模应用实践过程中遇到的问题;随后会逐一介绍解决这些问题的现有实践及其本身存在的局限性;最后会介绍阿里巴巴目前正在进行的尝试和社区在这一领域的发展方向。
如今,阿里巴巴内部维护了数十个大规模的 K8s 集群,其中最大的集群约 1 万个节点,每个集群会服务上万个应用;在阿里云的 Kubernetes 服务 ACK 上,我们还维护了上万个用户的 K8s 集群。我们在一定程度上解决了规模和稳定性问题之后,发现其实在 K8s 上管理应用还有很大的挑战等着我们。
应用管理的两大难题
---------
今天我们主要讨论这两个方面的挑战:
对应用研发而言,K8s API 针对简单应用过于复杂,针对复杂应用难以上手;
对应用运维而言,K8s 的扩展能力难以管理;K8s 原生的 API 没有对云资源全部涵盖。
总体而言,我们面临的挑战就是:如何基于 K8s 提供真正意义上的应用管理平台,让研发和运维只需关注到应用本身。
研发对应用管理的诉求
----------
### 1\. K8s all in one 的 YAML 文件
让我们来看一下这样一个 K8s 的 yaml 文件,这个 yaml 文件已经是被简化过的,但是我们可以看到它仍然还是比较长。
![lALPDgQ9rYRXqs_NBJLNAzg_824_1170_png_620x10000q90g](https://yqfile.alicdn.com/310747348e59a226369241a069d145519c442c7a.jpeg)
面对这样一个广受“复杂”诟病的 YAML 文件,我相信大家都会忍不住想该怎么简化。
自上而下,我们大致把它们分为三块:
* 一块是扩缩容、滚动升级相关的参数,这一块应该是应用运维的同学比较关心的;
* 中间一块是镜像、端口、启动参数相关的,这一块应该是开发的同学比较关心的;
* 最后一块大家可能根本看不懂,通常情况下也不太需要明白,可以把它们理解为 K8s 平台层的同学需要关心的。
看到这样一个 yaml 文件,我们很容易想到,只要把里面的字段封装一下,把该暴露的暴露出来就好了。确实,我们内部就有 PaaS 平台这么做。
### 2\. 只透出部分字段:简单却能力不足
内部的某个 PaaS 平台精心挑选了部分字段,并做了一个漂亮的前端界面给用户,只透出给用户 5 个左右的字段,大大降低了用户理解 K8s 的心智负担。然后底层实现用类似模板的方式把用户这五个字段渲染出来一个完整的 yaml 文件。
突出的字段大概如下图所示:
![lALPDgQ9rYRXqtLNAX3NBDg_1080_381_png_620x10000q90g](https://yqfile.alicdn.com/f159786106cf5b5e6872634d8d7d8ed2badd0bb5.jpeg)
不得不说这种方式是非常有效的,针对简单无状态的应用,精简 API 可以大大降低 K8s 的门槛,快速并且高效的对接用户,PaaS 平台也顺利让大家使用了起来。同时,我也从一些技术分享中了解到许多其他公司也是用这种类似的方式简化的 K8s API。
但是当用户的业务开始大规模对接以后,我们就会自然而然遇到有状态的复杂应用,用户就会开始抱怨 PaaS 平台能力不够了。比如我们的 Zookeeper 多实例选主、主从切换这些逻辑,在这五个字段里就很难展开了。
归根结底就是屏蔽大量字段的方式会限制基础设施本身的能力演进,但是 K8s 的能力是非常强大而灵活的。我们不可能为了简化而放弃掉 K8s 强大的能力。
就比如当前这个例子,我们很容易想到,针对复杂有状态的应用,应该通过 K8s 里面的 CRD 和 Operator 来解决。
### 3\. CRD+Operator: K8s 扩展能力强大却难以上手
确实,我们内部对接复杂应用云原生化的时候,也推荐他们编写 Operator,但是经常出现这样一段对话。
![lALPDgQ9rYRXqtXNAl7NBDg_1080_606_png_620x10000q90g](https://yqfile.alicdn.com/d66e18096caed28ddc7239560b0efda1b6a8f726.jpeg)
中间件的工程师跟我们说,我这有个 Zookeeper 该用哪种 K8s 的 Workload 接入啊?我们想了想,K8s 设计如此精妙,自然没有解决不了的问题,于是我们推荐他们使用 Operator。他们就懵了,说你们搞云原生的这几年造新词的能力绝对一流,之前都没听说过。
想想也是,业务方理解这些新概念不难,但是真的要自己去上手实现,还是非常困难的。我们自然也觉得业务方更应该专注于他们的业务本身,于是我们不得不帮他们一起写。
可以看到,我们亟需一个统一的模型去解决研发对应用管理的诉求。
运维对应用管理的诉求
----------
除了研发侧的问题之外,我们在运维侧也遇到了很大的挑战。
### 1\. 运维能力众多却难以管理
K8s 的 CRD Operator 机制非常灵活而强大,不光是复杂应用可以通过编写 CRD Operator 实现,我们的运维能力也大量通过 Operator 来扩展,比如灰度发布、流量管理、弹性扩缩容等等。
我们常常赞叹于 K8s 的灵活性,它让我们基础平台团队对外提供能力非常方便,但是对应用运维来说,他们要使用我们提供的这些运维能力,却变得有些困难。
比如我们上线了一个 CronHPA,可以定时设置在每个阶段会根据 CPU 调整实例数的范围。应用运维并不知道跟原生不带定时功能的 HPA 会产生冲突,而我们也没有一个统一的渠道帮助管理这么多种复杂的扩展能力,结果自然是引起了故障。这血的教训提醒我们要做事前检查,熟悉 K8s 的机制很容易让我们想到为每个 Operator 加上 admission webhook。
这个 admission webhook 需要拿到这个应用绑定的所有运维能力以及应用本身的运行模式,然后做统一的校验。如果这些运维能力都是一方提供的还好,如果存在两方,甚至三方提供的扩展能力,我们就没有一个统一的方式去获知了。
事实上如果我们想的更远一些就会发现,我们需要一个统一的模型来协商并管理这些复杂的扩展能力。
### 2\. 云资源难以描述和统一交付
当我们把应用的 Operator 以及对应的运维能力都写好以后,我们很容易想到要打包交付这个应用,这样无论是公有云还是专有云都可以通过一个统一的方式去交互。社区的主流方式目前就是使用 Helm 来打包应用,而我们也采用了这样的方式给我们的用户交付,但是却发现我们的用户需求远不止于此。
云原生应用有一个很大的特点,那就是它往往会依赖云上的资源,包括数据库、网络、负载均衡、缓存等一系列资源。
![lALPDgQ9rYRXqtfNAgXNBDg_1080_517_png_620x10000q90g](https://yqfile.alicdn.com/aa119c53b5830d36338eb4113aacd84a1de59ea6.jpeg)
当我们使用 Helm 打包时,我们只能针对 K8s 原生 API,而如果我们还想启动 RDS 数据库,就比较困难了。如果不想去数据库的交互页面,想通过 K8s 的 API 来管理,那就又不得不去写一个 CRD 来定义了,然后通过 Operator 去调用实际云资源的 API。
这一整套交付物实际上就是一个应用的完整描述,即我们所说的“应用定义”。但事实上,我们发现“应用定义”这个东西,在整个云原生社区里其实是缺失的。这也是为什么阿里巴巴内部有很多团队开始尝试设计了自己的“应用定义”。
![lALPDgQ9rYRXqtjNAozNBDg_1080_652_png_620x10000q90g](https://yqfile.alicdn.com/33ce1294cc7d94defb30b0cf247a0640a08699a7.jpeg)
这种定义方式最终所有的配置还是会全部堆叠到一个文件里,这跟 K8s API all-in-one 的问题其实是一样的,甚至还更严重了。而且,这些应用定义最终也都成为了黑盒,除了对应项目本身可以使用,其他系统基本无法复用,自然就更无法使得多方协作复用了。
### 3\. 每个公司和团队都在自己定义应用
不光是阿里巴巴内部的团队需要应用定义,事实上几乎每个基于 K8s 管理应用的公司和团队都在自己定义应用。如下所示,我就搜到了两家公司的应用定义:
![lALPDgQ9rYRXqtnNAtzNAug_744_732_png_620x10000q90g](https://yqfile.alicdn.com/1d767e6060739fa788250dd54f0a9c65321874e8.jpeg)
![lADPDgQ9rYRXqt3NARDNAyw_812_272_jpg_620x10000q90g](https://yqfile.alicdn.com/8a90f2891521149ddf553bb242057f32d5e7c369.jpeg)
应用定义实际上是应用交付/分发不可或缺的部分。但是在具体的实践中,我们感受到这些内部的应用定义都面临着如下的问题:
* 定义是否足够开放,是否可以复用?
* 如何与开源生态协作?
* 如何迭代与演进?
这三个问题带来的挑战都是巨大的,我在上文已经提到,一个应用定义需要容易上手,但又不失灵活性,更不能是一个黑盒。应用定义同样需要跟开源生态紧密结合,没有生态的应用定义注定是没有未来的,自然也很难持续的迭代和演进。
区分使用者的分层模型与模块化的封装
-----------------
让我们回过头来重新审视我们面临的挑战,归根结底在于 K8s 的 All in One API 是为平台提供者设计的,我们不能像下图左侧显示的一样,让应用的研发、运维跟 K8s 团队一样面对这一团 API。
![lALPDgQ9rYRXqt7NAYjNBDg_1080_392_png_620x10000q90g](https://yqfile.alicdn.com/a5044b5b40d580feb972092b734fe09876a62138.jpeg)
一个合理的应用模型应该具有区分使用者角色的分层结构,同时将运维能力模块化的封装。让不同的角色使用不同的 API,正如上图右侧部分。
OAM:以应用为中心的 K8s API 分层模型
------------------------
OAM(Open Application Model) 正是这样一个以应用为中心的 K8s API 分层模型:
* 从研发的角度,他操作和关注的 API 对象叫 Component;
* 从运维的角度,模块化的运维能力封装就是 Trait,而运维可以通过 App Config 将 Component 和 Trait 自由组合,最终实例化成一个运行的应用;
* K8s 团队本身则仍然基于 K8s 的原生 API 迭代这一层能力。
![lALPDgQ9rYRXqt_NAabNBDg_1080_422_png_620x10000q90g](https://yqfile.alicdn.com/01300a8e8884e58f64011af2c255c958de13fb4b.jpeg)
针对研发时常抱怨的 K8s API 太复杂,我们通过关注点分离,区分使用者面对的 API 来解决,同时提供了几种核心的 Workload,让研发只需要填写少数几个字段就可以完成组件的定义;针对复杂应用定义,我们通过扩展的 Workload,允许研发对接 CRD Operator 的方式对接自定义 Workload。
针对运维需要的模块化封装运维能力和全局管理的需求,OAM 模型通过 Trait 来提供。
Trait 是运维能力的体现,不同的 Trait 也对应了不同类型的运维能力,如日志收集 Trait、负载均衡 Trait、水平扩缩容 Trait 等等;同时 OAM 本身就提供了一个全局管理的标准,OAM 模型的实现层可以轻松针对 OAM 定义里的种种 Trait 描述进行管理和检查。
针对云资源,OAM 向上也提供了统一的 API,也是通过关注点分为三类:
一类是研发关注的云资源,如数据库 RDS、对象存储 OSS 等,通过扩展 Workload 接入;
另一类是运维关注的云资源,如负载均衡 SLB 等,通过 Trait 接入;
最后一类也是运维关注的云资源,但是可能包含多个应用之间的联动关系,如虚拟专有网络 VPC 等,通过应用的 Scope 接入。Scope 则是 OAM 中管理多应用联动关系的概念。
可以看到,OAM 通过统一的一套标准,解决了我们今天提到的所有难题。让我们继续深入到 OAM 中看看不同的概念具体是什么。
**1\. OAM Component:研发关注的 API**
Component 就是 OAM 模型提供给研发的 API 对象,如下所示:
```
apiVersion: core.oam.dev/v1alpha1
kind: Component
metadata:
name: nginx
annotations:
version: v1.0.0
description: >
Sample component schematic that describes the administrative interface for our nginx deployment.
spec:
workloadType: Server
osType: linux
containers:
- name: nginx
image:
name: nginx:1.7.9
digest: <sha256:...>
env:
- name: initReplicas
value: 3
- name: worker_connections
fromParam: connections
workloadSettings:
...
parameters:
- name: connections
description: "The setting for worker connections"
type: number
default: 1024
required: false
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
可以看到 Component 本身就是一个 K8s 的CRD,spec 字段里面的部分就是 Component 具体的定义。其中第一个重要的字段就是 workloadType,这个决定了应用的运行模式。
针对简单应用,OAM 提供了 6 种核心 Workload,如下表所示:
![lADPDgQ9rYRXquvNATbNAzg_824_310_jpg_620x10000q90g](https://yqfile.alicdn.com/318500fbbeec88ab3a6c24754a21d6fa3f10ff4d.jpeg)
主要通过是否可访问、是否可复制、是否长久运行来区分。如 Server,就代表了大家最常用的 K8s 里面 Deployment+Service 的组合。
填写了核心 workloadType 的 Component,只需要定义 Container 里的注入镜像、启动参数等字段,就如我们最开始所说的屏蔽掉大量字段的 PaaS 一样,为用户大大降低了门槛。
而针对复杂的有状态应用,OAM 则允许通过扩展 Workload 来实现,如下图所示,我们可以定义一个新的叫 openfaas 的 WorkloadType,它的定义实际上完全等价于一个 CRD 定义。
![lALPDgQ9rYRXquzNAm_NBDg_1080_623_png_620x10000q90g](https://yqfile.alicdn.com/256938fdbd472c10d6bcf869153362681a471b1f.jpeg)
OAM 模型中,使用自定义的 Workload 也是通过 Component,只是 WorkloadType 改为你自定义的 WorkloadType 名称。
**2\. OAM Trait:可发现、可管理的运维能力**
Trait 就是模块化的运维能力,我们能通过命令行工具发现一个系统里支持哪些 Traits(运维能力)。
```
$ kubectl get traits
NAME AGE
autoscaler 19m
ingress 19m
manual-scaler 19m
volume-mounter 19m
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
这时候,运维要查看具体的运维能力该怎么使用,是非常简单的:
```
$ kubectl get trait ingress -o yaml
apiVersion: core.oam.dev/v1alpha1
kind: Trait
metadata:
name: cron-scaler
annotations:
version: v1.0.0
description: "Allow cron scale a workloads that allow multiple replicas."
spec:
appliesTo:
- core.oam.dev/v1alpha1.Server
properties: |
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"schedule"
],
"properties": {
"schedule": {
"type": "array",
"description": "CRON expression for a scaler",
"item": {
"type": "string"
}
},
"timezone": {
"type": "string",
"description": "Time zone for this cron scaler."
},
"resource":{
"type": "object"
"description": "Resources the cron scaler will follow",
"properties": {
"cpu": {
type: "object"
...
}
}
}
}
}
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
可以看到,他可以在 Trait 定义里清晰的看到这个运维能力可以作用于哪种类型的 Workload,包括能填哪些参数、哪些必填/选填、参数的作用描述是什么。你也可以发现,OAM 体系里面,Component 和 Trait 这些 API 都是 Schema,所以它们是整个对象的字段全集,也是了解这个对象描述的能力“到底能干吗?”的最佳途径。
事实上,大家可能已经发现,Trait 的定义和 CRD 是对等的,而你完全也可以通过 Operator 实现 Trait。
![lALPDgQ9rYRXqu7NAnjNBDg_1080_632_png_620x10000q90g](https://yqfile.alicdn.com/52a9d7efeac5eac17fb600ae1a0edbb3f104e64d.jpeg)
所以 OAM 事实上将原本散乱的 Operator 通过不同的角色有机的管理起来了。
**3\. OAM Application Config:组装 Component 和 Trait,应用实例化运行**
Component 和 Trait 最终通过 Application Configuration 结合,并真实运行起来。
![lALPDgQ9rYRXqu_NAe3NBDg_1080_493_png_620x10000q90g](https://yqfile.alicdn.com/bfa0714b2386eaa4a330779f555f65492dc3c92d.jpeg)
更重要的是,这个 OAM 应用描述文件是完全自包含的,也就是说通过 OAM YAML,作为软件分发商,我们就可以完整地跟踪到一个软件运行需要的所有资源和依赖。这就使得现在对于一个应用,大家只需要一份 OAM 的配置文件,就可以快速、在不同运行环境上把应用随时运行起来,把这种自包含的应用描述文件完整地交付到任何一个运行环境中。
而我们图中的 Rudr 项目就是 OAM 的一个实现,也可以理解为 OAM 的一个解释器,将 OAM 的统一描述转换为背后众多的 Operator。
同时 Rudr 也是一个统一管理的媒介,如果 Application Configuration 中出现了一个 Component 绑定 2 个 Trait 并且互相冲突的情况,就可以快速被检验并发现问题,如下图所示:
![lALPDgQ9rYRXqvHNAvLNAnw_636_754_png_620x10000q90g](https://yqfile.alicdn.com/b2f84fc5da8273bdde23a8a78693f148032b933e.jpeg)
同样,包括复杂应用的编排、云资源的拉起、Workload 与 Trait 交互等等,都可以在这个 OAM 解释器中实现。
大家可以通过 Rudr 项目中的教程文档体验 OAM 的这些交互过程。
OAM 加持下的 Kubernetes PaaS
------------------------
事实上,OAM 加持下的 PaaS 基于 Kubernetes,将众多 Operator 分层的管理了起来。
![lALPDgQ9rYRXqvLNAebNBDg_1080_486_png_620x10000q90g](https://yqfile.alicdn.com/1639b5865d13dcb8c5aa1303ff0ecb41e8b61674.jpeg)
对于研发,通常他关心的应用可能是一个由 web 和数据库组合而成的应用,数据库组件的背后可能是一个 RDS Operator 实现。web 应用背后,则可以是我们开源的 K8s 原生 StatefulSet的增强项目 OpenKruise,OpenKruise 中提供的包括原地升级等增强能力则通过 Trait 的方式去配置。而额外的一些监控报警、日志等能力,则由一个个独立的 Operator 去实现,由运维在第二层去关注和管理。
最终 K8s 团队联合各种基础软件的提供商,围绕 K8s 原生 API,以 Operator 的形式不断提供扩展能力,通过 OAM 这样统一的规范和标准向外标准化输出。
更重要的是,OAM 的统一描述大大提高了 Operator 的复用能力,使得 Operator 的编写主需要关注业务逻辑本身。比如原先你写一个 Zookeeper Operator,你需要写实例的服务发现、需要写升级时主备切换的编排逻辑、需要写实例备份的逻辑,而这一切在 OAM 的标准化下,你将可以轻松在社区找到类似组成部分。
OAM 加持下的 Kubernetes PaaS,使得不同的 Operator 可以像乐高积木一样灵活组装,使得应用定义成为了社区共同建设的项目,使得应用管理变得统一,功能却更加强大!
[原文链接](https://link.zhihu.com/?target=https%3A//yq.aliyun.com/articles/739645%3Futm_content%3Dg_1000094672)
本文为阿里云内容,未经允许不得转载。
如今,阿里巴巴内部维护了数十个大规模的 K8s 集群,其中最大的集群约 1 万个节点,每个集群会服务上万个应用;在阿里云的 Kubernetes 服务 ACK 上,我们还维护了上万个用户的 K8s 集群。我们在一定程度上解决了规模和稳定性问题之后,发现其实在 K8s 上管理应用还有很大的挑战等着我们。
应用管理的两大难题
---------
今天我们主要讨论这两个方面的挑战:
对应用研发而言,K8s API 针对简单应用过于复杂,针对复杂应用难以上手;
对应用运维而言,K8s 的扩展能力难以管理;K8s 原生的 API 没有对云资源全部涵盖。
总体而言,我们面临的挑战就是:如何基于 K8s 提供真正意义上的应用管理平台,让研发和运维只需关注到应用本身。
研发对应用管理的诉求
----------
### 1\. K8s all in one 的 YAML 文件
让我们来看一下这样一个 K8s 的 yaml 文件,这个 yaml 文件已经是被简化过的,但是我们可以看到它仍然还是比较长。
![lALPDgQ9rYRXqs_NBJLNAzg_824_1170_png_620x10000q90g](https://yqfile.alicdn.com/310747348e59a226369241a069d145519c442c7a.jpeg)
面对这样一个广受“复杂”诟病的 YAML 文件,我相信大家都会忍不住想该怎么简化。
自上而下,我们大致把它们分为三块:
* 一块是扩缩容、滚动升级相关的参数,这一块应该是应用运维的同学比较关心的;
* 中间一块是镜像、端口、启动参数相关的,这一块应该是开发的同学比较关心的;
* 最后一块大家可能根本看不懂,通常情况下也不太需要明白,可以把它们理解为 K8s 平台层的同学需要关心的。
看到这样一个 yaml 文件,我们很容易想到,只要把里面的字段封装一下,把该暴露的暴露出来就好了。确实,我们内部就有 PaaS 平台这么做。
### 2\. 只透出部分字段:简单却能力不足
内部的某个 PaaS 平台精心挑选了部分字段,并做了一个漂亮的前端界面给用户,只透出给用户 5 个左右的字段,大大降低了用户理解 K8s 的心智负担。然后底层实现用类似模板的方式把用户这五个字段渲染出来一个完整的 yaml 文件。
突出的字段大概如下图所示:
![lALPDgQ9rYRXqtLNAX3NBDg_1080_381_png_620x10000q90g](https://yqfile.alicdn.com/f159786106cf5b5e6872634d8d7d8ed2badd0bb5.jpeg)
不得不说这种方式是非常有效的,针对简单无状态的应用,精简 API 可以大大降低 K8s 的门槛,快速并且高效的对接用户,PaaS 平台也顺利让大家使用了起来。同时,我也从一些技术分享中了解到许多其他公司也是用这种类似的方式简化的 K8s API。
但是当用户的业务开始大规模对接以后,我们就会自然而然遇到有状态的复杂应用,用户就会开始抱怨 PaaS 平台能力不够了。比如我们的 Zookeeper 多实例选主、主从切换这些逻辑,在这五个字段里就很难展开了。
归根结底就是屏蔽大量字段的方式会限制基础设施本身的能力演进,但是 K8s 的能力是非常强大而灵活的。我们不可能为了简化而放弃掉 K8s 强大的能力。
就比如当前这个例子,我们很容易想到,针对复杂有状态的应用,应该通过 K8s 里面的 CRD 和 Operator 来解决。
### 3\. CRD+Operator: K8s 扩展能力强大却难以上手
确实,我们内部对接复杂应用云原生化的时候,也推荐他们编写 Operator,但是经常出现这样一段对话。
![lALPDgQ9rYRXqtXNAl7NBDg_1080_606_png_620x10000q90g](https://yqfile.alicdn.com/d66e18096caed28ddc7239560b0efda1b6a8f726.jpeg)
中间件的工程师跟我们说,我这有个 Zookeeper 该用哪种 K8s 的 Workload 接入啊?我们想了想,K8s 设计如此精妙,自然没有解决不了的问题,于是我们推荐他们使用 Operator。他们就懵了,说你们搞云原生的这几年造新词的能力绝对一流,之前都没听说过。
想想也是,业务方理解这些新概念不难,但是真的要自己去上手实现,还是非常困难的。我们自然也觉得业务方更应该专注于他们的业务本身,于是我们不得不帮他们一起写。
可以看到,我们亟需一个统一的模型去解决研发对应用管理的诉求。
运维对应用管理的诉求
----------
除了研发侧的问题之外,我们在运维侧也遇到了很大的挑战。
### 1\. 运维能力众多却难以管理
K8s 的 CRD Operator 机制非常灵活而强大,不光是复杂应用可以通过编写 CRD Operator 实现,我们的运维能力也大量通过 Operator 来扩展,比如灰度发布、流量管理、弹性扩缩容等等。
我们常常赞叹于 K8s 的灵活性,它让我们基础平台团队对外提供能力非常方便,但是对应用运维来说,他们要使用我们提供的这些运维能力,却变得有些困难。
比如我们上线了一个 CronHPA,可以定时设置在每个阶段会根据 CPU 调整实例数的范围。应用运维并不知道跟原生不带定时功能的 HPA 会产生冲突,而我们也没有一个统一的渠道帮助管理这么多种复杂的扩展能力,结果自然是引起了故障。这血的教训提醒我们要做事前检查,熟悉 K8s 的机制很容易让我们想到为每个 Operator 加上 admission webhook。
这个 admission webhook 需要拿到这个应用绑定的所有运维能力以及应用本身的运行模式,然后做统一的校验。如果这些运维能力都是一方提供的还好,如果存在两方,甚至三方提供的扩展能力,我们就没有一个统一的方式去获知了。
事实上如果我们想的更远一些就会发现,我们需要一个统一的模型来协商并管理这些复杂的扩展能力。
### 2\. 云资源难以描述和统一交付
当我们把应用的 Operator 以及对应的运维能力都写好以后,我们很容易想到要打包交付这个应用,这样无论是公有云还是专有云都可以通过一个统一的方式去交互。社区的主流方式目前就是使用 Helm 来打包应用,而我们也采用了这样的方式给我们的用户交付,但是却发现我们的用户需求远不止于此。
云原生应用有一个很大的特点,那就是它往往会依赖云上的资源,包括数据库、网络、负载均衡、缓存等一系列资源。
![lALPDgQ9rYRXqtfNAgXNBDg_1080_517_png_620x10000q90g](https://yqfile.alicdn.com/aa119c53b5830d36338eb4113aacd84a1de59ea6.jpeg)
当我们使用 Helm 打包时,我们只能针对 K8s 原生 API,而如果我们还想启动 RDS 数据库,就比较困难了。如果不想去数据库的交互页面,想通过 K8s 的 API 来管理,那就又不得不去写一个 CRD 来定义了,然后通过 Operator 去调用实际云资源的 API。
这一整套交付物实际上就是一个应用的完整描述,即我们所说的“应用定义”。但事实上,我们发现“应用定义”这个东西,在整个云原生社区里其实是缺失的。这也是为什么阿里巴巴内部有很多团队开始尝试设计了自己的“应用定义”。
![lALPDgQ9rYRXqtjNAozNBDg_1080_652_png_620x10000q90g](https://yqfile.alicdn.com/33ce1294cc7d94defb30b0cf247a0640a08699a7.jpeg)
这种定义方式最终所有的配置还是会全部堆叠到一个文件里,这跟 K8s API all-in-one 的问题其实是一样的,甚至还更严重了。而且,这些应用定义最终也都成为了黑盒,除了对应项目本身可以使用,其他系统基本无法复用,自然就更无法使得多方协作复用了。
### 3\. 每个公司和团队都在自己定义应用
不光是阿里巴巴内部的团队需要应用定义,事实上几乎每个基于 K8s 管理应用的公司和团队都在自己定义应用。如下所示,我就搜到了两家公司的应用定义:
![lALPDgQ9rYRXqtnNAtzNAug_744_732_png_620x10000q90g](https://yqfile.alicdn.com/1d767e6060739fa788250dd54f0a9c65321874e8.jpeg)
![lADPDgQ9rYRXqt3NARDNAyw_812_272_jpg_620x10000q90g](https://yqfile.alicdn.com/8a90f2891521149ddf553bb242057f32d5e7c369.jpeg)
应用定义实际上是应用交付/分发不可或缺的部分。但是在具体的实践中,我们感受到这些内部的应用定义都面临着如下的问题:
* 定义是否足够开放,是否可以复用?
* 如何与开源生态协作?
* 如何迭代与演进?
这三个问题带来的挑战都是巨大的,我在上文已经提到,一个应用定义需要容易上手,但又不失灵活性,更不能是一个黑盒。应用定义同样需要跟开源生态紧密结合,没有生态的应用定义注定是没有未来的,自然也很难持续的迭代和演进。
区分使用者的分层模型与模块化的封装
-----------------
让我们回过头来重新审视我们面临的挑战,归根结底在于 K8s 的 All in One API 是为平台提供者设计的,我们不能像下图左侧显示的一样,让应用的研发、运维跟 K8s 团队一样面对这一团 API。
![lALPDgQ9rYRXqt7NAYjNBDg_1080_392_png_620x10000q90g](https://yqfile.alicdn.com/a5044b5b40d580feb972092b734fe09876a62138.jpeg)
一个合理的应用模型应该具有区分使用者角色的分层结构,同时将运维能力模块化的封装。让不同的角色使用不同的 API,正如上图右侧部分。
OAM:以应用为中心的 K8s API 分层模型
------------------------
OAM(Open Application Model) 正是这样一个以应用为中心的 K8s API 分层模型:
* 从研发的角度,他操作和关注的 API 对象叫 Component;
* 从运维的角度,模块化的运维能力封装就是 Trait,而运维可以通过 App Config 将 Component 和 Trait 自由组合,最终实例化成一个运行的应用;
* K8s 团队本身则仍然基于 K8s 的原生 API 迭代这一层能力。
![lALPDgQ9rYRXqt_NAabNBDg_1080_422_png_620x10000q90g](https://yqfile.alicdn.com/01300a8e8884e58f64011af2c255c958de13fb4b.jpeg)
针对研发时常抱怨的 K8s API 太复杂,我们通过关注点分离,区分使用者面对的 API 来解决,同时提供了几种核心的 Workload,让研发只需要填写少数几个字段就可以完成组件的定义;针对复杂应用定义,我们通过扩展的 Workload,允许研发对接 CRD Operator 的方式对接自定义 Workload。
针对运维需要的模块化封装运维能力和全局管理的需求,OAM 模型通过 Trait 来提供。
Trait 是运维能力的体现,不同的 Trait 也对应了不同类型的运维能力,如日志收集 Trait、负载均衡 Trait、水平扩缩容 Trait 等等;同时 OAM 本身就提供了一个全局管理的标准,OAM 模型的实现层可以轻松针对 OAM 定义里的种种 Trait 描述进行管理和检查。
针对云资源,OAM 向上也提供了统一的 API,也是通过关注点分为三类:
一类是研发关注的云资源,如数据库 RDS、对象存储 OSS 等,通过扩展 Workload 接入;
另一类是运维关注的云资源,如负载均衡 SLB 等,通过 Trait 接入;
最后一类也是运维关注的云资源,但是可能包含多个应用之间的联动关系,如虚拟专有网络 VPC 等,通过应用的 Scope 接入。Scope 则是 OAM 中管理多应用联动关系的概念。
可以看到,OAM 通过统一的一套标准,解决了我们今天提到的所有难题。让我们继续深入到 OAM 中看看不同的概念具体是什么。
**1\. OAM Component:研发关注的 API**
Component 就是 OAM 模型提供给研发的 API 对象,如下所示:
```
apiVersion: core.oam.dev/v1alpha1
kind: Component
metadata:
name: nginx
annotations:
version: v1.0.0
description: >
Sample component schematic that describes the administrative interface for our nginx deployment.
spec:
workloadType: Server
osType: linux
containers:
- name: nginx
image:
name: nginx:1.7.9
digest: <sha256:...>
env:
- name: initReplicas
value: 3
- name: worker_connections
fromParam: connections
workloadSettings:
...
parameters:
- name: connections
description: "The setting for worker connections"
type: number
default: 1024
required: false
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
可以看到 Component 本身就是一个 K8s 的CRD,spec 字段里面的部分就是 Component 具体的定义。其中第一个重要的字段就是 workloadType,这个决定了应用的运行模式。
针对简单应用,OAM 提供了 6 种核心 Workload,如下表所示:
![lADPDgQ9rYRXquvNATbNAzg_824_310_jpg_620x10000q90g](https://yqfile.alicdn.com/318500fbbeec88ab3a6c24754a21d6fa3f10ff4d.jpeg)
主要通过是否可访问、是否可复制、是否长久运行来区分。如 Server,就代表了大家最常用的 K8s 里面 Deployment+Service 的组合。
填写了核心 workloadType 的 Component,只需要定义 Container 里的注入镜像、启动参数等字段,就如我们最开始所说的屏蔽掉大量字段的 PaaS 一样,为用户大大降低了门槛。
而针对复杂的有状态应用,OAM 则允许通过扩展 Workload 来实现,如下图所示,我们可以定义一个新的叫 openfaas 的 WorkloadType,它的定义实际上完全等价于一个 CRD 定义。
![lALPDgQ9rYRXquzNAm_NBDg_1080_623_png_620x10000q90g](https://yqfile.alicdn.com/256938fdbd472c10d6bcf869153362681a471b1f.jpeg)
OAM 模型中,使用自定义的 Workload 也是通过 Component,只是 WorkloadType 改为你自定义的 WorkloadType 名称。
**2\. OAM Trait:可发现、可管理的运维能力**
Trait 就是模块化的运维能力,我们能通过命令行工具发现一个系统里支持哪些 Traits(运维能力)。
```
$ kubectl get traits
NAME AGE
autoscaler 19m
ingress 19m
manual-scaler 19m
volume-mounter 19m
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
这时候,运维要查看具体的运维能力该怎么使用,是非常简单的:
```
$ kubectl get trait ingress -o yaml
apiVersion: core.oam.dev/v1alpha1
kind: Trait
metadata:
name: cron-scaler
annotations:
version: v1.0.0
description: "Allow cron scale a workloads that allow multiple replicas."
spec:
appliesTo:
- core.oam.dev/v1alpha1.Server
properties: |
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"schedule"
],
"properties": {
"schedule": {
"type": "array",
"description": "CRON expression for a scaler",
"item": {
"type": "string"
}
},
"timezone": {
"type": "string",
"description": "Time zone for this cron scaler."
},
"resource":{
"type": "object"
"description": "Resources the cron scaler will follow",
"properties": {
"cpu": {
type: "object"
...
}
}
}
}
}
```
![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)![](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== "点击并拖拽以移动")
可以看到,他可以在 Trait 定义里清晰的看到这个运维能力可以作用于哪种类型的 Workload,包括能填哪些参数、哪些必填/选填、参数的作用描述是什么。你也可以发现,OAM 体系里面,Component 和 Trait 这些 API 都是 Schema,所以它们是整个对象的字段全集,也是了解这个对象描述的能力“到底能干吗?”的最佳途径。
事实上,大家可能已经发现,Trait 的定义和 CRD 是对等的,而你完全也可以通过 Operator 实现 Trait。
![lALPDgQ9rYRXqu7NAnjNBDg_1080_632_png_620x10000q90g](https://yqfile.alicdn.com/52a9d7efeac5eac17fb600ae1a0edbb3f104e64d.jpeg)
所以 OAM 事实上将原本散乱的 Operator 通过不同的角色有机的管理起来了。
**3\. OAM Application Config:组装 Component 和 Trait,应用实例化运行**
Component 和 Trait 最终通过 Application Configuration 结合,并真实运行起来。
![lALPDgQ9rYRXqu_NAe3NBDg_1080_493_png_620x10000q90g](https://yqfile.alicdn.com/bfa0714b2386eaa4a330779f555f65492dc3c92d.jpeg)
更重要的是,这个 OAM 应用描述文件是完全自包含的,也就是说通过 OAM YAML,作为软件分发商,我们就可以完整地跟踪到一个软件运行需要的所有资源和依赖。这就使得现在对于一个应用,大家只需要一份 OAM 的配置文件,就可以快速、在不同运行环境上把应用随时运行起来,把这种自包含的应用描述文件完整地交付到任何一个运行环境中。
而我们图中的 Rudr 项目就是 OAM 的一个实现,也可以理解为 OAM 的一个解释器,将 OAM 的统一描述转换为背后众多的 Operator。
同时 Rudr 也是一个统一管理的媒介,如果 Application Configuration 中出现了一个 Component 绑定 2 个 Trait 并且互相冲突的情况,就可以快速被检验并发现问题,如下图所示:
![lALPDgQ9rYRXqvHNAvLNAnw_636_754_png_620x10000q90g](https://yqfile.alicdn.com/b2f84fc5da8273bdde23a8a78693f148032b933e.jpeg)
同样,包括复杂应用的编排、云资源的拉起、Workload 与 Trait 交互等等,都可以在这个 OAM 解释器中实现。
大家可以通过 Rudr 项目中的教程文档体验 OAM 的这些交互过程。
OAM 加持下的 Kubernetes PaaS
------------------------
事实上,OAM 加持下的 PaaS 基于 Kubernetes,将众多 Operator 分层的管理了起来。
![lALPDgQ9rYRXqvLNAebNBDg_1080_486_png_620x10000q90g](https://yqfile.alicdn.com/1639b5865d13dcb8c5aa1303ff0ecb41e8b61674.jpeg)
对于研发,通常他关心的应用可能是一个由 web 和数据库组合而成的应用,数据库组件的背后可能是一个 RDS Operator 实现。web 应用背后,则可以是我们开源的 K8s 原生 StatefulSet的增强项目 OpenKruise,OpenKruise 中提供的包括原地升级等增强能力则通过 Trait 的方式去配置。而额外的一些监控报警、日志等能力,则由一个个独立的 Operator 去实现,由运维在第二层去关注和管理。
最终 K8s 团队联合各种基础软件的提供商,围绕 K8s 原生 API,以 Operator 的形式不断提供扩展能力,通过 OAM 这样统一的规范和标准向外标准化输出。
更重要的是,OAM 的统一描述大大提高了 Operator 的复用能力,使得 Operator 的编写主需要关注业务逻辑本身。比如原先你写一个 Zookeeper Operator,你需要写实例的服务发现、需要写升级时主备切换的编排逻辑、需要写实例备份的逻辑,而这一切在 OAM 的标准化下,你将可以轻松在社区找到类似组成部分。
OAM 加持下的 Kubernetes PaaS,使得不同的 Operator 可以像乐高积木一样灵活组装,使得应用定义成为了社区共同建设的项目,使得应用管理变得统一,功能却更加强大!
[原文链接](https://link.zhihu.com/?target=https%3A//yq.aliyun.com/articles/739645%3Futm_content%3Dg_1000094672)
本文为阿里云内容,未经允许不得转载。
相关推荐
崔力强,阿里巴巴研发效能部技术专家。 嘉宾简介: DevOps资深专家,译有《微服务设计》。曾在ThoughtWorks任职软件交付和敏捷顾问;对持续集成、自动化测试有丰富经验;目前专注于持续交付SaaS产品的开发,提供精益...
在这个阶段,阿里巴巴基于LXC自研了T4容器,并构建了一套集团管理系统来管理这些容器。这标志着阿里巴巴容器化的开端。 **2. 野蛮生长期 (2015年):** 随着对容器技术的认识加深和技术积累,阿里巴巴内部涌现出多个...
本文档概述了阿里云基于神龙裸金属服务器的Kubernetes集群运维实践,涵盖了从阿里云上云到神龙X-Dragon的诞生、神龙的优势、规模化集群运维实践、未来工作云原生全景图等方面。 1. 阿里云上云 阿里云于2018年底...
4. **云计算技术**:阿里巴巴基于自身强大的阿里云平台,实现了基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS),有效地支撑了中文站的运行。 5. **容器化与Docker**:为了实现快速部署和资源优化...
KubeNode:阿里巴巴云原生容器基础设施运维实践 OpenKruise:云原生应用全生命周期自动化的实战 OpenYurt:让云原生和边缘计算无缝融合的奥秘 三、KubeCon 议题 containerd 的现状 面向 SLO 的资源估计调度以优化...
这本书基于阿里巴巴的实际业务场景,结合丰富的实践经验,为Java开发者提供了深入、实用的性能调优指南。 在Java性能调优领域,有以下几个核心知识点: 1. **JVM调优**:Java虚拟机(JVM)是Java程序运行的基础,...
《阿里巴巴新一代基于 Go 的云原生应用引擎实践》 在当今的互联网时代,云原生技术已经成为企业数字化转型的关键驱动力。云原生应用引擎,尤其是基于 Go 语言的实现,因其高性能、轻量级和易扩展性,成为了构建现代...
阿里巴巴 K8s 超大规模实践经验 阿里巴巴 Kubernetes 应用管理实践中的经验与教训 阿里巴巴超大规模神龙裸金属 Kubernetes 集群运维实践 阿里巴巴核心应用落地 Service Mesh 的挑战与机遇 阿里巴巴云原生开源探索与...
2020阿里巴巴研发效能峰会将以“JUST LEAN ”为主题,描绘在新技术、新商业环境下,如何在产品创新、架构与代码智能、持续交付与质量、运维稳定性等领域提升工程效能,提升组织效能。 2020阿里巴巴研发效能峰会PPT...
《阿里巴巴 DevOps 实践...《阿里巴巴 DevOps 实践手册》结合了阿里巴巴集团丰富的实践经验,为读者提供了全面而实用的 DevOps 解决方案,无论你是初学者还是经验丰富的从业者,都能从中受益,提升团队的 DevOps 能力。
阿里巴巴作为中国最大的电商企业,也积极探索微服务化架构的应用,并在其业务中获得了实践经验。 从架构演进的角度来看,阿里巴巴的微服务化架构可以分为三个阶段: 第一阶段:传统 monolithic 架构。在这个阶段,...
- **张瑜标(花名: 龙轼)**:现任阿里巴巴技术专家,曾任京东Hadoop负责人,同时也是Hadoop代码贡献者。目前主要负责UC基于Kubernetes自研的PaaS平台的整体稳定性工作,特别关注Service Discovery和Observability等...
《不一样的双11技术:阿里巴巴经济体云原生实践》这份行业报告深入剖析了阿里巴巴在双十一购物狂欢节背后所采用的创新技术与云原生实践。作为全球最大的在线交易活动,双十一对技术的要求达到了前所未有的高度,阿里...
阿里巴巴可能采用如Kubernetes这样的容器编排技术,实现计算和存储资源的灵活调度。 4. **数据湖建设**:阿里巴巴可能构建了数据湖来统一管理和存储不同来源、格式的数据,提供统一的数据访问接口,便于后续分析和...
这个“思若仿阿里巴巴B2B大型商务网站系统 v1.0”项目,涉及到的领域广泛,涵盖了Web开发的各个环节,对于学习和实践电子商务平台的开发具有很高的参考价值。它不仅要求开发者具备扎实的技术基础,还需要对业务流程...
这一实践不仅推动了阿里巴巴内部技术的发展,也为整个行业提供了宝贵的经验和参考案例。随着SofaMesh项目的持续推进和完善,相信未来还将有更多的创新成果涌现,为Service Mesh领域的发展贡献更大的力量。
阿里巴巴云ACK(Alibaba Cloud Container Service for Kubernetes)是基于PouchContainer技术构建的企业级Kubernetes服务,它为企业提供了便捷、高效且安全的容器托管环境,支持大规模容器应用的部署和管理。...
【K8s超大规模技术实践】的讲解涵盖了阿里巴巴在容器技术领域的探索和发展,以及如何基于Kubernetes实现云原生的改造。以下是对这些内容的详细阐述: 阿里巴巴在2013年开始初步尝试使用容器技术,以替代传统的...