Version: v1.2
自定义组件入门
在阅读本部分之前,请确保你已经了解 KubeVela 中 组件定义(ComponentDefinition 的概念且学习掌握了 CUE 的基本知识
本节将以组件定义的例子展开说明,介绍如何使用 CUE 通过组件定义 ComponentDefinition 来自定义应用部署计划的组件。
交付一个简单的自定义组件
我们可以通过 vela def init 来根据已有的 YAML 文件来生成一个 ComponentDefinition 模板。
YAML 文件:
apiVersion: "apps/v1"kind: "Deployment"spec:selector:matchLabels:"app.oam.dev/component": "name"template:metadata:labels:"app.oam.dev/component": "name"spec:containers:- name: "name"image: "image"
根据以上的 YAML 来生成 ComponentDefinition:
vela def init stateless -t component --template-yaml ./stateless.yaml -o stateless.cue
得到如下结果:
$ cat stateless.cuestateless: {annotations: {}attributes: workload: definition: {apiVersion: "<change me> apps/v1"kind: "<change me> Deployment"}description: ""labels: {}type: "component"}template: {output: {spec: {selector: matchLabels: "app.oam.dev/component": "name"template: {metadata: labels: "app.oam.dev/component": "name"spec: containers: [{name: "name"image: "image"}]}}apiVersion: "apps/v1"kind: "Deployment"}outputs: {}parameters: {}}
在这个自动生成的模板中:
- 需要
.spec.workload来指示该组件的工作负载类型。 .spec.schematic.cue.template是一个 CUE 模板:output字段定义了 CUE 要输出的抽象模板。parameter字段定义了模板参数,即在应用部署计划(Application)中公开的可配置属性(KubeVela 将基于parameter字段自动生成 Json schema)。
下面我们来给这个自动生成的自定义组件添加参数并进行赋值:
stateless: {annotations: {}attributes: workload: definition: {apiVersion: "<change me> apps/v1"kind: "<change me> Deployment"}description: ""labels: {}type: "component"}template: {output: {spec: {selector: matchLabels: "app.oam.dev/component": parameter.nametemplate: {metadata: labels: "app.oam.dev/component": parameter.namespec: containers: [{name: parameter.nameimage: parameter.image}]}}apiVersion: "apps/v1"kind: "Deployment"}outputs: {}parameters: {name: stringimage: string}}
修改后可以用 vela def vet 做一下格式检查和校验。
$ vela def vet stateless.cueValidation succeed.
接着,让我们声明另一个名为 task 的组件。
vela def init task -t component -o task.cue
得到如下结果:
$ cat task.cuetask: {annotations: {}attributes: workload: definition: {apiVersion: "<change me> apps/v1"kind: "<change me> Deployment"}description: ""labels: {}type: "component"}template: {output: {}parameter: {}}
修改该组件定义:
task: {annotations: {}attributes: workload: definition: {apiVersion: "batch/v1"kind: "Job"}description: ""labels: {}type: "component"}template: {output: {apiVersion: "batch/v1"kind: "Job"spec: {parallelism: parameter.countcompletions: parameter.counttemplate: spec: {restartPolicy: parameter.restartcontainers: [{image: parameter.imageif parameter["cmd"] != _|_ {command: parameter.cmd}}]}}}parameter: {count: *1 | intimage: stringrestart: *"Never" | stringcmd?: [...string]}}
将以上两个组件定义部署到集群中:
$ vela def apply stateless.cueComponentDefinition stateless created in namespace vela-system.$ vela def apply task.cueComponentDefinition task created in namespace vela-system.
这两个已经定义好的组件,最终会在应用部署计划中实例化,我们引用自定义的组件类型 stateless,命名为 hello。同样,我们也引用了自定义的第二个组件类型 task,并命令为 countdown。
然后把它们编写到应用部署计划中,如下所示:
apiVersion: core.oam.dev/v1alpha2kind: Applicationmetadata:name: websitespec:components:- name: hellotype: statelessproperties:image: crccheck/hello-worldname: mysvc- name: countdowntype: taskproperties:image: centos:7cmd:- "bin/bash"- "-c"- "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
以上,我们就完成了一个自定义应用组件的应用交付全过程。值得注意的是,作为管理员的我们,可以通过 CUE 提供用户所需要的任何自定义组件类型,同时也为用户提供了模板参数 parameter 来灵活地指定对 Kubernetes 相关资源的要求。
查看 Kubernetes 最终资源信息
apiVersion: apps/v1kind: Deploymentmetadata:name: backend... # 隐藏一些与本小节讲解无关的信息spec:template:spec:containers:- name: mysvcimage: crccheck/hello-worldmetadata:labels:app.oam.dev/component: mysvcselector:matchLabels:app.oam.dev/component: mysvc---apiVersion: batch/v1kind: Jobmetadata:name: countdown... # 隐藏一些与本小节讲解无关的信息spec:parallelism: 1completions: 1template:metadata:name: countdownspec:containers:- name: countdownimage: 'centos:7'command:- bin/bash- '-c'- for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; donerestartPolicy: Never
交付一个复合的自定义组件
除了上面这个例子外,一个组件的定义通常也会由多个 Kubernetes API 资源组成。例如,一个由 Deployment 和 Service 组成的 webserver 组件。CUE 同样能很好的满足这种自定义复合组件的需求。
我们会使用 output 这个字段来定义工作负载类型的模板,而其他剩下的资源模板,都在 outputs 这个字段里进行声明,格式如下:
outputs: <unique-name>:<full template data>
回到 webserver 这个复合自定义组件上,它的 CUE 文件编写如下:
webserver: {annotations: {}attributes: workload: definition: {apiVersion: "apps/v1"kind: "Deployment"}description: ""labels: {}type: "component"}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}}}]}}}}// an extra templateoutputs: service: {apiVersion: "v1"kind: "Service"spec: {selector: {"app.oam.dev/component": context.name}ports: [{port: parameter.porttargetPort: parameter.port},]}}parameter: {image: stringcmd?: [...string]port: *80 | intenv?: [...{name: stringvalue?: stringvalueFrom?: {secretKeyRef: {name: stringkey: string}}}]cpu?: string}}
可以看到:
- 最核心的工作负载,我们按需要在
output字段里,定义了一个要交付的Deployment类型的 Kubernetes 资源。 Service类型的资源,则放到outputs里定义。以此类推,如果你要复合第三个资源,只需要继续在后面以键值对的方式添加:
outputs: service: {apiVersion: "v1"kind: "Service"spec: {...outputs: third-resource: {apiVersion: "v1"kind: "Service"spec: {...
在理解这些之后,将上面的组件定义对象保存到 CUE 文件中,并部署到你的 Kubernetes 集群。
$ vela def apply webserver.cueComponentDefinition webserver created in namespace vela-system.
然后,我们使用它们,来编写一个应用部署计划:
apiVersion: core.oam.dev/v1beta1kind: Applicationmetadata:name: webserver-demonamespace: defaultspec:components:- name: hello-worldtype: webserverproperties:image: crccheck/hello-worldport: 8000env:- name: "foo"value: "bar"cpu: "100m"
进行部署:
$ vela up -f webserver.yaml
最后,它将在运行时集群生成相关 Kubernetes 资源如下:
$ kubectl get deploymentNAME READY UP-TO-DATE AVAILABLE AGEhello-world-v1 1/1 1 1 15s$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEhello-world-trait-7bdcff98f7 ClusterIP <your ip> <none> 8000/TCP 32s
使用 CUE Context
KubeVela 让你可以在运行时,通过 context 关键字来引用一些信息。
最常用的就是应用部署计划的名称 context.appName 和组件的名称 context.name。
context: {appName: stringname: string}
举例来说,假设你在实现一个组件定义,希望将容器的名称填充为组件的名称。那么这样做:
parameter: {image: string}output: {...spec: {containers: [{name: context.nameimage: parameter.image}]}...}
注意,
context的信息会在资源部署到目标集群之前就自动注入了
CUE context 的配置项
| Context 变量名 | 说明 |
|---|---|
context.appRevision | 应用部署计划的版本 |
context.appRevisionNum | 应用部署计划的版本号(int 类型), 比如说如果 context.appRevision 是 app-v1 的话,context.appRevisionNum 会是 1 |
context.appName | 应用部署计划的名称 |
context.name | 组件的名称 |
context.namespace | 应用部署计划的命名空间 |
context.output | 组件中渲染的工作负载 API 资源,这通常用在运维特征里 |
context.outputs.<resourceName> | 组件中渲染的运维特征 API 资源,这通常用在运维特征里 |