OAM 加持下的 Kubernetes PaaS 应用管理实践

简介: 近年来随着云原生技术的高速发展,阿里巴巴看到了云原生技术的潜力,以及未来企业 IT 全面上云的必然趋势,从2018年开始全面转型到Kubernetes技术。到了 2019 年,Kubernetes 基础设施底盘在阿里巴巴经济体中已经覆盖了阿里巴巴方方面面的业务,规模化的接入了包括核心电商、物流、金融、外卖、搜索、计算、AI 等诸多头部互联网场景。这套技术底盘,也逐步成为了阿里巴巴支撑 618、双

近年来随着云原生技术的高速发展,阿里巴巴看到了云原生技术的潜力,以及未来企业 IT 全面上云的必然趋势,从2018年开始全面转型到Kubernetes技术。到了 2019 年,Kubernetes 基础设施底盘在阿里巴巴经济体中已经覆盖了阿里巴巴方方面面的业务,规模化的接入了包括核心电商、物流、金融、外卖、搜索、计算、AI 等诸多头部互联网场景。这套技术底盘,也逐步成为了阿里巴巴支撑 618、双 11 等互联网级大促的主力军之一。

如今,阿里巴巴和蚂蚁金服内部运行的集群规模也达到了一个新的高度,我们内部维护了数十个大规模的K8s集群,其中最大的集群约1万个节点,这其实还不是能力上限。每个集群会服务上万个应用。在阿里云的Kubernetes服务ACK上,我们还维护了上万个用户的K8s集群,这个规模和技术挑战在全世界也是首屈一指的。

应用管理的两大难题

在一定程度上解决了规模和稳定性问题之后,我们发现其实在K8s上管理应用还有很大的挑战等着我们解决。今天我们主要讨论这两个方面的挑战:

 

  1. 对应用研发而言,K8s API 针对简单应用过于复杂,针对复杂应用难以上手。
  2. 对应用运维而言,K8s 的扩展能力难以管理;K8s 原生的 API 没有对云资源全部涵盖。

 

总体而言,我们面临的挑战就是,如何基于K8s提供真正意义上的应用管理平台,让研发和运维只需关注到应用本身。

研发对应用管理的诉求

K8s all in one 的 YAML文件

 

让我们来看一下这样一个 K8s 的 yaml 文件,这个 yaml 文件已经是我简化过的,但是我们仍然可以看到还是比较长。

 

 

面对这样一个广受“复杂”诟病的YAML文件,我相信大家都会忍不住想该怎么简化。

 

自上而下,我们大致把他们分为三块,一块是扩缩容、滚动升级相关的参数,这一块应该是应用运维的同学比较关心的;然后中间一块是镜像、端口、启动参数相关的,这一块应该是开发的同学比较关心的;最后一块大家可能根本看不懂,通常情况下也不太需要明白,可以把他们理解为K8s平台层的同学需要关心的。

 

看到这样一个yaml文件,我们很容易想到,只要把里面的字段封装一下,把该暴露的暴露出来就好了。确实,我们内部就有 PaaS 平台这么做。

只透出部分字段:简单却能力不足

 

部分PaaS平台精心挑选了部分字段,并做了一个漂亮的前端界面给用户,只透出给用户5个左右的字段,大大降低了用户理解K8s的心智负担。然后底层实现用类似模板的方式把用户这五个字段渲染出来一个完整的yaml文件。突出的字段大概如下图所示:

 

 

不得不说这种方式是非常有效的,针对简单无状态的应用,精简 API 可以大大降低 K8s 的门槛,快速并且高效的对接用户,PaaS平台也顺利让大家使用了起来。同时,我也从一些技术分享中了解到许多其他公司也是用这种类似的方式简化的 K8s API。

 

但是当用户的业务开始大规模对接以后,我们就会自然而言开始遇到有状态的复杂应用。用户就会开始抱怨 PaaS 平台能力不够了。比如我们的Zookeeper多实例选主、主从切换这些逻辑,在这五个字段里就很难展开了。

 

归根结底就是屏蔽大量字段的方式会限制基础设施本身的能力演进,但是 K8s 的能力是非常强大而灵活的。我们不可能为了简化而放弃掉K8s强大的能力。

 

就比如当前这个例子,我们很容易想到,针对复杂有状态的应用,应该通过K8s里面的 CRD 和 Operator 来解决。

CRD+Operator: K8s 扩展能力强大却难以上手

确实,我们内部对接复杂应用云原生化的时候,也推荐他们编写Operator,但是经常出现这样一段对话。

 

 

中间件的工程师跟我们说,我这有个Zookeeper该用哪种K8s的Workload接入啊? 我们想了想,K8s设计如此精妙,自然没有解决不了的问题,于是我们推荐他们使用Operator。他们就懵了,说你们搞云原生的这几年造新词的能力绝对一流,之前都没听说过。

 

想想也是,业务方理解这些新概念不难,但是真的要自己去上手实现,还是非常困难的。我们自然也觉得业务方更应该专注于他们的业务本身,于是我们不得不帮跟他们一起写。

 

可以看到,我们亟需一个统一的模型去解决研发对应用管理的诉求

运维对应用管理的诉求

除了研发侧的问题之外,我们在运维侧也遇到了很大的挑战。

运维能力众多却难以管理

K8s的CRD Operator 机制非常的灵活而强大,不光是复杂应用可以通过编写CRD Operator实现,我们的运维能力也大量通过Operator来扩展,比如灰度发布、流量管理,弹性扩缩容等等。我们常常赞叹于 K8s 的灵活性,它让我们基础平台团队对外提供能力非常方便,但是对应用运维来说,他们要使用我们提供的这些运维能力,却变得有些困难。

 

比如我们上线了一个CronHPA,可以定时设置在每个阶段会根据 CPU 调整实例数的范围。应用运维并不知道跟原生不带定时功能的 HPA 会产生冲突,而我们也没有一个统一的渠道帮助管理这么多种复杂的扩展能力,结果自然是引起了故障。这血的教训提醒我们要做事前检查,熟悉K8s的机制很容易让我们想到为每个 Operator 加上 admission webhook。

 

这个 admission webhook 需要拿到这个应用绑定的所有运维能力以及应用本身的运行模式,然后做统一的校验。如果这些运维能力都是一方提供的还好,如果存在二方,甚至三方提供的扩展能力,我们就没有一个统一的方式去获知了。事实上如果我们想的更远一些就会发现,我们需要一个统一的模型来协商并管理这些复杂的扩展能力。

云资源难以描述和统一交付

当我们把应用的Operator以及对应的运维能力都写好以后,我们很容易想到要打包交付这个应用,这样无论是公有云还是专有云都可以通过一个统一的方式去交互。社区的主流方式目前就是使用Helm来打包应用,而我们也采用了这样的方式给我们的用户交付。但是却发现我们的用户需求远不止于此。

 

云原生应用有一个很大的特点,那就是它往往会依赖云上的资源,包括数据库、网络、负载均衡、缓存等一系列资源。

 

 

当我们使用 Helm 打包时,我们只能针对K8s 原生API,而如果我们还想启动 RDS 数据库,就比较困难了。如果不想去数据库的交互页面,想通过K8s的API来管理,那就又不得不去写一个 CRD 来定义了,然后通过Operator去调用实际云资源的API。

 

这一整套交付物实际上就是一个应用的完整描述,即我们所说的“应用定义”。但事实上,我们发现“应用定义”这个东西,在整个云原生社区里其实是缺失的。这也是为什么阿里巴巴内部有很多团队开始尝试设计了自己的“应用描述”。

 

 

 

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

每个公司和团队都在自己定义应用

 

不光是阿里内部的团队需要应用定义,事实上几乎每个基于K8s管理应用的公司和团队都在自己定义应用。如下所示,我就搜到了两家公司的应用定义:

 

 

 

应用定义实际上是应用交付、分发不可或缺的部分。但是在具体的实践中,我们感受到内部的应用定义都面临着如下的问题:

  1. 定义是否足够开放,是否可以复用?
  2. 如何与开源生态协作?
  3. 如何迭代与演进?

这三个问题带来的挑战都是巨大的,我在上文已经提到,一个应用定义需要容易上手,但又不是灵活性,更不能是一个黑盒。应用定义同样需要跟开源生态紧密结合,没有生态的应用定义注定是没有未来的,自然也很难持续的迭代和演进。

区分使用者的分层模型与模块化的封装

让我们回过头来重新审视我们面临的挑战,归根结底在于 K8s 的 All in One API 是为平台提供者设计的,我们不能像下图左侧显示的一样,让应用的研发、运维跟K8s团队一样面对这一团API。

 

 

一个合理的应用模型应该具有区分使用者角色的分层结构,同时将运维能力模块化的封装。让不同的角色使用不同的API,正如上图右侧部分。

OAM: 以应用为中心的K8s API分层模型

OAM(Open Application Model)正是这样一个以应用为中心的 K8s API 分层模型:

  • 从研发的角度,他操作和关注的API对象叫Component。
  • 从运维的角度,模块化的运维能力封装就是Trait,而运维可以通过App Config将Component和Trait自有组合,最终实例化成一个运行的应用。
  • K8s团队本身则仍然基于K8s的原生 API 迭代这一层能力。

 

针对研发时常抱怨的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中看看不同的概念具体是什么。

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

 

可以看到Component本身就是一个K8s的CRD,spec 字段里面的部分就是Component具体的定义。其中第一个重要的字段就是workloadType,这个决定了应用的运行模式。

 

针对简单应用,OAM提供了6种核心Workload,如下表所示:

 

 

主要通过是否可访问、是否可复制、是否长久运行来区分。如Server,就代表了大家最常用的K8s里面Deployment+Service的组合。

 

填写了核心workloadType的Component,只需要定义Container里的注入镜像、启动参数等字段,就如我们最开始所说的屏蔽掉大量字段的PaaS一样,为用户大大降低了门槛。

 

而针对复杂的有状态应用,OAM 则允许通过扩展Workload来实现,如下图所示,我们可以定义一个新的叫 openfaas 的WorkloadType,它的定义实际上完全等价于一个CRD定义。

 

 

OAM模型中,使用自定义的Workload也是通过Component,只是WorkloadType改为你自定义的WorkloadType名称。

通过WorkloadType,OAM的Component就把简单无状态应用和复杂有状态应用统一了起来。

 

OAM Trait:可发现、可管理的运维能力

Trait 就是模块化的运维能力,我们能通过命令行工具发现一个系统里支持哪些Traits(运维能力)。

 

$ kubectl get traits
NAME            AGE
autoscaler      19m
ingress         19m
manual-scaler   19m
volume-mounter  19m

 

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

 

$ 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"
               ...
             }
          }
        }
      }
    }

 

可以看到,他可以在 Trait 定义里清晰的看到这个运维能力可以作用于哪种类型的 Workload,包括能填哪些参数、哪些必填/选填、参数的作用描述是什么。 你也可以发现,OAM 体系里面,Component 和 Trait 这些 API 都是 Schema,所以它们是整个对象的字段全集,也是了解这个对象描述的能力“到底能干吗?”的最佳途径。

 

实时上,大家也可能已经发现,Trait 的定义和 CRD 也是对等的,而你完全也可以通过 Operator 实现 Trait。

 

 

所以 OAM 事实上将原本散乱的Operator通过不同的角色有机的管理起来了

 

OAM Application Config:组装Component和Trait,应用实例化运行

Component 和 Trait 最终通过Application Configuration结合,并真实运行起来。

 

 

更重要的是,这个 OAM 应用描述文件是完全自包含的,也就是说通过 OAM YAML,作为软件分发商,我们就可以完整地跟踪到一个软件运行所需要的所有资源和依赖。这就使得现在对于一个应用,大家只需要一份 OAM 的配置文件,就可以快速、在不同运行环境上把应用随时运行起来,把这种自包含的应用描述文件完整地交付到任何一个运行环境中。

 

而我们图中的 Rudr 项目就是OAM的一个实现,也可以理解为OAM的一个解释器,将OAM的统一描述转换为背后众多的Operator。同时Rudr也将是一个统一管理的媒介,如果Application Configuration中出现了一个Component绑定2个Trait并且互相冲突的情况,就可以快速被检验并发现问题,如下图所示。

 

同样的,包括复杂应用的编排、云资源的拉起、Workload与Trait交互等等,都可以在这个OAM解释器中实现。

 

大家可以通过rudr项目中的教程文档体验OAM的这些交互过程。

OAM 加持下的 Kubernetes PaaS

事实上,OAM 加持下的 PaaS 基于Kubernetes,将众多 Operator 分层的管理了起来。

 

 

 

对于研发,通常他关心的应用可能是一个由 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 可以像乐高积木一样灵活组装,使得应用定义成为了社区共同建设的项目,使得应用管理变得统一,功能却更加强大!

最后

最后,给大家分享一下 OAM 项目近期的计划,OAM 是一个完全属于社区的应用定义模型,我们非常希望大家都能参与进来。

 

  • 我们会集成 OpenFaaS、Terraform、Knative,支持不同的 Workload,让 OAM 可以对接不同的实现。
  • 我们会针对 K8s Operator 提供一键接入的转换方式,让现在的 Operator 快速融入OAM。
  • 我们也会开源一个 oam-framework 项目,这个项目可以快速构建一个 OAM 的实现,类似kubebuilder/Operator-sdk 快速构建 Operator 一样,oam-framework 会帮助你快速构建OAM实现。
  • 我们还会构建一个 CRD (traits/workloads) Registry项目,可以让大家注册自己的OAM实现、自定义Workload、Trait等等资源,以便最大程度的实现社区中大家的协作与复用。

最后的最后,我们也非常欢迎大家加入阿里云原生应用平台-基础技术中台团队,这里大牛云集,有世界级的复杂场景。

 

 

 

 

 

 

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
15天前
|
运维 Kubernetes 监控
Kubernetes 集群的持续性能优化实践
【4月更文挑战第26天】 在动态且不断增长的云计算环境中,维护高性能的 Kubernetes 集群是一个挑战。本文将探讨一系列实用的策略和工具,旨在帮助运维专家监控、分析和优化 Kubernetes 集群的性能。我们将讨论资源分配的最佳实践,包括 CPU 和内存管理,以及集群规模调整的策略。此外,文中还将介绍延迟和吞吐量的重要性,并提供日志和监控工具的使用技巧,以实现持续改进的目标。
|
19天前
|
存储 运维 Kubernetes
Kubernetes 集群的持续性能优化实践
【4月更文挑战第22天】在动态且复杂的微服务架构中,确保 Kubernetes 集群的高性能运行是至关重要的。本文将深入探讨针对 Kubernetes 集群性能优化的策略与实践,从节点资源配置、网络优化到应用部署模式等多个维度展开,旨在为运维工程师提供一套系统的性能调优方法论。通过实际案例分析与经验总结,读者可以掌握持续优化 Kubernetes 集群性能的有效手段,以适应不断变化的业务需求和技术挑战。
|
2月前
|
Kubernetes 网络协议 应用服务中间件
K8S二进制部署实践-1.15.5
K8S二进制部署实践-1.15.5
40 0
|
2月前
|
Prometheus 监控 Kubernetes
Kubernetes 集群监控与日志管理实践
【2月更文挑战第29天】 在微服务架构日益普及的当下,Kubernetes 已成为容器编排的事实标准。然而,随着集群规模的扩大和业务复杂度的提升,有效的监控和日志管理变得至关重要。本文将探讨构建高效 Kubernetes 集群监控系统的策略,以及实施日志聚合和分析的最佳实践。通过引入如 Prometheus 和 Fluentd 等开源工具,我们旨在为运维专家提供一套完整的解决方案,以保障系统的稳定性和可靠性。
|
6月前
|
运维 Kubernetes 大数据
利用 Kubernetes 降本增效?EasyMR 基于 Kubernetes 部署的探索实践
Kubernetes 是市面上最受欢迎的集群管理解决方案之一,本文将介绍 EasyMR 作为一款提供一站式可视化组件安装部署与可观测运维管理能力的大数据计算引擎产品,是如何基于 Kubernetes 部署进行实践探索的。
48 0
|
2天前
|
消息中间件 运维 Kubernetes
构建高效自动化运维体系:Ansible与Kubernetes的融合实践
【5月更文挑战第9天】随着云计算和微服务架构的普及,自动化运维成为确保系统可靠性和效率的关键。本文将深入探讨如何通过Ansible和Kubernetes的集成,构建一个强大的自动化运维体系。我们将分析Ansible的配置管理功能以及Kubernetes容器编排的优势,并展示如何将二者结合,以实现持续部署、快速扩展和高效管理现代云原生应用。文章还将涵盖实际案例,帮助读者理解在真实环境下如何利用这些工具优化运维流程。
|
4月前
|
Web App开发 Kubernetes 数据可视化
Kubernetes Dashboard 可视化插件部署 博主亲自实践可用
Kubernetes Dashboard 可视化插件部署 博主亲自实践可用
61 0
|
15天前
|
存储 Kubernetes 监控
Kubernetes 集群的持续性能优化实践
【4月更文挑战第25天】 在动态且不断变化的云计算环境中,维护 Kubernetes 集群的高性能是一个挑战。本文将探讨一系列实用的策略和方法,用于持续监控和优化 Kubernetes 集群的性能。通过分析真实案例,我们将展示如何识别瓶颈,采取相应的优化措施,并实现自动化以简化运维工作。这些方法将帮助读者提高其 Kubernetes 环境的稳定性和效率,同时降低运营成本。
|
25天前
|
存储 运维 Kubernetes
Kubernetes 集群的持续性能优化实践
【4月更文挑战第16天】 随着容器化技术的普及,Kubernetes 已成为管理微服务架构的首选平台。但在动态变化的负载环境中保持高性能并非易事。本文将探讨一系列实用的 Kubernetes 集群性能优化策略,旨在帮助运维工程师识别和解决潜在的性能瓶颈。通过对存储、计算资源分配、网络配置以及集群规模管理的深入分析,我们将提供一套综合的性能调优框架,以支持高效、稳定的服务运行。
|
27天前
|
Kubernetes 监控 Cloud Native
构建高效云原生应用:基于Kubernetes的微服务治理实践
【4月更文挑战第13天】 在当今数字化转型的浪潮中,企业纷纷将目光投向了云原生技术以支持其业务敏捷性和可扩展性。本文深入探讨了利用Kubernetes作为容器编排平台,实现微服务架构的有效治理,旨在为开发者和运维团队提供一套优化策略,以确保云原生应用的高性能和稳定性。通过分析微服务设计原则、Kubernetes的核心组件以及实际案例,本文揭示了在多变的业务需求下,如何确保系统的高可用性、弹性和安全性。
23 4