没有addon的生态,是个不够开放的生态


Cloud Native
神州数码ESG服务BU云原生交付中心、云基地
在云原生上的尝试、调研与分享
本期作者
肖晟鹏
专业踩坑的 bug工程师
在前不久的一期云原生专栏推文中 (神助攻网红项目一线牵:顶级云原生项目 KubeVela 插件仓库支持 GitLab 了! ),我们分享了云原生团队与顶级云原生开源项目 KubeVela 的故事,详细介绍了 KubeVela 的项目背景、应用场景,谈到了云原生团队借由给自己编写 addon (插件)的契机,成功为 KubeVela 做出了在代码仓库方面的开源贡献——实现 KubeVela 插件仓库对 GitLab 的支持。
那么本期推文就来初步探索 KubeVela 中的 addon,谈谈 KubeVela 中为什么需要 addon,并以一个简小的例子来说明如何自定义 addon。
#1 为什么需要addon
我们知道,应用和 模块自定义 都可以自己写 yaml 或者 cue 文件部署,为什么会存在 addon (插件)呢?
这是因为通过自己写 yaml 和 cue 的方式来部署应用一般是用于部署自己写的服务,而如果是部署一些通用的中间件,这种方式就太麻烦了。比如有的应用每个集群只需要部署一次,但是非常复杂,每次部署都要写一大堆配置文件。
并且如果应用需要用到一个复杂的模块定义,那么开发人员在部署应用的时候就会花费大量的时间去研究怎么写 yaml 或者 cue 去扩展 KubeVela。
什么是 cue
cue 是 json 的超集,与 Go 完美集成,还能使用 go 的一些内置依赖包。
使用 cue 的目的就是为了使配置更加灵活。
在 KubeVela 中部署的时候,cue 定义会转变为 yaml 定义。
那么有没有一个很好地解决办法呢?
这就是 Addon了。
Addon 在安装启用之后,会被创建成一个一个的应用,最终由运行在管控集群的 KubeVela 控制器完成对应用中所描述资源的下发。
插件可以给 KubeVela 管理的集群带来:自定义的应用和自定义的组件。
并且,Addon 在 UX 页面上是可以通过 OSS 或者代码仓库引入的,官方有个公共的插件库,并且还能够引入自己的插件库,在页面上点击启用,或者使用 CLI enable,就能给 KubeVela 带来新的功能,在 KubeVela 中扩展 Terraform 功能就是通过 addon 的形式来的。
#2 如何定义addon
addon代码的目录结构
那么插件是如何定义的呢?
官方文档中有简单的说明,其实插件代码中编写的就是一些 yaml 和 cue 文件,addon 代码必须要满足如下目录结构,其中metadata.yaml和template.yaml是必须的:
目录结构
├── resources/
│ ├── xxx.cue
│ ├── xxx.yaml
│ └── parameter.cue
├── definitions/
├── schemas/
├── README.md
├── metadata.yaml
└── template.yaml
metadata.yaml: 元数据文件 (metadata.yaml)描述了插件的名称、描述等基本描述信息。只有包含这个文件,一个仓库下的目录才会被 UX/CLI 识别为一个插件的资源目录。
template.yaml: 插件目录下面的所有文件最终会渲染成为一个 KubeVela 的 Application 应用,所以template.yaml就是用于组成这个应用的框架。
resources目录: 下的文件可以理解为应用的部署文件,格式为K8S的Manifest,当addon启用的时候,如果resources目录下有定义,就会部署到集群上面去。
definitions目录: 用于存放组件定义、运维特征定义和工作流节点定义等模版定义文件,当addon启用的时候,如果该目录下有定义,那么最终KubeVela会引入新的模块定义,比如新的组件定义,在部署的时候就可以选择不同的type,而不是webservice进行部署。
schema目录: 配合definitions目录中存放的模块定义。在definitions目录下编写模块定义时,在cue中通常会写一些自定义的属性,比如开放什么端口,service的类型等。这些自定义的属性在CLI部署的时候可以供用户使用,如果你希望这些属性也能够在UX界面展示,就需要在该目录下将这些数据写进去。
概念是很抽象的,实践才是检验真理的唯一标准。
我们这里来做一个小实验,从简单的 addon 部署简单应用开始。
一个简单的小实例
Step 1:创建代码仓库
首先创建一个代码仓库,目录结构如下:
/ 代码仓库的目录结构
resources 目录下保存的是一些 k8s 的 Manfest,如下:
redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-deployment
namespace: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:6.2.6
command:
- "sh"
- "-c"
- "redis-server /usr/local/etc/redis/redis.conf"
ports:
- containerPort: 6379
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: data
hostPath:
path: /home/k8s/redis/data
- name: config
configMap:
name: redisconfig
redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-service
labels:
app: redis
spec:
type: NodePort
ports:
- name: redis
port: 6379
selector:
app: redis
redis-config.cue
output: {
type: "raw"
properties: {
apiVersion: "v1"
kind: "ConfigMap"
metadata: {
name: "redisconfig"
namespace: "redis"
}
data: input: parameter.redisconfig
}
}
parameter.cue
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-deployment
namespace: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:6.2.6
command:
- "sh"
- "-c"
- "redis-server /usr/local/etc/redis/redis.conf"
ports:
- containerPort: 6379
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: data
hostPath:
path: /home/k8s/redis/data
- name: config
configMap:
name: redisconfig
ps:这里的 parameter 就是自定义的属性。
如果熟悉 K8S 的读者一眼看过去就明白,这就是 K8S 的 Manifest,在 K8S 上面部署资源的文件。
addon 仓库中必须要有 metadata.yaml 文件,该文件描述了插件的名称、描述等基本描述信息。只有包含这个文件,一个仓库下的目录才会被 UX/CLI 识别为一个插件的资源目录。
metadata.yaml
metadata.yaml:
name: my-redis
version: 1.0.0
description: Example adddon.
icon: icon/niu.jpeg
url: example.com
tags:
- only_example
deployTo:
runtimeCluster: false
这里就是描述了这个插件的基本信息,这里有一个参数deployTo.runtimeCluster,表示插件是否安装到子集群当中,当该字段被设置为 true,应用中的资源会被下发到子集群当中。
插件目录下面的所有文件最终会渲染成为一个 KubeVela 的 Application 应用,所以 template.yaml 就是用于组成这个应用的框架。
template.yaml
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: redis
namespace: redis
spec:
这个文件就是 KubeVela 在部署应用时使用的 yaml 定义,我这里什么都没有写,只是定义了应用的名称和命名空间,插件在启用的时候会走默认的工作流,将 resources 目录中定义的 k8s 资源部署到 KubeVela 的集群中。
Step 2:启用插件
在服务器上克隆代码,使用命令启用插件::
vela addon enable
启用成功之后能通过命令查看刚刚引入的 addon:
这里的 addon 名称就是在 metadata.yaml 定义的name, 使用命令查看 application,可以看到自定义的应用:
使用 kubectl 工具查看 K8S 资源,可以看到部署的情况:
启用这个 addon,KubeVela 就将 addon 代码中定义的一些 k8s 资源 渲染成 KubeVela 应用并创建,这就是 addon 的运行机制。
#3 说在最后
addon 部署应用一般用于给集群带来一些只需要部署一次的应用,比如 KubeVela 的 UX,或者一些通用的中间件等。
但是在实际使用中,通常用户有着不一样的需求,比如在部署服务 A 时,需要一个定制参数的中间件。在部署服务B时,需要不同的工作流节点。在这种场景下,就可以通过 addon 带来模块定义,在部署应用的时候选择不同的组件类型,不同的工作流节点类型。
关于如何使用 addon 扩展 KubeVela 模块,这里留一个悬念,我们下篇文章再见!