没有银弹,但有时会有很好用的弓箭。
—— 改自于著作《没有银弹》[1]
很多企业开始落地 Kubernetes,很多业务工程师也开始“被迫”学习各种“抽象”的概念(如 Pod、YAML 文件、声明式 API、Operator)。落地前充满期待,结果却往往适得其反。
导致上面问题的根源在于,Kubernetes 的定位是基础设施项目、是“平台的平台”(The Platform for Platform)。它的声明式 API 设计、CRD Operator 体系,是为了接入和构建新基础设施能力而设计的。这就导致作为这些能力的最终用户 —— 业务工程师,跟 Kubernetes 核心定位之间存在明显的错位。
大家抱怨 Kubernetes 过于复杂,但“复杂”是任何基础设施项目的天生特质,而非缺点。不过,基础设施“复杂”不意味着应该由使用者承受。这就好比,Linux 内核是世界上最复杂的软件之一,但我们使用 Linux 系统却没有太多心智负担,这是因为 Linux 系统通过高度抽象屏蔽了底层的复杂性。既然 Kubernetes 被称为“云原生时代的操作系统”,现在也该考虑学习 Linux 抽象方式,寻找一种应用层的软件交付模型和抽象,以更友好的方式服务最终用户了。
本章内容安排如图 10-0 所示。

“以应用为中心”的设计思想
回顾过去十几年间的技术演进历程,精彩纷呈!
从单体系统到分布式系统,系统能力大幅提升,但也引入了更多的不确定性。比如节点可能随时宕机、网络有不等的延迟、消息可能丢失。为了解决这些不确定性,业界提出了诸多的分布式理论和协议,如 CAP 定理、BASE 理论以及共识算法(Paxos、Raft 等),以保障系统稳定运行。
进入微服务时代,这些理论推动基础设施能力演进,这些能力(服务发现、负载均衡、故障转移、动态扩容)从业务逻辑中抽象出来,以 SDK(中间件)形式提供给应用开发者。中间件的出现其实体现了一种朴素的“关注点分离”的思想,使得你可以在不需要深入了解具体基础设施能力细节的前提下,以最小的代价学习和使用这些基础设施能力!
不过,基础设施能力的演进,也伴随着云计算和开源社区的发展,带来了全新的升级。这个变化,正是从云原生技术改变中间件格局开始。更确切地说,原先通过中间件提供和封装的能力,现在全部被 kubernetes 从应用层拽到基础设施层。比如,Kubernetes 最早提供的应用副本管理、服务发现和分布式协同能力,其实把构建分布式应用最迫切的需求,利用 Replication Controller、kube-proxy 和 etcd “下沉”到基础设施中,也就是 kubernetes 中。
值得注意的是,kubernetes 不直接提供这些能力,它的角色定位是通过声明式 API 和控制器模式对用户暴露更底层基础设施的能力。从这个角度来看,Kubernetes 设计的重点在于“如何标准化地接入底层资源,无论是容器、虚拟机、负载均衡等,并通过声明式 API 将这些能力暴露给用户”。所以说,Kubernetes 的核心价值不在于容器编排或资源调度,而在于声明式 API。声明式 API 的最大优势是将“简单的交给用户,将复杂的留给系统”。通过声明式 API,Kubernetes 用户只需关心应用的最终状态,无需关注底层基础设施的配置和实现细节。
这种设计理念,以一言蔽之,就是以应用中心。正是因为以应用为中心,整个云原生技术体系无限强调基础设施更好地服务于应用,以更高效的方式为应用提供基础设施能力,而不是反其道行之。而相应的,Kubernetes 也好、Docker 也好、Istio 也好,这些在云原生生态中起到了关键作用的开源项目,就是让这种思想落地的技术手段。
声明式管理的本质
Kubernetes 与其他基础设施的最大不同是,它是基于声明式管理的系统。很多人容易将“声明式风格的 API”和“声明式管理”混为一谈,这实际上是对声明式管理缺乏正确认识。想要真正理解声明式管理,首先需要弄清楚 Kubernetes 的控制器模式。
控制器模式
分析 Kubernetes 的工作原理可以发现,无论是 kube-scheduler 调度 Pod,还是 Deployment 管理 Pod 部署,亦或是 HPA 执行弹性伸缩,它们的整体设计都遵循“控制器模式”。
例如,用户定义一个 Deployment 资源,指定运行的容器镜像和副本数量。Deployment 控制器根据这些定义,在 Kubernetes 节点上创建相应的 Pod,并持续监控它们的运行状态。如果某个副本 Pod 异常退出,控制器会自动创建新的 Pod,确保系统的“实际状态”始终与用户定义的“预期状态”(如 8 个副本)保持一致。

总结控制器模式的核心是,用户通过 YAML 文件定义资源的“预期状态”,然后“控制器”监视资源的实际状态。当实际状态与预期状态不一致时,控制器会执行相应操作,确保两者一致。在 Kubernetes 中,这个过程被称为“调谐”(Reconcile),即不断执行“检查 -> 差异分析 -> 执行”的循环。
调谐过程的存在,确保了系统状态始终向预期终态收敛。这个逻辑很容易理解:系统在第一次提交描述时达到了期望状态,但这并不意味着一个小时后的情况也是如此。
所以说,声明式管理的核心在于“调谐”,而声明式风格的 API 仅仅是一种对外的交互方式。
基础设施即数据思想
“控制器模式”体系的理论基础,是一种叫做 IaD(Infrastructure as Data,基础设施即数据)的思想。
IaD 思想主张,基础设施的管理应该脱离特定的编程语言或配置方式,而采用纯粹、格式化、系统可读的数据,描述用户期望的系统状态。这种思想的优势在于,对基础设施的所有操作本质上等同于对数据的“增、删、改、查”。更重要的是,这些操作的实现方式与基础设施本身无关,不依赖于特定编程语言、协议或 SDK,只要生成符合格式要求的“数据”,便可以“随心所欲”地采用任何你偏好的方式管理基础设施。
IaD 思想在 Kubernetes 上的体现,就是执行任何操作,只需要提交一个 YAML 文件,然后对 YAML 文件增、删、查、改即可,而不是必须使用 Kubernetes SDK 或者 Restful API。这个 YAML 文件其实就对应了 IaD 中的 Data。从这个角度来看,Kubernetes 暴露出来的各种 API 对象,本质是一张张预先定义好 Schema 的“表”(table)(见表 10-1 )。唯一跟传统数据库不太一样的是,Kubernetes 并不以持久化这些数据为目标,而是监控数据变化驱动“控制器”执行相应操作。
表 Kubernetes 是个“数据库”
关系型数据库 | Kubernetes (as a database) | 说明 |
---|---|---|
DATABASE | cluster | 一套 K8s 集群就是一个 database |
TABLE | Kind | 每种资源类型对应一个表 |
COLUMN | property | 表里面的列,有 string、boolean 等多种类型 |
rows | resources | 表中的一个具体记录 |
本质上,Kubernetes v1.7 版本引入的 CRD(自定义资源定义)功能,其实是赋予用户管理自定义“数据”、将特定业务需求抽象为 Kubernetes 原生对象的能力。
例如,可以通过 CRD 定义持续交付领域中的 Task(任务)和 Pipeline(流水线)。这意味着,用户完全可以在 Kubernetes 的基础上,利用其内置能力扩展出一套全新的 CI/CD 系统。
apiVersion: tekton.dev/v1beta1 kind: Task metadata: name: example-task spec: steps: - name: echo-hello image: alpine:3.14 script: | #!/bin/sh echo "Hello, Tekton!"
借助 CRD,工程师可以突破 Kubernetes 内置资源的限制,根据需求创建自定义资源类型,如数据库、CI/CD 流程、消息队列或数字证书等。配合自定义控制器,特定的业务逻辑和基础设施能力可以无缝集成到 Kubernetes 中。
最终,云原生生态圈那些让人兴奋的技术,通过插件、接口、容器设计模式、Mesh 形式,以“声明式管理”为基础下沉至 Kubernetes 中,并通过声明式 API 暴露出来。虽然 Kubernetes 的复杂度不断增加,但声明式 API 的优势在于,它能确保在基础设施复杂度指数级增长的同时,用户交互界面的复杂度仅以线性方式增长。否则的话,Kubernetes 早就变成一个既难学又难用的系统了。
从“封装配置”到“应用模型”
在 Kubernetes 时代,“软件”不再是一个由应用开发者掌控的单一交付物,而是多个 Kubernetes 对象的集合。使用 Kubernetes 原生对象构建一套微服务应用,是一件高度碎片化且充满挑战的事情。
举个例子,如果你要在 Kubernetes 中部署一套微服务系统,那你需要为每个子服务配置 Service(提供服务发现和负载均衡)、Deployment(管理无状态服务)、HPA(自动扩缩容)、StatefulSet(管理有状态服务)、PersistentVolume(持久化存储)、NetworkPolicy(网络访问控制规则)等等。上述工作“繁琐”还在其次,关键难点是写出合适 YAML 元数据描述,这要求操作人员既要懂研发(理解服务运行、镜像版本、依赖关系等需求),又要懂运维(理解扩缩容、负载均衡、安全、监控等策略),还要懂平台(网络、存储、计算),一般的开发人员根本无从下手。
上述问题的根源在于,Docker 容器镜像封装了单一服务,Kubernetes 则通过资源封装了服务集群,却没有一个载体真正封装整个应用。封装应用的难点是:要屏蔽底层基础设施的复杂性,不要暴露给最终用户;同时,还要将开发、运维、平台等各种角色的关注点恰当地分离,使得不同角色可以更聚焦更专业的做好本角色的工作。
目前,业内对于如何封装应用还没有最终的结论,但经过不断探索,也出现了几种主流的应用封装与交付方案。接下来,笔者将介绍它们供你参考。
Kustomize
Kubernetes 官方对应用的定义是一组具有相同目标资源合集。这种设定下,只要应用规模稍大,尤其是不同环境(如开发和生产环境)之间的差异较小时,资源配置文件就开始泛滥。尤其是当不同环境(如开发和生产环境)之间的差异较小时,你就会发现通过 kubectl 管理应用十分“蛋疼”。
Kubernetes 对此的观点是,如果逐一配置和部署资源文件过于繁琐,那就将应用中的稳定信息与可变信息分离,并自动生成一个多合一(All-in-One)的配置包。完成这一任务的工具名为 Kustomize。
Kustomize 可以看作是 YAML 模板引擎的变体,由它组织的应用结构有两个部分:base 和 overlays。base 目录存放原始的 Kubernetes YAML 模板文件,overlays 目录用于管理不同环境的差异。每个目录下都有一个 kustomization.yaml 配置文件,描述如何组合和修改 Kubernetes 资源。
├── base/ │ ├── deployment.yaml │ ├── service.yaml │ └── kustomization.yaml ├── overlays/ │ ├── dev/ │ │ ├── kustomization.yaml │ │ └── patch-deployment.yaml │ ├── staging/ │ │ ├── kustomization.yaml │ │ └── patch-deployment.yaml │ └── prod/ │ ├── kustomization.yaml │ └── patch-deployment.yaml
只要为每个环境创建对应的 kustomization.yaml 文件,使用 kubectl kustomize 命令,可以将多个资源文件(如 Deployments、Services、ConfigMaps)合并为一个最终的 YAML 配置包。这样,使用 kubectl apply -k 命令,就能一次性部署所有相关资源。
// 合并后的配置文件 all-in-one.yaml --- apiVersion: v1 kind: Namespace metadata: name: my-namespace --- apiVersion: v1 kind: ConfigMap metadata: name: my-app-config namespace: my-namespace data: config.yaml: | ... --- apiVersion: v1 kind: Secret metadata: name: my-app-secret namespace: my-namespace data: ... --- apiVersion: apps/v1 kind: Deployment metadata: name: my-app namespace: my-namespace spec: replicas: 3 template: spec: containers: - name: my-app-container image: my-app-image:v1.2.3 ... --- apiVersion: v1 kind: Service metadata: name: my-app-service namespace: my-namespace spec: ports: - ... selector: ... --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app-ingress namespace: my-namespace spec: rules: - host: my-app.example.com ...
不难看出,kustomize 使用 Base、Overlay 生成最终配置文件的思路跟 Docker 分层镜像的思路非常相似,只要建立多个 Kustomization 文件,开发人员就能基于基准进行派生(Base and Overlay),对不同的模式(比如生产模式、调试模式)、不同的项目(同一个产品对不同客户的客制化)定制出一个多合一配置包。
不过呢,回头看 Kustomize 只能算作一个辅助应用部署的“小工具”,配置包里面的资源一个也没有少写,只是减少了不同场景下的重复配置。对于一个应用而言,其管理需求远不止部署阶段,还涉及更新、回滚、卸载、多版本管理、多实例支持以及依赖关系维护等操作。要解决这些问题,还需要更高级的“工具”,这就是接下来要介绍的 Helm。
Helm 与 Chart
相信读者朋友们知道 Linux 的包管理工具和封装格式,如 Debian 系的 apt-get 和 dpkg,RHEL 系的 yum 和 rpm。在 Linux 系统中,有了包管理工具,我们只要知道应用名称,就能从仓库中下载、安装、升级或回滚。而且,包管理工具掌握应用的依赖和版本信息,应用依赖的第三方库,在安装时都会一并处理好。
2015 年,Deis(后被 Microsoft 收购)创建了 Helm,它借鉴了各大 Linux 发行版的应用管理方式,引入了与 Linux 包管理对应的 Chart 格式和 Repository 仓库概念。对于用户而言,使用 Helm 无需手动编写部署文件、无需了解 Kubernetes 的 YAML 语法,只需一行命令,即可在 Kubernetes 集群内安装所需应用。

Chart 是一个包含描述 Kubernetes 相关资源的文件集合。以官方仓库中 WordPress 应用为例,它的 Chart 目录结构是这样的。
WordPress |—— charts // 存放依赖的chart ├── templates // 存放应用一系列 Kubernetes 资源的 YAML 模板,通过渲染变量得到部署文件 │ ├── NOTES.txt // 为用户提供一个关于 chart 部署后使用说明的文件 | |—— _helpers.tpl // 存放能够复用的模板 │ ├── deployment.yaml │ ├── externaldb-secrets.yaml │ └── ingress.yaml │ └── .... └── Chart.yaml // chart 的基本信息(名称、版本、许可证、自述、说明、图标,等等) └── requirements.yaml // 应用的依赖关系,依赖项指向的是另一个应用的坐标(名称、版本、Repository 地址) └── values.yaml // 存放全局变量,templates 目录中模板文件中用到变量的值
以模版目录中的 deployment.yaml 为例,它的内容如下。
apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-nginx spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: nginx image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: 80
部署应用时,Helm 会先将管理员指定的值覆盖 values.yaml 中的默认值,然后通过字符串替换将这些值传递给 templates 目录中的资源模板,最终渲染为 Kubernetes 资源文件,在 Kubernetes 集群中以 Release 的形式管理。
Release 是 Helm Chart 的运行实例,它将多个 Kubernetes 资源抽象为一个整体,用户无需单独操作每个资源,而是通过 Helm 提供的命令(如 helm install、helm upgrade、helm rollback 等)进行统一管理。
Helm 提供了应用生命周期、版本、依赖项的管理能力,还支持与 CI/CD 流程的集成,强大的功能使它在业内备受瞩目,业内流行的应用纷纷提供 Helm Chart 格式的版本。2020 年,CNCF 牵头开发了 Artifact Hub,该项目已经成为全球规模最大的 Helm 仓库,用户可以在这里找到数以千计的 Helm Charts,一键部署各种应用(如数据库、消息队列、监控工具、CI/CD 系统、日志处理工具)。
不过,需要明确的是,Helm 本质是简化 Kubernetes 应用安装与配置的工具。对于“有状态应用”(Stateful Application)来说,Helm 无法进行精细的生命周期管理。例如,它无法处理数据备份、扩缩容、分区重平衡、动态扩展等操作,这些都是在管理复杂有状态应用时所必须考虑的细节!
如何对复杂有状态应用提供全生命周期的管理,是接下将要介绍的 Operator 的课题。
Operator
Operator 的概念由 CoreOS 于 2016 年提出,它并非具体的工具或系统,而是一种在 Kubernetes 中封装、部署和管理应用的方法,尤其适合管理需要特定领域知识的“有状态应用”(Stateful Application)。
要理解 Operator 所做的事情,先要理解有状态应用和无状态应用的区别。
无状态应用(Stateless Application)是指应用在运行过程中不依赖于任何持久化数据或内部状态,每次请求的处理都是独立的,不会受到之前请求的影响,其多个实例是对等关系。常见的无状态应用有 Web 服务反向代理与负载均衡服务、微服务架构中的服务等;而有状态应用(Stateful Application)则需要持久化数据,这些数据在应用重启或迁移后依然保持。对于有状态应用,其多个实例之间通常存在不对等关系,如主备或主从架构。常见的有状态应用有数据库(MySQL、PostgreSQL、etcd)、缓存系统(Redis、Memcached)、消息队列(Kafka、RabbitMQ)等。
有状态应用和无状态应用的区别
无状态应用像家畜,按规模化方式管理,个体之间无实质差异,出现问题时可直接用其他个体替代。有状态应用则像宠物,每个个体都有特定角色和作用,彼此不可替代,还需精心照料。
Kubernetes 使用 Deployment 编排无状态应用,假设所有 Pod 完全相同,没有顺序依赖,也无需关心运行在哪台宿主机上。相反的,有状态应用每个实例都需要维护特定的状态:
- 拓扑状态:应用的多个实例之间并非完全对等关系。例如,在“主从”(Master-Slave)架构中,主节点 A 必须先于从节点 B 启动。此外,若 Pod 被删除重新,必须保留与原 Pod 相同的网络标识,以确保访问者能够通过原有的访问方式连接到新的 Pod。
- 存储状态:应用的多个实例分别绑定了独立的存储数据。对于实例 Pod 而言,无论是首次读取还是在被重新创建后再次读取,获取的数据都必须一致。典型的例子是一个数据库应用的多个存储实例,每个实例需要持久化数据到本地存储,如果实例迁移到了其他节点,服务就无法正常使用。
Kubernetes v1.9 版本引入 StatefulSet 的核心功能就是用某种方式记录这些状态,当有状态应用的 Pod 重建后,仍然满足上一次运行状态的需求。不过有状态应用的维护并不限于此:
- 以 StatefulSet 创建的 Etcd 集群为例,最多只能实现创建、删除集群等基本操作。对于集群扩容、健康检查、备份恢复等等高级运维操作,也需要配套支持。
- 其次,使用 StatefulSet 创建 etcd 集群,还必须配置大量的细节,明确网络标识符、存储配置、集群成员管理、健康检查方式,告诉 Kuberntes 如何处理 Etcd。举一个具体的例子,供你体会在“在 YAML 文件里编程序”的感觉,请看下面配置 etcd 的 YAML 文件:
apiVersion: v1 kind: Service metadata: name: etcd-headless labels: app: etcd spec: clusterIP: None # 必须为 None,启用 headless 服务 selector: app: etcd ports: - port: 2379 # Etcd 客户端端口 name: client - port: 2380 # Etcd 集群通信端口 name: peer --- apiVersion: apps/v1 kind: StatefulSet metadata: name: etcd spec: serviceName: "etcd-headless" replicas: 3 # 设置 Etcd 集群节点的副本数 selector: matchLabels: app: etcd template: metadata: labels: app: etcd spec: containers: - name: etcd image: quay.io/coreos/etcd:v3.5.0 # 可根据需要修改版本 command: - /bin/sh - -ec - | /usr/local/bin/etcd --name $(POD_NAME) \ --data-dir /etcd-data \ --listen-peer-urls http://0.0.0.0:2380 \ --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://$(POD_NAME).etcd-headless:2379 \ --initial-advertise-peer-urls http://$(POD_NAME).etcd-headless:2380 \ --initial-cluster $(POD_NAME)=http://$(POD_NAME).etcd-headless:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-cluster-state new \ --cert-file=/etc/etcd/certs/server.crt \ --key-file=/etc/etcd/certs/server.key \ --trusted-ca-file=/etc/etcd/certs/ca.crt volumeMounts: - mountPath: /etcd-data name: etcd-data - mountPath: /etc/etcd/certs name: etcd-certs readOnly: true volumeClaimTemplates: - metadata: name: etcd-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Gi # 为每个 Pod 分配 1Gi 存储 - metadata: name: etcd-certs spec: accessModes: ["ReadOnlyMany"] resources: requests: storage: 1Gi
观察上面的例子,不难发现,用户很难、也不想关心运维以及 Kubernetes 底层的各种概念。用户其实只关心两个信息:我怎么连接它(端口 port)、etcd 的版本是多少(image)。
如果向最终用户只暴露下述信息,是不是简洁很多了呢?
port: 2379 image: quay.io/coreos/etcd:v3.5.0
这种设计“简化版”的 API 对象,就叫做“构建上层抽象”,“构建上层抽象”是简化应用管理的必要手段。
接下来,再看使用 Operator 后的情况,事情就变得简单多了。Etcd 的 Operator 提供了 EtcdCluster 自定义资源,在它的帮助下,仅用几十行代码,安装、启动、停止等基础的运维操作。
apiVersion: operator.etcd.database.coreos.com/v1beta2 kind: EtcdCluster metadata: name: my-etcd-cluster namespace: default spec: size: 3 version: "3.4.15" storage: volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi
要扩容的话也很简单,只要更新节点数量(比如 size 从 3 改到 5),再 apply 一下,它同样会监听这个自定义资源的变动,去做对应的更新。更高级的 Operator 还可以自动升级、扩容、备份、恢复,甚至与 Prometheus 系统集成,自动检测故障、自动转移故障。
Operator 的实现上,其实是基于 CRD 构建“高层抽象”,通过 Kubernetes 的原生“控制器模式”将有状态应用的运维操作代码化。它与 StatefulSet 也并非竞争关系,你完全可以编写一个 Operator,在其控制循环里创建和管理 StatefulSet,而非直接管理 Pod。例如,业界知名的 Prometheus Operator 就是这么实现的。这种设计的优势,不仅在于简化操作,更在于它遵循 Kubernetes 基于资源和控制器的设计原则,同时不受限于内置资源的表达能力。只要开发者愿意编写代码,特定领域的经验都可以转化为 Operator 逻辑。
Red Hat 收购 CoreOS 之后,为开发者提供一套完整的工具集 Operator Framework 简化 Operator 的开发过程,但这依然不是一件轻松的工作。以 etcd 的 Operator 为例,尽管 etcd 本身算不上特别复杂的有状态应用,etcd Operator 的功能也相对基础,但其代码超过了9,000 行。这是因为,管理有状态应用本身就是非常复杂的事情,更何况在容器云平台上进行管理。
最后,尽管业内对状态应用以容器形式部署存在激烈争议,但可以肯定的是,若希望有状态应用在 Kubernetes 上稳定运行,Operator 是当前最可行的方案!
OAM 与 KubeVela
2019 年 10 月,阿里云与微软在上海 QCon 大会上联合发布了全球首个开放应用模型(OAM,Open Application Model)。该项目有两个部分:OAM 规范以及 OAM 规范的 Kubernetes 实现。
在 OAM 的规范中,应用由一组具有运维特征(Trait)的组件(Component)组成,并且限定在一个或多个应用边界(Application Scope)内。上述并非是完全抽象的概念,而是可实际使用的自定义资源(CRD)。这些概念的具体含义如下:
- 组件(Component):只要有编程经验的人,应该都知道组件的含义,组件是应用的基本构建块,具备可复用性,用于定义核心功能单元。在 OAM 中,每个组件代表一个独立的、可部署的微服务或资源(例如:数据库、缓存、API 网关等)。
- 运维特征(Trait):既然应用功能可以复用,那某些运维逻辑自然也可以封装复用。运维特征是可以随时绑定给待部署组件的、模块化、可拔插的运维能力,比如:副本数调整(手动、自动)、数据持久化、 设置网关策略、自动设置 DNS 解析等。
- 应用边界(Application Scopes):定义应用级别的部署特征,比如健康检查规则、安全组、防火墙、SLO、检验等模块。相对于运维特征而言,应用边界作用于一个应用的整体,而运维特征作用于应用中的某个组件。
- 应用(Application):将 Component(必需)、Trait(必需)和 Scope(可选)组合并实例化,形成了一个完整的应用描述。
OAM 通过上述自定义资源将原本复杂的 Kubernetes All-in-one 配置进行了一定程度的解耦。应用研发人员负责管理 Component,运维人员将 Component 组合并绑定 Trait,形成 Application。平台或基础设施提供方则负责 OAM 的解释能力,将这些自定义资源映射到实际的基础设施上。各种角色的关注点恰当地分离,不同角色更聚焦更专业的做好本角色的工作。
整个过程如图 所示。

KubeVela 是 OAM 规范在 Kubernetes 上的完整实现,它起源于 OAM 社区,由阿里巴巴、微软等技术专家共同维护。
对于平台工程师(Platform Builder)来说,KubeVela 是一个具备无限扩展性的 Kubernetes 原生应用构建引擎。他们负责准备应用部署环境、维护稳定可靠的基础设施,并将这些基础设施能力作为 KubeVela 模块注册到集群中。对于最终用户(End User,研发人员或运维人员)来说,只需选择部署环境、挑选能力模块并填写业务参数,就可以在不同运行环境上把应用随时运行起来!
KubeVela 工作流程如图 。

企业落地 Kubernetes 的难题
很多企业落地 Kubernetes 的时候采用了 “PaaS” 化的思路,即在 Kubernetes 之上,开发一个类 PaaS 平台。但这个平台设计理念、模型和使用方式往往都是自己的,这些设计会“盖住” Kubernetes 的能力,使其声明式 API、容器设计模式、控制器模式根本无法发挥原本的实力,也难以与广泛的生态系统对接。
上述问题的直接表现就是,这个 PaaS 系统不具备扩展性。假设我们要满足以下诉求:
能不能帮我运行一个定时任务
能不能帮我运运行一个 MySQL Operator
能不能根据自定义 metrics 定义水平扩容策略
能不能基于 Istio 来帮我做渐进式灰度发布
这里的关键点在于,上述能力在 Kubernetes 生态中都是常见且广泛支持的,有些甚至是 Kubernetes 内置功能。但是到了 PaaS 这里,要实现这些能力往往需要重新开发,而且由于先前的设计假设,可能还需要进行大规模的重构。
KubeVela 本质上是在 Kubernetes 上安装了一个 OAM 插件,使平台工程师能够依据 OAM 规范,将 Kubernetes 生态中的各种能力和插件整合成一个应用交付平台。所以说,KubeVela 为最终用户提供了类似 PaaS 的使用体验,同时也为平台工程师带来了 Kubernetes 原生的高可扩展性和平台构建规范。
不过,目前来看,KubeVela 背后的理论还是过于抽象,落地有一定的技术门槛!但 KubeVela 这种构建以”应用为中心“的上层平台的思想,毫无疑问代表着云原生技术未来的发展方向!
小结
云原生技术与理念发展至今,在推动现代应用架构演进方面取得了空前的成就!
以 Kubernetes 为代表的基础设施,将传统中间件的功能(如服务发现、负载均衡和自动化伸缩)从应用层剥离,转移至基础设施层。而服务网格进一步将“服务间流量治理”这一关键功能也下沉至基础设施层。
当然,基础设施的最终目标是创造业务价值,帮助用户更快、更好、更有信心地开发和交付应用。无论是 Kubernetes 还是 Istio,它们都是实现这一目标的工具,而非目的。而今出现的 Helm、Operator、OAM、KubeVela 等,则是以“以应用为中心”,将底层基础设施能力以更友好的方式“输送”给业务用户。
随着底层基础设施能力的日趋完善,相信不久的未来,一个应用要在世界上任何一个地方运行起来,唯一要做的,就是声明“我是什么”、“我要什么”。在那个时候,所有基础设施的概念,无论是 Kubernetes 还是 Istio,将统统消失不见。