作者 | 孙健波(天元)
来源|阿里巴巴云原生公众号

上个月,KubeVela 正式发布了, 作为一款简单易用且高度可扩展的应用管理平台与核心引擎,可以说是广大平台工程师用来构建自己的云原生 PaaS 的神兵利器。 那么本文就以一个实际的例子,讲解一下如何在 20 分钟内,为你基于 KubeVela 的 PaaS “上线“一个新能力。

在正式开始本文档的教程之前,请确保你本地已经正确安装了 KubeVela 及其依赖的 K8s 环境。

KubeVela 扩展的基本结构

KubeVela 的基本架构如图所示:

简单来说,KubeVela 通过添加 Workload TypeTrait 来为用户扩展能力,平台的服务提供方通过 Definition 文件注册和扩展,向上通过 Appfile 透出扩展的功能。官方文档中也分别给出了基本的编写流程,其中 2 个是 Workload 的扩展例子,一个是 Trait 的扩展例子:

  • OpenFaaS 为例的 Workload Type 扩展
  • 云资源 RDS 为例的 Workload Type 扩展
  • KubeWatch 为例的 Trait 扩展

我们以一个内置的 WorkloadDefinition 为例来介绍一下 Definition 文件的基本结构:

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:name: webserviceannotations:definition.oam.dev/description: "`Webservice` is a workload type to describe long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers.If workload type is skipped for any service defined in Appfile, it will be defaulted to `Web Service` type."
spec:definitionRef:name: deployments.appsextension:template: |output: {apiVersion: "apps/v1"kind:       "Deployment"spec: {selector: matchLabels: {"app.oam.dev/component": context.name}template: {metadata: labels: {"app.oam.dev/component": context.name}spec: {containers: [{name:  context.nameimage: parameter.imageif parameter["cmd"] != _|_ {command: parameter.cmd}if parameter["env"] != _|_ {env: parameter.env}if context["config"] != _|_ {env: context.config}ports: [{containerPort: parameter.port}]if parameter["cpu"] != _|_ {resources: {limits:cpu: parameter.cpurequests:cpu: parameter.cpu}}}]}}}}parameter: {// +usage=Which image would you like to use for your service// +short=iimage: string// +usage=Commands to run in the containercmd?: [...string]// +usage=Which port do you want customer traffic sent to// +short=pport: *80 | int// +usage=Define arguments by using environment variablesenv?: [...{// +usage=Environment variable namename: string// +usage=The value of the environment variablevalue?: string// +usage=Specifies a source the value of this var should come fromvalueFrom?: {// +usage=Selects a key of a secret in the pod's namespacesecretKeyRef: {// +usage=The name of the secret in the pod's namespace to select fromname: string// +usage=The key of the secret to select from. Must be a valid secret keykey: string}}}]// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)cpu?: string}

乍一看挺长的,好像很复杂,但是不要着急,其实细看之下它分为两部分:

  • 不含扩展字段的 Definition 注册部分
  • 供 Appfile 使用的扩展模板(CUE Template)部分

我们拆开来慢慢介绍,其实学起来很简单。

不含扩展字段的 Definition 注册部分

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:name: webserviceannotations:definition.oam.dev/description: "`Webservice` is a workload type to describe long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers.If workload type is skipped for any service defined in Appfile, it will be defaulted to `Web Service` type."
spec:definitionRef:name: deployments.apps

这一部分满打满算 11 行,其中有 3 行是在介绍 webservice 的功能,5行是固定的格式。只有 2 行是有特定信息:

  definitionRef:name: deployments.apps

这两行的意思代表了这个 Definition 背后用的 CRD 名称是什么,其格式是 <resources>.<api-group>。了解 K8s 的同学应该知道 K8s 中比较常用的是通过 api-group, versionkind 定位资源,而 kind 在 K8s restful API 中对应的是 resources。以大家熟悉 Deploymentingress 为例,它的对应关系如下:

![image.png](https://img-blog.csdnimg.cn/img_convert/bf72f5ef3c83bc67071d3201413a688f.png#align=left&display=inline&height=76&margin=[object Object]&name=image.png&originHeight=133&originWidth=1296&size=10962&status=done&style=none&width=744)

这里补充一个小知识,为什么有了 kind 还要加个 resources 的概念呢? 因为一个 CRD 除了 kind 本身还有一些像 status,replica 这样的字段希望跟 spec 本身解耦开来在 restful API 中单独更新, 所以 resources 除了 kind 对应的那一个,还会有一些额外的 resources,如 Deployment 的 status 表示为 deployments/status

所以相信聪明的你已经明白了不含 extension 的情况下,Definition 应该怎么写了,最简单的就是根据 K8s 的资源组合方式拼接一下,只要填下面三个尖括号的空格就可以了。

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:name: <这里写名称>
spec:definitionRef:name: <这里写resources>.<这里写api-group>

针对运维特征注册(TraitDefinition)也是这样。

apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:name: <这里写名称>
spec:definitionRef:name: <这里写resources>.<这里写api-group>

所以把 Ingress 作为 KubeVela 的扩展写进去就是:

apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:name:  ingress
spec:definitionRef:name: ingresses.networking.k8s.io

除此之外,TraitDefinition 中还增加了一些其他功能模型层功能,如:

  • appliesToWorkloads: 表示这个 trait 可以作用于哪些 Workload 类型。
  • conflictWith: 表示这个 trait 和哪些其他类型的 trait 有冲突。
  • workloadRefPath: 表示这个 trait 包含的 workload 字段是哪个,KubeVela 在生成 trait 对象时会自动填充。 …

这些功能都是可选的,本文中不涉及使用,在后续的其他文章中我们再给大家详细介绍。

所以到这里,相信你已经掌握了一个不含 extensions 的基本扩展模式,而剩下部分就是围绕 CUE 的抽象模板。

供 Appfile 使用的扩展模板(CUE Template)部分

对 CUE 本身有兴趣的同学可以参考这篇 CUE 基础入门 多做一些了解,限于篇幅本文对 CUE 本身不详细展开。

大家知道 KubeVela 的 Appfile 写起来很简洁,但是 K8s 的对象是一个相对比较复杂的 YAML,而为了保持简洁的同时又不失可扩展性,KubeVela 提供了一个从复杂到简洁的桥梁。 这就是 Definition 中 CUE Template 的作用。

CUE 格式模板

让我们先来看一个 Deployment 的 YAML 文件,如下所示,其中很多内容都是固定的框架(模板部分),真正需要用户填的内容其实就少量的几个字段(参数部分)。

apiVersion: apps/v1
kind: Deployment
meadata:name: mytest
spec:template:spec:containers:- name: mytestenv:- name: avalue: bimage: nginx:v1metadata:labels:app.oam.dev/component: mytestselector:matchLabels:app.oam.dev/component: mytest

在 KubeVela 中,Definition 文件的固定格式就是分为 outputparameter 两部分。其中output中的内容就是“模板部分”,而 parameter 就是参数部分。

那我们来把上面的 Deployment YAML 改写成 Definition 中模板的格式。

output: {apiVersion: "apps/v1"kind:       "Deployment"metadata: name: "mytest"spec: {selector: matchLabels: {"app.oam.dev/component": "mytest"}template: {metadata: labels: {"app.oam.dev/component": "mytest"}spec: {containers: [{name:  "mytest"image: "nginx:v1"env: [{name:"a",value:"b"}]}]}}}
}

这个格式跟 json 很像,事实上这个是 CUE 的格式,而 CUE 本身就是一个 json 的超集。也就是说,CUE的格式在满足 JSON 规则的基础上,增加了一些简便规则, 使其更易读易用:

  • C 语言的注释风格。
  • 表示字段名称的双引号在没有特殊符号的情况下可以缺省。
  • 字段值结尾的逗号可以缺省,在字段最后的逗号写了也不会出错。
  • 最外层的大括号可以省略。

CUE 格式的模板参数–变量引用

编写好了模板部分,让我们来构建参数部分,而这个参数其实就是变量的引用。

parameter: {name: stringimage: string
}
output: {apiVersion: "apps/v1"kind:       "Deployment"spec: {selector: matchLabels: {"app.oam.dev/component": parameter.name}template: {metadata: labels: {"app.oam.dev/component": parameter.name}spec: {containers: [{name:  parameter.nameimage: parameter.image}]}}}
}

如上面的这个例子所示,KubeVela 中的模板参数就是通过 parameter 这个部分来完成的,而 parameter 本质上就是作为引用,替换掉了 output 中的某些字段。

完整的 Definition 以及在 Appfile 使用

事实上,经过上面两部分的组合,我们已经可以写出一个完整的 Definition 文件:

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:name: mydeploy
spec:definitionRef:name: deployments.appsextension:template: |parameter: {name: stringimage: string}output: {apiVersion: "apps/v1"kind:       "Deployment"spec: {selector: matchLabels: {"app.oam.dev/component": parameter.name}template: {metadata: labels: {"app.oam.dev/component": parameter.name}spec: {containers: [{name:  parameter.nameimage: parameter.image}]}}}}

为了方便调试,一般情况下可以预先分为两个文件,一部分放前面的 yaml 部分,假设命名为 def.yaml 如:

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:name: mydeploy
spec:definitionRef:name: deployments.appsextension:template: |

另一个则放 cue 文件,假设命名为 def.cue

parameter: {name: stringimage: string
}
output: {apiVersion: "apps/v1"kind:       "Deployment"spec: {selector: matchLabels: {"app.oam.dev/component": parameter.name}template: {metadata: labels: {"app.oam.dev/component": parameter.name}spec: {containers: [{name:  parameter.nameimage: parameter.image}]}}}
}

先对 def.cue 做一个格式化,格式化的同时 cue 工具本身会做一些校验,也可以更深入的通过 cue 命令做调试:

cue fmt def.cue

调试完成后,可以通过脚本把这个 yaml 组装:

./hack/vela-templates/mergedef.sh def.yaml def.cue > mydeploy.yaml

再把这个 yaml 文件 apply 到 K8s 集群中。

$ kubectl apply -f mydeploy.yaml
workloaddefinition.core.oam.dev/mydeploy created

一旦新能力 kubectl apply 到了 Kubernetes 中,不用重启,也不用更新,KubeVela 的用户可以立刻看到一个新的能力出现并且可以使用了:

$ vela worklaods
Automatically discover capabilities successfully ✅ Add(1) Update(0) Delete(0)TYPE           CATEGORY    DESCRIPTION
+mydeploy      workload    description not definedNAME        DESCRIPTION
mydeploy    description not defined

在 Appfile 中使用方式如下:

name: my-extend-app
services:mysvc:type: mydeployimage: crccheck/hello-worldname: mysvc

执行 vela up 就能把这个运行起来了:

$ vela up -f docs/examples/blog-extension/my-extend-app.yaml
Parsing vela appfile ...
Loading templates ...Rendering configs for service (mysvc)...
Writing deploy config to (.vela/deploy.yaml)Applying deploy configs ...
Checking if app has been deployed...
App has not been deployed, creating a new deployment...
✅ App has been deployed 												

如何在 20 分钟内给你的 K8s PaaS 上线一个新功能?相关推荐

  1. 如何在20分钟内批量部署20台ESXi服务器?

    如何在20分钟内批量部署20台ESXi服务器? https://mp.weixin.qq.com/s?__biz=MjM5NTk0MTM1Mw==&mid=2650642256&idx ...

  2. 如何在20分钟内找寻到生命的意义

    原文 如何找寻到你生命的真正意义?我说的不是你的工作,不是你的日常职责,也不是你的长期目标.我说的是你活着的真正原因,你为什么而存在. 也许你是一个虚无主义者,不相信你活着有一个目标,认为生活是没有意 ...

  3. 了解如何在20分钟内创建您的第一个Angular应用

    Angular is a JavaScript framework, created my Misko Hevery and maintained by Google. It's an MVC (Mo ...

  4. 以太坊区块链同步_以太坊69:如何在10分钟内建立完全同步的区块链节点

    以太坊区块链同步 by Lukas Lukac 卢卡斯·卢卡奇(Lukas Lukac) Ethereu M 69:如何在10分钟内建立完全同步的区块链节点 (Ethereum 69: how to ...

  5. 如何在10分钟内开始使用MongoDB

    by Navindu Jayatilake 通过纳文杜·贾亚提莱克 如何在10分钟内开始使用MongoDB (How to get started with MongoDB in 10 minutes ...

  6. 如何在1分钟内CSDN收益1000万,走上人生巅峰?!

    事情的起因源于前几日CSDN专栏作者群中有位同志自曝收益:426584.46元(不用数了42万+,未证实是否属实),瞬间刷屏. 那么作为一位普通的技术分享者,是否有机会利用开源项目短时间内赢取白富美. ...

  7. github创建静态页面_如何在10分钟内使用GitHub Pages创建免费的静态站点

    github创建静态页面 Static sites have become all the rage, and with good reason – they are blazingly fast a ...

  8. es6 ... 添加属性_如何在10分钟内免费将HTTPS添加到您的网站,以及为什么您现在不止需要这样做......

    es6 ... 添加属性 by Ayo Isaiah 通过Ayo Isaiah 如何在10分钟内免费将HTTPS添加到您的网站,以及为什么现在比以往更需要这样做 (How to add HTTPS t ...

  9. javascript创建类_如何在10分钟内使用JavaScript创建费用管理器

    javascript创建类 by Per Harald Borgen 通过Per Harald Borgen 如何在10分钟内使用JavaScript创建费用管理器 (How to create an ...

最新文章

  1. 英文金曲大赛_JAVA
  2. (~解题报告~)L1-020 帅到没朋友 (20分)——25行代码AC
  3. How Many Answers Are Wrong HDU - 3038(带权并查集)
  4. 【论文写作】精品课程教学网站中用户管理如何写
  5. 创建全局SystemTray.ProgressIndicator
  6. [Soft]软件技术的两个趋势
  7. 你还不知道Java异或运算符的妙用?
  8. vue中公告消息横向无缝循环滚动
  9. ONEDNS配置1:centos7DNS服务器forwarder配置
  10. “红山开源”创新论坛 | ChinaOSC
  11. 网上商城建设:微信小程序直播申请开通流程及开通方法
  12. 海信html501n手机,专为中老年人设计的智能手机,海信T50确实不简单
  13. cocos2dx之Chipmunk
  14. XB7608AFJ单节锂电池二合一保护芯片
  15. 基于Neo4j的关联数据评估风险投资人业绩
  16. 下拉框反选的几种方式
  17. python批量解压文件,python批量解压zip文件的方法
  18. 关于计算机的小故事英语作文,急求一篇英语作文《关于自己的故事》急求一篇英语作文《关于自己的小故事》~...
  19. 「蓝玫瑰不会安眠」读后感
  20. windows分屏 拔掉显示器之后软件不在主显示器上显示问题

热门文章

  1. C/C++写无控制台窗口程序
  2. BFS求无权图的单源最短路径-邻接矩阵存储
  3. 1068 Find More Coins (30 分)【难度: 难 / 知识点:01背包问题 + 找路径】
  4. 计算机网络一些重要的知识
  5. 【在线画流程图】网站
  6. Spring boot使用Bootstrap
  7. fiddler everywhere手机抓包_基于移动端抓包使用Fiddler模拟弱网测试
  8. 【Java自顶向下】HashMap面试题(2021最新版)
  9. 面试:你说一下 MyBatis 事务吧!
  10. JDK 13 的最新垃圾回收器ZGC,你了解多少?