Merge pull request #1006 from wonderflow/fixsearch
fix search and refine docs
This commit is contained in:
commit
2d94618b17
|
|
@ -10,7 +10,7 @@ First, generate `ComponentDefinition` scaffolds via `vela def init` with existed
|
|||
|
||||
The YAML file:
|
||||
|
||||
```yaml
|
||||
```yaml title="stateless.yaml"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec:
|
||||
|
|
@ -35,8 +35,7 @@ vela def init stateless -t component --template-yaml ./stateless.yaml -o statele
|
|||
|
||||
It generates a file:
|
||||
|
||||
```cue
|
||||
// $ cat stateless.cue
|
||||
```cue title="stateless.cue"
|
||||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -69,10 +68,11 @@ template: {
|
|||
```
|
||||
|
||||
In detail:
|
||||
- `.spec.workload` is required to indicate the workload type of this component.
|
||||
- `.spec.schematic.cue.template` is a CUE template, specifically:
|
||||
* The `output` filed defines the template for the abstraction.
|
||||
* The `parameter` filed defines the template parameters, i.e. the configurable properties exposed in the `Application`abstraction (and JSON schema will be automatically generated based on them).
|
||||
- The `stateless` is the name of component definition, it can be defined by yourself when initialize the component.
|
||||
- `stateless.attributes.workload` indicates the workload type of this component, it can help integrate with traits that apply to this kind of workload.
|
||||
- `template` is a CUE template, specifically:
|
||||
* The `output` and `outputs` fields define the resources that the component will be composed.
|
||||
* The `parameter` field defines the parameters of the component, i.e. the configurable properties exposed in the `Application` (and schema will be automatically generated based on them for end users to learn this component).
|
||||
|
||||
Add parameters in this auto-generated custom component file :
|
||||
|
||||
|
|
@ -80,8 +80,8 @@ Add parameters in this auto-generated custom component file :
|
|||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "<change me> apps/v1"
|
||||
kind: "<change me> Deployment"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
description: ""
|
||||
labels: {}
|
||||
|
|
@ -114,11 +114,56 @@ template: {
|
|||
You can use `vela def vet` to validate the format:
|
||||
|
||||
```shell
|
||||
$ vela def vet stateless.cue
|
||||
Validation succeed.
|
||||
vela def vet stateless.cue
|
||||
```
|
||||
|
||||
Declare another component named `task` which is an abstraction for run-to-completion workload.
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
Validation succeed.
|
||||
```
|
||||
</details>
|
||||
|
||||
Apply above `ComponentDefinition` to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
vela def apply stateless.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
Then the end user can check the schema and use it in an application now:
|
||||
|
||||
```
|
||||
vela show stateless
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
# Specification
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| name | | string | true | |
|
||||
| image | | string | true | |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
Declare another component named `task` which is an abstraction for run-to-completion workload works the same.
|
||||
|
||||
<details>
|
||||
<summary>Check the details for another example to define a task based component.</summary>
|
||||
|
||||
```shell
|
||||
vela def init task -t component -o task.cue
|
||||
|
|
@ -186,16 +231,17 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
Apply above `ComponentDefinition` files to your Kubernetes cluster:
|
||||
Apply above `ComponentDefinition` files to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
$ vela def apply stateless.cue
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
$ vela def apply task.cue
|
||||
ComponentDefinition task created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
## Declare an `Application`
|
||||
Now let's use the `stateless` and `task` component type.
|
||||
|
||||
## Declare an `Application` using this component
|
||||
|
||||
The `ComponentDefinition` can be instantiated in `Application` abstraction as below:
|
||||
|
||||
|
|
@ -221,8 +267,8 @@ The `ComponentDefinition` can be instantiated in `Application` abstraction as be
|
|||
- "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
|
||||
```
|
||||
|
||||
### Under The Hood
|
||||
<details>
|
||||
<summary> Learn Details Under The Hood </summary>
|
||||
|
||||
Above application resource will generate and manage following Kubernetes resources in your target cluster based on the `output` in CUE template and user input in `Application` properties.
|
||||
|
||||
|
|
@ -268,7 +314,10 @@ spec:
|
|||
```
|
||||
</details>
|
||||
|
||||
## CUE `Context`
|
||||
You can also use [dry run](../debug/dry-run) to show what the yaml results will be rendered for debugging.
|
||||
|
||||
|
||||
## CUE `Context` for runtime information
|
||||
|
||||
KubeVela allows you to reference the runtime information of your application via `context` keyword.
|
||||
|
||||
|
|
@ -299,32 +348,40 @@ output: {
|
|||
}
|
||||
```
|
||||
|
||||
> Note that `context` information are auto-injected before resources are applied to target cluster.
|
||||
:::tip
|
||||
Note that `context` information are auto-injected before resources are applied to target cluster.
|
||||
:::
|
||||
|
||||
### Full available `context` information can be used
|
||||
The list of [all available context variables](#full-available-context-in-component) are listed at last of this doc.
|
||||
|
||||
* Check the reference docs of [definition protocol](../../platform-engineers/oam/x-definition#definition-runtime-context) to see all of the available information in KubeVela `context`.
|
||||
|
||||
## Composition
|
||||
## Compose resources in one component
|
||||
|
||||
It's common that a component definition is composed by multiple API resources, for example, a `webserver` component that is composed by a Deployment and a Service. CUE is a great solution to achieve this in simplified primitives.
|
||||
|
||||
> Another approach to do composition in KubeVela of course is [using Helm](../../tutorials/helm).
|
||||
:::tip
|
||||
Compare to [using Helm](../../tutorials/helm), this approach gives your more flexibility as you can control the abstraction any time and integrate with traits, workflows in KubeVela better.
|
||||
:::
|
||||
|
||||
## How-to
|
||||
|
||||
KubeVela requires you to define the template of workload type in `output` section, and leave all the other resource templates in `outputs` section with format as below:
|
||||
KubeVela requires you to define the template of main workload in `output` section, and leave all the other resource templates in `outputs` section with format as below:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
output: {
|
||||
<template of main workload structural data>
|
||||
}
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of auxiliary resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" like patching annotations/labels or other data during it.
|
||||
:::note
|
||||
The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" by traits such like patching annotations/labels or other data during it.
|
||||
:::
|
||||
|
||||
Below is the example for `webserver` definition:
|
||||
Below is the example for `webserver` definition, let's use a demo to show how to use it:
|
||||
|
||||
```cue
|
||||
```cue title="webserver.cue"
|
||||
webserver: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -420,13 +477,20 @@ template: {
|
|||
Apply to your Kubernetes cluster:
|
||||
|
||||
```shell
|
||||
$ vela def apply webserver.cue
|
||||
vela def apply webserver.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition webserver created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
The user could now declare an `Application` with it:
|
||||
|
||||
```yaml
|
||||
```yaml title="webserver-app.yaml"
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
|
|
@ -434,7 +498,7 @@ metadata:
|
|||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world
|
||||
- name: hello-webserver
|
||||
type: webserver
|
||||
properties:
|
||||
image: oamdev/hello-world
|
||||
|
|
@ -445,26 +509,196 @@ spec:
|
|||
cpu: "100m"
|
||||
```
|
||||
|
||||
It will generate and manage below Kubernetes API resources in target cluster, you can use [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) to check:
|
||||
Create this application by:
|
||||
|
||||
```
|
||||
vela up -f webserver-app.yaml
|
||||
```
|
||||
|
||||
Then you can check the resources and find the results:
|
||||
|
||||
```shell
|
||||
kubectl get deployment
|
||||
vela status webserver-demo --tree --detail
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```console
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
hello-world-v1 1/1 1 1 15s
|
||||
CLUSTER NAMESPACE RESOURCE STATUS APPLY_TIME DETAIL
|
||||
local ─── default ─┬─ Service/hello-webserver-auxiliaryworkload-685d98b6d9 updated 2022-10-15 21:58:35 Type: ClusterIP
|
||||
│ Cluster-IP: 10.43.255.55
|
||||
│ External-IP: <none>
|
||||
│ Port(s): 8000/TCP
|
||||
│ Age: 66s
|
||||
└─ Deployment/hello-webserver updated 2022-10-15 21:58:35 Ready: 1/1 Up-to-date: 1
|
||||
Available: 1 Age: 66s
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## Define health check and status message for component
|
||||
|
||||
You can also define health check policy and status message when a component deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health check
|
||||
|
||||
The spec of health check is `<component-type-name>.attributes.status.healthPolicy`.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the component is healthy or not.
|
||||
|
||||
The keyword is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl get svc
|
||||
```
|
||||
```console
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hello-world-trait-7bdcff98f7 ClusterIP <your ip> <none> 8000/TCP 32s
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What's Next
|
||||
The health check result will be recorded into the corresponding component in `.status.services` of `Application` resource.
|
||||
|
||||
* Learn more about [defining customized trait](../traits/customize-trait) in CUE.
|
||||
* Learn how to [define health check and custom status](../traits/status) of Component.
|
||||
* Learn how to [define policy](../policy/custom-policy) in CUE.
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
name: myweb
|
||||
...
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<component-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE expression is `message`, the result must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
ready: {
|
||||
readyReplicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding component in `.status.services` of `Application` resource like below.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: false
|
||||
message: Ready:1/1
|
||||
name: express-server
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
| `context.replicaKey` | The key of replication in context. Replication is an internal policy, it will replicate resources with different keys specified. (This feature will be introduced in v1.6+.) | string |
|
||||
|
||||
|
||||
## Component definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The component definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: <ComponentDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <Function description>
|
||||
spec:
|
||||
workload: # Workload Capability Indicator
|
||||
definition:
|
||||
apiVersion: <Kubernetes Workload resource group>
|
||||
kind: <Kubernetes Workload types>
|
||||
schematic: # Component description
|
||||
cue: # Details of components defined by CUE language
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin component definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/component).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -4,9 +4,13 @@ title: Trait Definition
|
|||
|
||||
In this section we will introduce how to define a custom trait with CUE. Make sure you've learned the basic knowledge about [Definition Concept](../../getting-started/definition) and [how to manage definition](../cue/definition-edit).
|
||||
|
||||
## Generate Resources by Trait
|
||||
## Generate a Trait scaffold
|
||||
|
||||
A trait can be something similar to component that you can define operational Kubernetes API resources such as ingress, service as trait.
|
||||
A trait can be something similar to component, while they're attached operational resources.
|
||||
|
||||
- Kubernetes API resources like ingress, service, rollout.
|
||||
- The composition of these operational resources.
|
||||
- A patch of data, for example, patch sidecar to workload.
|
||||
|
||||
Let's use `vela def init` to create a basic trait scaffold:
|
||||
|
||||
|
|
@ -14,8 +18,6 @@ Let's use `vela def init` to create a basic trait scaffold:
|
|||
vela def init my-route -t trait --desc "My ingress route trait." > myroute.cue
|
||||
```
|
||||
|
||||
> Note: there's a bug in vela CLI(`<=1.4.2`), the `vela def init` command will generate `definitionRef: ""` in `attributes` which is wrong, please remove that line.
|
||||
|
||||
The content of the scaffold expected to be:
|
||||
|
||||
```cue
|
||||
|
|
@ -39,13 +41,26 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
There's a bug in vela CLI(`<=1.4.2`), the `vela def init` command will generate `definitionRef: ""` in `attributes` which is wrong, please remove that line.
|
||||
:::
|
||||
|
||||
## Define a trait to compose resources
|
||||
|
||||
Unlike component definition, KubeVela requires objects in traits **MUST** be defined in `outputs` section (not `output`) in CUE template with format as below:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of trait resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
Actually the CUE template of trait here will be evaluated with component CUE template in the same context, so the name can't be conflict. That also explain why the `output` can't be defined in trait.
|
||||
:::
|
||||
|
||||
Below is an example that we combine `ingress` and `service` of Kubernetes into our `my-route` trait.
|
||||
|
||||
```cue
|
||||
|
|
@ -152,7 +167,9 @@ With the help of CUE, we can achieve many advanced features in trait.
|
|||
|
||||
You can define the for-loop inside the `outputs`.
|
||||
|
||||
> Note that in this case the type of `parameter` field used in the for-loop must be a map.
|
||||
:::note
|
||||
In this case the type of `parameter` field used in the for-loop must be a map.
|
||||
:::
|
||||
|
||||
Below is an example that will render multiple Kubernetes Services in one trait:
|
||||
|
||||
|
|
@ -211,7 +228,9 @@ The trait definition can send a HTTP request and capture the response to help yo
|
|||
|
||||
You can define HTTP request `method`, `url`, `body`, `header` and `trailer` in the `processing.http` section, and the returned data will be stored in `processing.output`.
|
||||
|
||||
> Please ensure the target HTTP server returns a **JSON data**. `output`.
|
||||
:::tip
|
||||
Please ensure the target HTTP server returns a **JSON data** as `output`.
|
||||
:::
|
||||
|
||||
Then you can reference the returned data from `processing.output` in `patch` or `output/outputs`.
|
||||
|
||||
|
|
@ -251,11 +270,13 @@ template: {
|
|||
|
||||
In above example, this trait definition will send request to get the `token` data, and then patch the data to given component instance.
|
||||
|
||||
## Get context data of Component parameters
|
||||
## CUE `Context` for runtime information
|
||||
|
||||
A trait definition can read the generated resources (rendered from `output` and `outputs`) of given component definition.
|
||||
|
||||
>KubeVela will ensure the component definitions are always evaluated before its traits.
|
||||
:::caution
|
||||
Generally, KubeVela will ensure the component definitions are evaluated before its traits. But there're a [stage mechanism](https://github.com/kubevela/kubevela/pull/4570) that allow trait be deployed before component.
|
||||
:::
|
||||
|
||||
Specifically, the `context.output` contains the rendered workload API resource (whose GVK is indicated by `spec.workload`in component definition), and use `context.outputs.<xx>` to contain all the other rendered API resources.
|
||||
|
||||
|
|
@ -399,8 +420,187 @@ There're several reasons:
|
|||
|
||||
So KubeVela allow patch or override in this case, please refer to [patch trait](./patch-trait) for more details. As trait and workflow step can both patch, so we write them together.
|
||||
|
||||
## What's Next
|
||||
## Define Health for Definition
|
||||
|
||||
* Learn how to [define policy](../policy/custom-policy) in CUE.
|
||||
* Learn how to [define health check and custom status](../traits/status) of Trait.
|
||||
* Learn how to [define workflow step](../workflow/workflow) in CUE.
|
||||
You can also define health check policy and status message when a trait deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health Check
|
||||
|
||||
The spec of health check is `<trait-type-name>.attributes.status.healthPolicy`, it's similar to component definition.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the trait is healthy or not.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
my-ingress: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The health check result will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<trait-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
my-service: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
if context.outputs.ingress.status.loadBalancer.ingress != _|_ {
|
||||
let igs = context.outputs.ingress.status.loadBalancer.ingress
|
||||
if igs[0].ip != _|_ {
|
||||
if igs[0].host != _|_ {
|
||||
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
|
||||
}
|
||||
if igs[0].host == _|_ {
|
||||
message: "Host not specified, visit the cluster or load balancer in front of the cluster with IP: " + igs[0].ip
|
||||
}
|
||||
}
|
||||
}
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
|
||||
|
||||
## Trait definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The trait definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: <TraitDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <function description>
|
||||
spec:
|
||||
definition:
|
||||
apiVersion: <corresponding Kubernetes resource group>
|
||||
kind: <corresponding Kubernetes resource type>
|
||||
workloadRefPath: <The path to the reference field of the Workload object in the Trait>
|
||||
podDisruptive: <whether the parameter update of Trait cause the underlying resource (pod) to restart>
|
||||
manageWorkload: <Whether the workload is managed by this Trait>
|
||||
skipRevisionAffect: <Whether this Trait is not included in the calculation of version changes>
|
||||
appliesToWorkloads:
|
||||
- <Workload that TraitDefinition can adapt to>
|
||||
conflictsWith:
|
||||
- <other Traits that conflict with this><>
|
||||
revisionEnabled: <whether Trait is aware of changes in component version>
|
||||
controlPlaneOnly: <Whether resources generated by trait are dispatched to the hubcluster (local)>
|
||||
schematic: # Abstract
|
||||
cue: # There are many abstracts
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin trait definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/trait).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -2,140 +2,4 @@
|
|||
title: Define Health for Definition
|
||||
---
|
||||
|
||||
This documentation will explain how to achieve status write back by using CUE templates in definition objects.
|
||||
|
||||
## Health Check
|
||||
|
||||
The spec of health check is `spec.status.healthPolicy`, they are the same for both Workload Type and Trait.
|
||||
|
||||
If not defined, the health result will always be `true`.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the context field.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Trait will not have the `context.output`, other fields are the same.
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
spec:
|
||||
status:
|
||||
healthPolicy: |
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
...
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
spec:
|
||||
status:
|
||||
healthPolicy: |
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
...
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/docs/examples/app-with-status/template.yaml) for the complete example.
|
||||
|
||||
The health check result will be recorded into the `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
components:
|
||||
- name: myweb
|
||||
type: worker
|
||||
properties:
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
enemies: alien
|
||||
image: busybox
|
||||
lives: "3"
|
||||
traits:
|
||||
- type: ingress
|
||||
properties:
|
||||
domain: www.example.com
|
||||
http:
|
||||
/: 80
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
message: "type: busybox,\t enemies:alien"
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
## Custom Status
|
||||
|
||||
The spec of custom status is `spec.status.customStatus`, they are the same for both Workload Type and Trait.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
The custom status has the same mechanism with health check.
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Trait will not have the `context.output`, other fields are the same.
|
||||
|
||||
|
||||
Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/docs/examples/app-with-status/template.yaml) for the complete example.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
spec:
|
||||
status:
|
||||
customStatus: |-
|
||||
message: "type: " + context.output.spec.template.spec.containers[0].image + ",\t enemies:" + context.outputs.gameconfig.data.enemies
|
||||
...
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
spec:
|
||||
status:
|
||||
customStatus: |-
|
||||
message: "type: "+ context.outputs.service.spec.type +",\t clusterIP:"+ context.outputs.service.spec.clusterIP+",\t ports:"+ "\(context.outputs.service.spec.ports[0].port)"+",\t domain"+context.outputs.ingress.spec.rules[0].host
|
||||
...
|
||||
```
|
||||
|
||||
## Next Step
|
||||
|
||||
* Learn how to [define custom workflow](../workflow/workflow) with CUE.
|
||||
This documentation has been merged into [component](../components/custom-component) and [trait](customize-trait).
|
||||
|
|
@ -32,6 +32,7 @@ module.exports = {
|
|||
appId: 'PXMFHFWUGZ',
|
||||
apiKey: '2d1f4924c15d2cc0947820c01e65521f',
|
||||
indexName: 'kubevela',
|
||||
contextualSearch: false,
|
||||
},
|
||||
navbar: {
|
||||
title: 'KubeVela',
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
title: 自定义组件
|
||||
---
|
||||
|
||||
> 在阅读本部分之前,请确保你已经了解 KubeVela 中 [组件定义(ComponentDefinition)](../oam/x-definition#组件定义(ComponentDefinition)) 的概念且学习掌握了 [CUE 的基本知识](../cue/basic)
|
||||
:::tip
|
||||
在阅读本部分之前,请确保你已经了解 KubeVela 中 [组件定义(ComponentDefinition)](../oam/x-definition#组件定义(ComponentDefinition)) 的概念且学习掌握了 [CUE 的基本知识](../cue/basic)
|
||||
:::
|
||||
|
||||
本节将以组件定义的例子展开说明,介绍如何使用 [CUE](../cue/basic) 通过组件定义 `ComponentDefinition` 来自定义应用部署计划的组件。
|
||||
|
||||
### 交付一个简单的自定义组件
|
||||
## 交付一个简单的自定义组件
|
||||
|
||||
我们可以通过 `vela def init` 来根据已有的 YAML 文件来生成一个 `ComponentDefinition` 模板。
|
||||
|
||||
|
|
@ -37,8 +39,7 @@ vela def init stateless -t component --template-yaml ./stateless.yaml -o statele
|
|||
|
||||
得到如下结果:
|
||||
|
||||
```shell
|
||||
$ cat stateless.cue
|
||||
```shell title="stateless.cue"
|
||||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -71,10 +72,11 @@ template: {
|
|||
```
|
||||
|
||||
在这个自动生成的模板中:
|
||||
- 需要 `.spec.workload` 来指示该组件的工作负载类型。
|
||||
- `.spec.schematic.cue.template` 是一个 CUE 模板:
|
||||
* `output` 字段定义了 CUE 要输出的抽象模板。
|
||||
* `parameter` 字段定义了模板参数,即在应用部署计划(Application)中公开的可配置属性(KubeVela 将基于 `parameter` 字段自动生成 Json schema)。
|
||||
- The `stateless` is the name of component definition, it can be defined by yourself when initialize the component.
|
||||
- `stateless.attributes.workload` indicates the workload type of this component, it can help integrate with traits that apply to this kind of workload.
|
||||
- `template` is a CUE template, specifically:
|
||||
* The `output` and `outputs` fields define the resources that the component will be composed.
|
||||
* The `parameter` field defines the parameters of the component, i.e. the configurable properties exposed in the `Application` (and schema will be automatically generated based on them for end users to learn this component).
|
||||
|
||||
下面我们来给这个自动生成的自定义组件添加参数并进行赋值:
|
||||
|
||||
|
|
@ -82,8 +84,8 @@ template: {
|
|||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "<change me> apps/v1"
|
||||
kind: "<change me> Deployment"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
description: ""
|
||||
labels: {}
|
||||
|
|
@ -106,7 +108,7 @@ template: {
|
|||
kind: "Deployment"
|
||||
}
|
||||
outputs: {}
|
||||
parameters: {
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
}
|
||||
|
|
@ -116,11 +118,56 @@ template: {
|
|||
修改后可以用 `vela def vet` 做一下格式检查和校验。
|
||||
|
||||
```shell
|
||||
$ vela def vet stateless.cue
|
||||
Validation succeed.
|
||||
vela def vet stateless.cue
|
||||
```
|
||||
|
||||
接着,让我们声明另一个名为 `task` 的组件。
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
```
|
||||
Validation succeed.
|
||||
```
|
||||
</details>
|
||||
|
||||
Apply above `ComponentDefinition` to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
vela def apply stateless.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
Then the end user can check the schema and use it in an application now:
|
||||
|
||||
```
|
||||
vela show stateless
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
# Specification
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| name | | string | true | |
|
||||
| image | | string | true | |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
接着,让我们声明另一个名为 `task` 的组件,其原理类似。
|
||||
|
||||
<details>
|
||||
<summary>点击查看声明 task 组件的创建过程。</summary>
|
||||
|
||||
```shell
|
||||
vela def init task -t component -o task.cue
|
||||
|
|
@ -191,12 +238,12 @@ template: {
|
|||
将以上两个组件定义部署到集群中:
|
||||
|
||||
```shell
|
||||
$ vela def apply stateless.cue
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
$ vela def apply task.cue
|
||||
ComponentDefinition task created in namespace vela-system.
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
这两个已经定义好的组件,最终会在应用部署计划中实例化,我们引用自定义的组件类型 `stateless`,命名为 `hello`。同样,我们也引用了自定义的第二个组件类型 `task`,并命令为 `countdown`。
|
||||
|
||||
然后把它们编写到应用部署计划中,如下所示:
|
||||
|
|
@ -225,9 +272,10 @@ ComponentDefinition task created in namespace vela-system.
|
|||
|
||||
以上,我们就完成了一个自定义应用组件的应用交付全过程。值得注意的是,作为管理员的我们,可以通过 CUE 提供用户所需要的任何自定义组件类型,同时也为用户提供了模板参数 `parameter` 来灵活地指定对 Kubernetes 相关资源的要求。
|
||||
|
||||
#### 查看 Kubernetes 最终资源信息
|
||||
<details>
|
||||
|
||||
<summary> 了解背后的 Kubernetes 最终资源信息 </summary>
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
|
|
@ -268,23 +316,79 @@ spec:
|
|||
- for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
You can also use [dry run](../debug/dry-run) to show what the yaml results will be rendered for debugging.
|
||||
|
||||
### 交付一个复合的自定义组件
|
||||
|
||||
## 使用 CUE `Context` 获取运行时信息
|
||||
|
||||
KubeVela 让你可以在运行时,通过 `context` 关键字来引用一些信息。
|
||||
|
||||
最常用的就是应用部署计划的名称 `context.appName` 和组件的名称 `context.name`。
|
||||
|
||||
```cue
|
||||
context: {
|
||||
appName: string
|
||||
name: string
|
||||
}
|
||||
```
|
||||
|
||||
举例来说,假设你在实现一个组件定义,希望将容器的名称填充为组件的名称。那么这样做:
|
||||
|
||||
```cue
|
||||
parameter: {
|
||||
image: string
|
||||
}
|
||||
output: {
|
||||
...
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
}]
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
注意 `context` 的信息会在资源部署到目标集群之前就自动注入了。
|
||||
:::
|
||||
|
||||
|
||||
在本文的最后列出了完整的 context 变量列表。
|
||||
|
||||
|
||||
## 交付一个复合的自定义组件
|
||||
|
||||
除了上面这个例子外,一个组件的定义通常也会由多个 Kubernetes API 资源组成。例如,一个由 `Deployment` 和 `Service` 组成的 `webserver` 组件。CUE 同样能很好的满足这种自定义复合组件的需求。
|
||||
|
||||
:::tip
|
||||
Compare to [using Helm](../../tutorials/helm), this approach gives your more flexibility as you can control the abstraction any time and integrate with traits, workflows in KubeVela better.
|
||||
:::
|
||||
|
||||
我们会使用 `output` 这个字段来定义工作负载类型的模板,而其他剩下的资源模板,都在 `outputs` 这个字段里进行声明,格式如下:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
output: {
|
||||
<template of main workload structural data>
|
||||
}
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of auxiliary resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" by traits such like patching annotations/labels or other data during it.
|
||||
:::
|
||||
|
||||
回到 `webserver` 这个复合自定义组件上,它的 CUE 文件编写如下:
|
||||
|
||||
```
|
||||
``` title="webserver.cue"
|
||||
webserver: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -396,10 +500,18 @@ outputs: third-resource: {
|
|||
|
||||
在理解这些之后,将上面的组件定义对象保存到 CUE 文件中,并部署到你的 Kubernetes 集群。
|
||||
|
||||
|
||||
```shell
|
||||
$ vela def apply webserver.cue
|
||||
vela def apply webserver.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition webserver created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
然后,我们使用它们,来编写一个应用部署计划:
|
||||
|
||||
|
|
@ -423,59 +535,194 @@ spec:
|
|||
```
|
||||
|
||||
进行部署:
|
||||
|
||||
```
|
||||
$ vela up -f webserver.yaml
|
||||
```
|
||||
|
||||
最后,它将在运行时集群生成相关 Kubernetes 资源如下:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployment
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
hello-world-v1 1/1 1 1 15s
|
||||
|
||||
$ kubectl get svc
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hello-world-trait-7bdcff98f7 ClusterIP <your ip> <none> 8000/TCP 32s
|
||||
vela status webserver-demo --tree --detail
|
||||
```
|
||||
|
||||
## 使用 CUE `Context`
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
KubeVela 让你可以在运行时,通过 `context` 关键字来引用一些信息。
|
||||
```console
|
||||
CLUSTER NAMESPACE RESOURCE STATUS APPLY_TIME DETAIL
|
||||
local ─── default ─┬─ Service/hello-webserver-auxiliaryworkload-685d98b6d9 updated 2022-10-15 21:58:35 Type: ClusterIP
|
||||
│ Cluster-IP: 10.43.255.55
|
||||
│ External-IP: <none>
|
||||
│ Port(s): 8000/TCP
|
||||
│ Age: 66s
|
||||
└─ Deployment/hello-webserver updated 2022-10-15 21:58:35 Ready: 1/1 Up-to-date: 1
|
||||
Available: 1 Age: 66s
|
||||
```
|
||||
</details>
|
||||
|
||||
最常用的就是应用部署计划的名称 `context.appName` 和组件的名称 `context.name`。
|
||||
|
||||
## 自定义健康检查和状态
|
||||
|
||||
You can also define health check policy and status message when a component deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### 健康检查
|
||||
|
||||
The spec of health check is `<component-type-name>.attributes.status.healthPolicy`.
|
||||
|
||||
如果没有定义,它的值默认是 `true`,意味着在部署完对象后就将对象的状态设置为健康。为了让组件的状态及时、准确,通常你需要为组件定义监控状态,这个过程可以通过一个 CUE 表达式完成。
|
||||
|
||||
在 CUE 里的关键词是 `isHealth`,CUE 表达式结果必须是 `bool` 类型。
|
||||
KubeVela 运行时会一直检查 CUE 表达式,直至其状态显示为健康。每次控制器都会获取所有的 Kubernetes 资源,并将他们填充到 `context` 字段中。
|
||||
|
||||
所以 context 字段会包含如下信息:
|
||||
|
||||
```cue
|
||||
context: {
|
||||
appName: string
|
||||
name: string
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <Kubernetes workload resource>
|
||||
outputs: {
|
||||
<resource1>: <Kubernetes trait resource1>
|
||||
<resource2>: <Kubernetes trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
举例来说,假设你在实现一个组件定义,希望将容器的名称填充为组件的名称。那么这样做:
|
||||
我们看看健康检查的例子:
|
||||
|
||||
```cue
|
||||
parameter: {
|
||||
image: string
|
||||
}
|
||||
output: {
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
}]
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
"""#
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意,`context` 的信息会在资源部署到目标集群之前就自动注入了
|
||||
The health check result will be recorded into the corresponding component in `.status.services` of `Application` resource.
|
||||
|
||||
### CUE `context` 的配置项
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
name: myweb
|
||||
...
|
||||
status: running
|
||||
```
|
||||
|
||||
* 你可以通过查看[模块定义的完整协议](../../platform-engineers/oam/x-definition#definition-runtime-context)来了解全部的 `context` 运行时变量.
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
## 下一步
|
||||
### 自定义状态
|
||||
|
||||
* 了解如何基于 CUE [自定义运维特征](../traits/customize-trait)。
|
||||
* 了解如何为组件和运维特征模块[定义健康状态](../traits/status)。
|
||||
The spec of custom status is `<component-type-name>.attributes.status.customStatus`, 自定义状态和健康检查的原理一致。
|
||||
|
||||
在 CUE 中的关键词是 `message`。同时,CUE 表达式的结果必须是 `string` 类型。
|
||||
|
||||
`Application` 对象的 CRD 控制器都会检查 CUE 表达式,直至显示健康通过。
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
ready: {
|
||||
readyReplicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding component in `.status.services` of `Application` resource like below.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: false
|
||||
message: Ready:1/1
|
||||
name: express-server
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
| `context.replicaKey` | The key of replication in context. Replication is an internal policy, it will replicate resources with different keys specified. (This feature will be introduced in v1.6+.) | string |
|
||||
|
||||
|
||||
## Component definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The component definition will be in the following API format:
|
||||
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: <ComponentDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <Function description>
|
||||
spec:
|
||||
workload: # Workload Capability Indicator
|
||||
definition:
|
||||
apiVersion: <Kubernetes Workload resource group>
|
||||
kind: <Kubernetes Workload types>
|
||||
schematic: # Component description
|
||||
cue: # Details of components defined by CUE language
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin component definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/component).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -7,7 +7,11 @@ title: 自定义运维特征
|
|||
|
||||
## 通过 Trait 生成资源对象
|
||||
|
||||
通过 Trait 生成资源的用法和 Component 基本类似,这种场景通常用于生成运维的对象,比如用于服务访问的 Ingress、Service,或者用于扩缩容的 HPA 等对象。
|
||||
通过 Trait 生成资源的用法和 Component 基本类似,有如下场景:
|
||||
|
||||
- 用于生成运维的资源对象,比如用于服务访问的 Ingress、Service,或者用于扩缩容的 HPA 等对象。
|
||||
- 用于上述运维对象的多种组合。
|
||||
- 用于对组件配置的补丁,如增加一个边车容器做日志收集等。
|
||||
|
||||
同样的,我们使用 `vela def init`命令来生成一个框架:
|
||||
|
||||
|
|
@ -15,8 +19,6 @@ title: 自定义运维特征
|
|||
vela def init my-route -t trait --desc "My ingress route trait." > myroute.cue
|
||||
```
|
||||
|
||||
> 注意: 在 vela CLI(`<=1.4.2`)的版本中有一个已知问题,`vela def init` 命令会生成一个错误的 `definitionRef: ""` 字段,这一行需要删除。
|
||||
|
||||
期望生成的内容如下:
|
||||
|
||||
```
|
||||
|
|
@ -40,13 +42,25 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
在 vela CLI(`<=1.4.2`)的版本中有一个已知问题,`vela def init` 命令会生成一个错误的 `definitionRef: ""` 字段,这一行需要删除。
|
||||
:::
|
||||
|
||||
|
||||
与组件定义有所不同,在用法上,你需要把所有的运维特征定义在 `outputs` 里(注意,不是 `output`),格式如下:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of trait resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
Actually the CUE template of trait here will be evaluated with component CUE template in the same context, so the name can't be conflict. That also explain why the `output` can't be defined in trait.
|
||||
:::
|
||||
|
||||
我们下面使用一个 `ingress` 和 `Service` 组成一个称为 `my-route` 的运维特征作为示例讲解:
|
||||
|
||||
```cue
|
||||
|
|
@ -151,7 +165,9 @@ EOF
|
|||
|
||||
你可以在 `outputs` 里定义 For 循环。
|
||||
|
||||
> 注意在 For 循环里的 `parameter` 字段必须是 map 类型。
|
||||
:::note
|
||||
注意在 For 循环里的 `parameter` 字段必须是 map 类型。
|
||||
:::
|
||||
|
||||
看看如下这个例子,在一个 `TraitDefinition` 对象里渲染多个 `Service`:
|
||||
|
||||
|
|
@ -210,7 +226,9 @@ spec:
|
|||
|
||||
你可以在 `processing.http` 里定义 HTTP 请求的 `method`, `url`, `body`, `header` 和 `trailer`,然后返回的数据将被存储在 `processing.output` 中。
|
||||
|
||||
> 请确保目标 HTTP 服务器返回的数据是 JSON 格式
|
||||
:::tip
|
||||
请确保目标 HTTP 服务器返回的数据是 JSON 格式才能正确解析到 `output` 字段中。
|
||||
:::
|
||||
|
||||
接着,你就可以通过 `patch` 或者 `output/outputs` 里的 `processing.output` 来引用返回数据了。
|
||||
|
||||
|
|
@ -254,126 +272,132 @@ template: {
|
|||
|
||||
`TraitDefinition` 对象可以读取特定 `ComponentDefinition` 对象生成的 API 资源(渲染自 `output` 和 `outputs`)。
|
||||
|
||||
> KubeVela 保证了 `ComponentDefinition` 一定会在 `TraitDefinition` 之前渲染
|
||||
:::caution
|
||||
Generally, KubeVela will ensure the component definitions are evaluated before its traits. But there're a [stage mechanism](https://github.com/kubevela/kubevela/pull/4570) that allow trait be deployed before component.
|
||||
:::
|
||||
|
||||
|
||||
具体来说,`context.output` 字段包含了所有渲染后的工作负载 API 资源,然后 `context.outputs.<xx>` 则包含渲染后的其它类型 API 资源。
|
||||
|
||||
下面是一个数据传递的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: worker
|
||||
spec:
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
1. Let's define a component definition `myworker` like below:
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
ports: [{containerPort: parameter.port}]
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```cue
|
||||
"myworker": {
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
type: "component"
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
template: {
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
port: int
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
ports: [{containerPort: parameter.port}]
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: ingress
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
path: string
|
||||
exposePort: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [{
|
||||
port: parameter.exposePort
|
||||
targetPort: context.output.spec.template.spec.containers[0].ports[0].containerPort
|
||||
}]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
labels: config: context.outputs.gameconfig.data.enemies
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [{
|
||||
path: parameter.path
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: parameter.exposePort
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
port: int
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Define a new `myingress` trait that read the port.
|
||||
|
||||
```cue
|
||||
"myingress": {
|
||||
type: "trait"
|
||||
attributes: {
|
||||
appliesToWorkloads: ["myworker"]
|
||||
}
|
||||
}
|
||||
|
||||
template: {
|
||||
parameter: {
|
||||
domain: string
|
||||
path: string
|
||||
exposePort: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [{
|
||||
port: parameter.exposePort
|
||||
targetPort: context.output.spec.template.spec.containers[0].ports[0].containerPort
|
||||
}]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
labels: config: context.outputs.gameconfig.data.enemies
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [{
|
||||
path: parameter.path
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: parameter.exposePort
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在渲染 `worker` `ComponentDefinition` 时,具体发生了:
|
||||
|
|
@ -393,7 +417,187 @@ spec:
|
|||
|
||||
针对上述场景,KubeVela 通过 patch 功能来支撑,因为 Patch 的能力针对 Trait 和 Workflow 均适用,我们通过[这篇 Patch 文档](./patch-trait)统一介绍。
|
||||
|
||||
## 下一步
|
||||
## Define Health for Definition
|
||||
|
||||
* 了解组件和运维特征如何[定义健康状态](../traits/status)。
|
||||
* 了解如何通过 CUE [定义工作流步骤](../workflow/workflow)。
|
||||
You can also define health check policy and status message when a trait deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health Check
|
||||
|
||||
The spec of health check is `<trait-type-name>.attributes.status.healthPolicy`, it's similar to component definition.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the trait is healthy or not.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
my-ingress: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The health check result will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<trait-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
my-service: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
if context.outputs.ingress.status.loadBalancer.ingress != _|_ {
|
||||
let igs = context.outputs.ingress.status.loadBalancer.ingress
|
||||
if igs[0].ip != _|_ {
|
||||
if igs[0].host != _|_ {
|
||||
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
|
||||
}
|
||||
if igs[0].host == _|_ {
|
||||
message: "Host not specified, visit the cluster or load balancer in front of the cluster with IP: " + igs[0].ip
|
||||
}
|
||||
}
|
||||
}
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
|
||||
|
||||
## Trait definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The trait definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: <TraitDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <function description>
|
||||
spec:
|
||||
definition:
|
||||
apiVersion: <corresponding Kubernetes resource group>
|
||||
kind: <corresponding Kubernetes resource type>
|
||||
workloadRefPath: <The path to the reference field of the Workload object in the Trait>
|
||||
podDisruptive: <whether the parameter update of Trait cause the underlying resource (pod) to restart>
|
||||
manageWorkload: <Whether the workload is managed by this Trait>
|
||||
skipRevisionAffect: <Whether this Trait is not included in the calculation of version changes>
|
||||
appliesToWorkloads:
|
||||
- <Workload that TraitDefinition can adapt to>
|
||||
conflictsWith:
|
||||
- <other Traits that conflict with this><>
|
||||
revisionEnabled: <whether Trait is aware of changes in component version>
|
||||
controlPlaneOnly: <Whether resources generated by trait are dispatched to the hubcluster (local)>
|
||||
schematic: # Abstract
|
||||
cue: # There are many abstracts
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin trait definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/trait).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -2,11 +2,13 @@
|
|||
title: 自定义组件
|
||||
---
|
||||
|
||||
> 在阅读本部分之前,请确保你已经了解 KubeVela 中 [组件定义(ComponentDefinition)](../oam/x-definition#组件定义(ComponentDefinition)) 的概念且学习掌握了 [CUE 的基本知识](../cue/basic)
|
||||
:::tip
|
||||
在阅读本部分之前,请确保你已经了解 KubeVela 中 [组件定义(ComponentDefinition)](../oam/x-definition#组件定义(ComponentDefinition)) 的概念且学习掌握了 [CUE 的基本知识](../cue/basic)
|
||||
:::
|
||||
|
||||
本节将以组件定义的例子展开说明,介绍如何使用 [CUE](../cue/basic) 通过组件定义 `ComponentDefinition` 来自定义应用部署计划的组件。
|
||||
|
||||
### 交付一个简单的自定义组件
|
||||
## 交付一个简单的自定义组件
|
||||
|
||||
我们可以通过 `vela def init` 来根据已有的 YAML 文件来生成一个 `ComponentDefinition` 模板。
|
||||
|
||||
|
|
@ -37,8 +39,7 @@ vela def init stateless -t component --template-yaml ./stateless.yaml -o statele
|
|||
|
||||
得到如下结果:
|
||||
|
||||
```shell
|
||||
$ cat stateless.cue
|
||||
```shell title="stateless.cue"
|
||||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -71,10 +72,11 @@ template: {
|
|||
```
|
||||
|
||||
在这个自动生成的模板中:
|
||||
- 需要 `.spec.workload` 来指示该组件的工作负载类型。
|
||||
- `.spec.schematic.cue.template` 是一个 CUE 模板:
|
||||
* `output` 字段定义了 CUE 要输出的抽象模板。
|
||||
* `parameter` 字段定义了模板参数,即在应用部署计划(Application)中公开的可配置属性(KubeVela 将基于 `parameter` 字段自动生成 Json schema)。
|
||||
- The `stateless` is the name of component definition, it can be defined by yourself when initialize the component.
|
||||
- `stateless.attributes.workload` indicates the workload type of this component, it can help integrate with traits that apply to this kind of workload.
|
||||
- `template` is a CUE template, specifically:
|
||||
* The `output` and `outputs` fields define the resources that the component will be composed.
|
||||
* The `parameter` field defines the parameters of the component, i.e. the configurable properties exposed in the `Application` (and schema will be automatically generated based on them for end users to learn this component).
|
||||
|
||||
下面我们来给这个自动生成的自定义组件添加参数并进行赋值:
|
||||
|
||||
|
|
@ -82,8 +84,8 @@ template: {
|
|||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "<change me> apps/v1"
|
||||
kind: "<change me> Deployment"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
description: ""
|
||||
labels: {}
|
||||
|
|
@ -106,7 +108,7 @@ template: {
|
|||
kind: "Deployment"
|
||||
}
|
||||
outputs: {}
|
||||
parameters: {
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
}
|
||||
|
|
@ -116,11 +118,56 @@ template: {
|
|||
修改后可以用 `vela def vet` 做一下格式检查和校验。
|
||||
|
||||
```shell
|
||||
$ vela def vet stateless.cue
|
||||
Validation succeed.
|
||||
vela def vet stateless.cue
|
||||
```
|
||||
|
||||
接着,让我们声明另一个名为 `task` 的组件。
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
```
|
||||
Validation succeed.
|
||||
```
|
||||
</details>
|
||||
|
||||
Apply above `ComponentDefinition` to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
vela def apply stateless.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
Then the end user can check the schema and use it in an application now:
|
||||
|
||||
```
|
||||
vela show stateless
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
# Specification
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| name | | string | true | |
|
||||
| image | | string | true | |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
接着,让我们声明另一个名为 `task` 的组件,其原理类似。
|
||||
|
||||
<details>
|
||||
<summary>点击查看声明 task 组件的创建过程。</summary>
|
||||
|
||||
```shell
|
||||
vela def init task -t component -o task.cue
|
||||
|
|
@ -191,12 +238,12 @@ template: {
|
|||
将以上两个组件定义部署到集群中:
|
||||
|
||||
```shell
|
||||
$ vela def apply stateless.cue
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
$ vela def apply task.cue
|
||||
ComponentDefinition task created in namespace vela-system.
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
这两个已经定义好的组件,最终会在应用部署计划中实例化,我们引用自定义的组件类型 `stateless`,命名为 `hello`。同样,我们也引用了自定义的第二个组件类型 `task`,并命令为 `countdown`。
|
||||
|
||||
然后把它们编写到应用部署计划中,如下所示:
|
||||
|
|
@ -225,9 +272,10 @@ ComponentDefinition task created in namespace vela-system.
|
|||
|
||||
以上,我们就完成了一个自定义应用组件的应用交付全过程。值得注意的是,作为管理员的我们,可以通过 CUE 提供用户所需要的任何自定义组件类型,同时也为用户提供了模板参数 `parameter` 来灵活地指定对 Kubernetes 相关资源的要求。
|
||||
|
||||
#### 查看 Kubernetes 最终资源信息
|
||||
<details>
|
||||
|
||||
<summary> 了解背后的 Kubernetes 最终资源信息 </summary>
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
|
|
@ -268,23 +316,79 @@ spec:
|
|||
- for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
You can also use [dry run](../debug/dry-run) to show what the yaml results will be rendered for debugging.
|
||||
|
||||
### 交付一个复合的自定义组件
|
||||
|
||||
## 使用 CUE `Context` 获取运行时信息
|
||||
|
||||
KubeVela 让你可以在运行时,通过 `context` 关键字来引用一些信息。
|
||||
|
||||
最常用的就是应用部署计划的名称 `context.appName` 和组件的名称 `context.name`。
|
||||
|
||||
```cue
|
||||
context: {
|
||||
appName: string
|
||||
name: string
|
||||
}
|
||||
```
|
||||
|
||||
举例来说,假设你在实现一个组件定义,希望将容器的名称填充为组件的名称。那么这样做:
|
||||
|
||||
```cue
|
||||
parameter: {
|
||||
image: string
|
||||
}
|
||||
output: {
|
||||
...
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
}]
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
注意 `context` 的信息会在资源部署到目标集群之前就自动注入了。
|
||||
:::
|
||||
|
||||
|
||||
在本文的最后列出了完整的 context 变量列表。
|
||||
|
||||
|
||||
## 交付一个复合的自定义组件
|
||||
|
||||
除了上面这个例子外,一个组件的定义通常也会由多个 Kubernetes API 资源组成。例如,一个由 `Deployment` 和 `Service` 组成的 `webserver` 组件。CUE 同样能很好的满足这种自定义复合组件的需求。
|
||||
|
||||
:::tip
|
||||
Compare to [using Helm](../../tutorials/helm), this approach gives your more flexibility as you can control the abstraction any time and integrate with traits, workflows in KubeVela better.
|
||||
:::
|
||||
|
||||
我们会使用 `output` 这个字段来定义工作负载类型的模板,而其他剩下的资源模板,都在 `outputs` 这个字段里进行声明,格式如下:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
output: {
|
||||
<template of main workload structural data>
|
||||
}
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of auxiliary resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" by traits such like patching annotations/labels or other data during it.
|
||||
:::
|
||||
|
||||
回到 `webserver` 这个复合自定义组件上,它的 CUE 文件编写如下:
|
||||
|
||||
```
|
||||
``` title="webserver.cue"
|
||||
webserver: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -396,10 +500,18 @@ outputs: third-resource: {
|
|||
|
||||
在理解这些之后,将上面的组件定义对象保存到 CUE 文件中,并部署到你的 Kubernetes 集群。
|
||||
|
||||
|
||||
```shell
|
||||
$ vela def apply webserver.cue
|
||||
vela def apply webserver.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition webserver created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
然后,我们使用它们,来编写一个应用部署计划:
|
||||
|
||||
|
|
@ -423,59 +535,194 @@ spec:
|
|||
```
|
||||
|
||||
进行部署:
|
||||
|
||||
```
|
||||
$ vela up -f webserver.yaml
|
||||
```
|
||||
|
||||
最后,它将在运行时集群生成相关 Kubernetes 资源如下:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployment
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
hello-world-v1 1/1 1 1 15s
|
||||
|
||||
$ kubectl get svc
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hello-world-trait-7bdcff98f7 ClusterIP <your ip> <none> 8000/TCP 32s
|
||||
vela status webserver-demo --tree --detail
|
||||
```
|
||||
|
||||
## 使用 CUE `Context`
|
||||
<details>
|
||||
<summary>期望输出</summary>
|
||||
|
||||
KubeVela 让你可以在运行时,通过 `context` 关键字来引用一些信息。
|
||||
```console
|
||||
CLUSTER NAMESPACE RESOURCE STATUS APPLY_TIME DETAIL
|
||||
local ─── default ─┬─ Service/hello-webserver-auxiliaryworkload-685d98b6d9 updated 2022-10-15 21:58:35 Type: ClusterIP
|
||||
│ Cluster-IP: 10.43.255.55
|
||||
│ External-IP: <none>
|
||||
│ Port(s): 8000/TCP
|
||||
│ Age: 66s
|
||||
└─ Deployment/hello-webserver updated 2022-10-15 21:58:35 Ready: 1/1 Up-to-date: 1
|
||||
Available: 1 Age: 66s
|
||||
```
|
||||
</details>
|
||||
|
||||
最常用的就是应用部署计划的名称 `context.appName` 和组件的名称 `context.name`。
|
||||
|
||||
## 自定义健康检查和状态
|
||||
|
||||
You can also define health check policy and status message when a component deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### 健康检查
|
||||
|
||||
The spec of health check is `<component-type-name>.attributes.status.healthPolicy`.
|
||||
|
||||
如果没有定义,它的值默认是 `true`,意味着在部署完对象后就将对象的状态设置为健康。为了让组件的状态及时、准确,通常你需要为组件定义监控状态,这个过程可以通过一个 CUE 表达式完成。
|
||||
|
||||
在 CUE 里的关键词是 `isHealth`,CUE 表达式结果必须是 `bool` 类型。
|
||||
KubeVela 运行时会一直检查 CUE 表达式,直至其状态显示为健康。每次控制器都会获取所有的 Kubernetes 资源,并将他们填充到 `context` 字段中。
|
||||
|
||||
所以 context 字段会包含如下信息:
|
||||
|
||||
```cue
|
||||
context: {
|
||||
appName: string
|
||||
name: string
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <Kubernetes workload resource>
|
||||
outputs: {
|
||||
<resource1>: <Kubernetes trait resource1>
|
||||
<resource2>: <Kubernetes trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
举例来说,假设你在实现一个组件定义,希望将容器的名称填充为组件的名称。那么这样做:
|
||||
我们看看健康检查的例子:
|
||||
|
||||
```cue
|
||||
parameter: {
|
||||
image: string
|
||||
}
|
||||
output: {
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
}]
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
"""#
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 注意,`context` 的信息会在资源部署到目标集群之前就自动注入了
|
||||
The health check result will be recorded into the corresponding component in `.status.services` of `Application` resource.
|
||||
|
||||
### CUE `context` 的配置项
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
name: myweb
|
||||
...
|
||||
status: running
|
||||
```
|
||||
|
||||
* 你可以通过查看[模块定义的完整协议](../../platform-engineers/oam/x-definition#definition-runtime-context)来了解全部的 `context` 运行时变量.
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
## 下一步
|
||||
### 自定义状态
|
||||
|
||||
* 了解如何基于 CUE [自定义运维特征](../traits/customize-trait)。
|
||||
* 了解如何为组件和运维特征模块[定义健康状态](../traits/status)。
|
||||
The spec of custom status is `<component-type-name>.attributes.status.customStatus`, 自定义状态和健康检查的原理一致。
|
||||
|
||||
在 CUE 中的关键词是 `message`。同时,CUE 表达式的结果必须是 `string` 类型。
|
||||
|
||||
`Application` 对象的 CRD 控制器都会检查 CUE 表达式,直至显示健康通过。
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
ready: {
|
||||
readyReplicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding component in `.status.services` of `Application` resource like below.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: false
|
||||
message: Ready:1/1
|
||||
name: express-server
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
| `context.replicaKey` | The key of replication in context. Replication is an internal policy, it will replicate resources with different keys specified. (This feature will be introduced in v1.6+.) | string |
|
||||
|
||||
|
||||
## Component definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The component definition will be in the following API format:
|
||||
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: <ComponentDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <Function description>
|
||||
spec:
|
||||
workload: # Workload Capability Indicator
|
||||
definition:
|
||||
apiVersion: <Kubernetes Workload resource group>
|
||||
kind: <Kubernetes Workload types>
|
||||
schematic: # Component description
|
||||
cue: # Details of components defined by CUE language
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin component definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/component).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -7,7 +7,11 @@ title: 自定义运维特征
|
|||
|
||||
## 通过 Trait 生成资源对象
|
||||
|
||||
通过 Trait 生成资源的用法和 Component 基本类似,这种场景通常用于生成运维的对象,比如用于服务访问的 Ingress、Service,或者用于扩缩容的 HPA 等对象。
|
||||
通过 Trait 生成资源的用法和 Component 基本类似,有如下场景:
|
||||
|
||||
- 用于生成运维的资源对象,比如用于服务访问的 Ingress、Service,或者用于扩缩容的 HPA 等对象。
|
||||
- 用于上述运维对象的多种组合。
|
||||
- 用于对组件配置的补丁,如增加一个边车容器做日志收集等。
|
||||
|
||||
同样的,我们使用 `vela def init`命令来生成一个框架:
|
||||
|
||||
|
|
@ -15,8 +19,6 @@ title: 自定义运维特征
|
|||
vela def init my-route -t trait --desc "My ingress route trait." > myroute.cue
|
||||
```
|
||||
|
||||
> 注意: 在 vela CLI(`<=1.4.2`)的版本中有一个已知问题,`vela def init` 命令会生成一个错误的 `definitionRef: ""` 字段,这一行需要删除。
|
||||
|
||||
期望生成的内容如下:
|
||||
|
||||
```
|
||||
|
|
@ -40,13 +42,25 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
在 vela CLI(`<=1.4.2`)的版本中有一个已知问题,`vela def init` 命令会生成一个错误的 `definitionRef: ""` 字段,这一行需要删除。
|
||||
:::
|
||||
|
||||
|
||||
与组件定义有所不同,在用法上,你需要把所有的运维特征定义在 `outputs` 里(注意,不是 `output`),格式如下:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of trait resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
Actually the CUE template of trait here will be evaluated with component CUE template in the same context, so the name can't be conflict. That also explain why the `output` can't be defined in trait.
|
||||
:::
|
||||
|
||||
我们下面使用一个 `ingress` 和 `Service` 组成一个称为 `my-route` 的运维特征作为示例讲解:
|
||||
|
||||
```cue
|
||||
|
|
@ -151,7 +165,9 @@ EOF
|
|||
|
||||
你可以在 `outputs` 里定义 For 循环。
|
||||
|
||||
> 注意在 For 循环里的 `parameter` 字段必须是 map 类型。
|
||||
:::note
|
||||
注意在 For 循环里的 `parameter` 字段必须是 map 类型。
|
||||
:::
|
||||
|
||||
看看如下这个例子,在一个 `TraitDefinition` 对象里渲染多个 `Service`:
|
||||
|
||||
|
|
@ -210,7 +226,9 @@ spec:
|
|||
|
||||
你可以在 `processing.http` 里定义 HTTP 请求的 `method`, `url`, `body`, `header` 和 `trailer`,然后返回的数据将被存储在 `processing.output` 中。
|
||||
|
||||
> 请确保目标 HTTP 服务器返回的数据是 JSON 格式
|
||||
:::tip
|
||||
请确保目标 HTTP 服务器返回的数据是 JSON 格式才能正确解析到 `output` 字段中。
|
||||
:::
|
||||
|
||||
接着,你就可以通过 `patch` 或者 `output/outputs` 里的 `processing.output` 来引用返回数据了。
|
||||
|
||||
|
|
@ -254,126 +272,132 @@ template: {
|
|||
|
||||
`TraitDefinition` 对象可以读取特定 `ComponentDefinition` 对象生成的 API 资源(渲染自 `output` 和 `outputs`)。
|
||||
|
||||
> KubeVela 保证了 `ComponentDefinition` 一定会在 `TraitDefinition` 之前渲染
|
||||
:::caution
|
||||
Generally, KubeVela will ensure the component definitions are evaluated before its traits. But there're a [stage mechanism](https://github.com/kubevela/kubevela/pull/4570) that allow trait be deployed before component.
|
||||
:::
|
||||
|
||||
|
||||
具体来说,`context.output` 字段包含了所有渲染后的工作负载 API 资源,然后 `context.outputs.<xx>` 则包含渲染后的其它类型 API 资源。
|
||||
|
||||
下面是一个数据传递的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: worker
|
||||
spec:
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
1. Let's define a component definition `myworker` like below:
|
||||
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
ports: [{containerPort: parameter.port}]
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```cue
|
||||
"myworker": {
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
type: "component"
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
template: {
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
port: int
|
||||
}
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
ports: [{containerPort: parameter.port}]
|
||||
envFrom: [{
|
||||
configMapRef: name: context.name + "game-config"
|
||||
}]
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs: gameconfig: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: context.name + "game-config"
|
||||
}
|
||||
data: {
|
||||
enemies: parameter.enemies
|
||||
lives: parameter.lives
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: ingress
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
path: string
|
||||
exposePort: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [{
|
||||
port: parameter.exposePort
|
||||
targetPort: context.output.spec.template.spec.containers[0].ports[0].containerPort
|
||||
}]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
labels: config: context.outputs.gameconfig.data.enemies
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [{
|
||||
path: parameter.path
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: parameter.exposePort
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
lives: string
|
||||
enemies: string
|
||||
port: int
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Define a new `myingress` trait that read the port.
|
||||
|
||||
```cue
|
||||
"myingress": {
|
||||
type: "trait"
|
||||
attributes: {
|
||||
appliesToWorkloads: ["myworker"]
|
||||
}
|
||||
}
|
||||
|
||||
template: {
|
||||
parameter: {
|
||||
domain: string
|
||||
path: string
|
||||
exposePort: int
|
||||
}
|
||||
// trait template can have multiple outputs in one trait
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [{
|
||||
port: parameter.exposePort
|
||||
targetPort: context.output.spec.template.spec.containers[0].ports[0].containerPort
|
||||
}]
|
||||
}
|
||||
}
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
labels: config: context.outputs.gameconfig.data.enemies
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [{
|
||||
path: parameter.path
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: parameter.exposePort
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在渲染 `worker` `ComponentDefinition` 时,具体发生了:
|
||||
|
|
@ -393,7 +417,187 @@ spec:
|
|||
|
||||
针对上述场景,KubeVela 通过 patch 功能来支撑,因为 Patch 的能力针对 Trait 和 Workflow 均适用,我们通过[这篇 Patch 文档](./patch-trait)统一介绍。
|
||||
|
||||
## 下一步
|
||||
## Define Health for Definition
|
||||
|
||||
* 了解组件和运维特征如何[定义健康状态](../traits/status)。
|
||||
* 了解如何通过 CUE [定义工作流步骤](../workflow/workflow)。
|
||||
You can also define health check policy and status message when a trait deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health Check
|
||||
|
||||
The spec of health check is `<trait-type-name>.attributes.status.healthPolicy`, it's similar to component definition.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the trait is healthy or not.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
my-ingress: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The health check result will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<trait-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
my-service: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
if context.outputs.ingress.status.loadBalancer.ingress != _|_ {
|
||||
let igs = context.outputs.ingress.status.loadBalancer.ingress
|
||||
if igs[0].ip != _|_ {
|
||||
if igs[0].host != _|_ {
|
||||
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
|
||||
}
|
||||
if igs[0].host == _|_ {
|
||||
message: "Host not specified, visit the cluster or load balancer in front of the cluster with IP: " + igs[0].ip
|
||||
}
|
||||
}
|
||||
}
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
|
||||
|
||||
## Trait definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The trait definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: <TraitDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <function description>
|
||||
spec:
|
||||
definition:
|
||||
apiVersion: <corresponding Kubernetes resource group>
|
||||
kind: <corresponding Kubernetes resource type>
|
||||
workloadRefPath: <The path to the reference field of the Workload object in the Trait>
|
||||
podDisruptive: <whether the parameter update of Trait cause the underlying resource (pod) to restart>
|
||||
manageWorkload: <Whether the workload is managed by this Trait>
|
||||
skipRevisionAffect: <Whether this Trait is not included in the calculation of version changes>
|
||||
appliesToWorkloads:
|
||||
- <Workload that TraitDefinition can adapt to>
|
||||
conflictsWith:
|
||||
- <other Traits that conflict with this><>
|
||||
revisionEnabled: <whether Trait is aware of changes in component version>
|
||||
controlPlaneOnly: <Whether resources generated by trait are dispatched to the hubcluster (local)>
|
||||
schematic: # Abstract
|
||||
cue: # There are many abstracts
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin trait definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/trait).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -106,9 +106,8 @@ kind: ConfigMap
|
|||
metadata:
|
||||
name: clone-set-relation
|
||||
namespace: vela-system
|
||||
annotations:
|
||||
"rules.oam.dev/resource-format": "yaml"
|
||||
labels:
|
||||
"rules.oam.dev/resource-format": "yaml"
|
||||
"rules.oam.dev/resources": "true"
|
||||
data:
|
||||
rules: |-
|
||||
|
|
@ -128,9 +127,8 @@ kind: ConfigMap
|
|||
metadata:
|
||||
name: clone-set-relation
|
||||
namespace: vela-system
|
||||
annotations:
|
||||
"rules.oam.dev/resource-format": "json"
|
||||
labels:
|
||||
"rules.oam.dev/resource-format": "json"
|
||||
"rules.oam.dev/resources": "true"
|
||||
data:
|
||||
rules: |-
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ module.exports = {
|
|||
'platform-engineers/components/custom-component',
|
||||
'platform-engineers/traits/customize-trait',
|
||||
'platform-engineers/policy/custom-policy',
|
||||
'platform-engineers/traits/status',
|
||||
'platform-engineers/workflow/workflow',
|
||||
{
|
||||
'Patch and Override': [
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ This module configures AWS Config, a service that enables you to assess, audit,
|
|||
findings_notification_arn | The ARN for an SNS topic to send findings notifications to. This is only used if create_sns_topic is false.\nIf you want to send findings to an existing SNS topic, set the value of this to the ARN of the existing topic and set\ncreate_sns_topic to false.\n | string | false |
|
||||
force_destroy | A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable | bool | false |
|
||||
global_resource_collector_region | The region that collects AWS Config data for global resources such as IAM | string | true |
|
||||
iam_role_arn | The ARN for an IAM Role AWS Config uses to make read or write requests to the delivery channel and to describe the\nAWS resources associated with the account. This is only used if create_iam_role is false.\n\nIf you want to use an existing IAM Role, set the value of this to the ARN of the existing topic and set\ncreate_iam_role to false.\n\nSee the AWS Docs for further information:\nhttp://docs.aws.amazon.com/config/latest/developerguide/iamrole-permissions.html\n | string | false |
|
||||
iam_role_arn | The ARN for an IAM Role AWS Config uses to make read or write requests to the delivery channel and to describe the\nAWS resources associated with the account. This is only used if create_iam_role is false.\n\nIf you want to use an existing IAM Role, set the value of this to the ARN of the existing topic and set\ncreate_iam_role to false.\n\nSee the AWS Docs for further information:\nhttps://docs.aws.amazon.com/config/latest/developerguide/iamrole-permissions.html\n | string | false |
|
||||
managed_rules | A list of AWS Managed Rules that should be enabled on the account.\n\nSee the following for a list of possible rules to enable:\nhttps://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html\n | map(object({\n description = string\n identifier = string\n input_parameters = any\n tags = map(string)\n enabled = bool\n })) | false |
|
||||
s3_bucket_arn | The ARN of the S3 bucket used to store the configuration history | string | true |
|
||||
s3_bucket_id | The id (name) of the S3 bucket used to store the configuration history | string | true |
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ First, generate `ComponentDefinition` scaffolds via `vela def init` with existed
|
|||
|
||||
The YAML file:
|
||||
|
||||
```yaml
|
||||
```yaml title="stateless.yaml"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec:
|
||||
|
|
@ -35,8 +35,7 @@ vela def init stateless -t component --template-yaml ./stateless.yaml -o statele
|
|||
|
||||
It generates a file:
|
||||
|
||||
```cue
|
||||
// $ cat stateless.cue
|
||||
```cue title="stateless.cue"
|
||||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -69,10 +68,11 @@ template: {
|
|||
```
|
||||
|
||||
In detail:
|
||||
- `.spec.workload` is required to indicate the workload type of this component.
|
||||
- `.spec.schematic.cue.template` is a CUE template, specifically:
|
||||
* The `output` filed defines the template for the abstraction.
|
||||
* The `parameter` filed defines the template parameters, i.e. the configurable properties exposed in the `Application`abstraction (and JSON schema will be automatically generated based on them).
|
||||
- The `stateless` is the name of component definition, it can be defined by yourself when initialize the component.
|
||||
- `stateless.attributes.workload` indicates the workload type of this component, it can help integrate with traits that apply to this kind of workload.
|
||||
- `template` is a CUE template, specifically:
|
||||
* The `output` and `outputs` fields define the resources that the component will be composed.
|
||||
* The `parameter` field defines the parameters of the component, i.e. the configurable properties exposed in the `Application` (and schema will be automatically generated based on them for end users to learn this component).
|
||||
|
||||
Add parameters in this auto-generated custom component file :
|
||||
|
||||
|
|
@ -80,8 +80,8 @@ Add parameters in this auto-generated custom component file :
|
|||
stateless: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
apiVersion: "<change me> apps/v1"
|
||||
kind: "<change me> Deployment"
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
}
|
||||
description: ""
|
||||
labels: {}
|
||||
|
|
@ -114,11 +114,56 @@ template: {
|
|||
You can use `vela def vet` to validate the format:
|
||||
|
||||
```shell
|
||||
$ vela def vet stateless.cue
|
||||
Validation succeed.
|
||||
vela def vet stateless.cue
|
||||
```
|
||||
|
||||
Declare another component named `task` which is an abstraction for run-to-completion workload.
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
Validation succeed.
|
||||
```
|
||||
</details>
|
||||
|
||||
Apply above `ComponentDefinition` to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
vela def apply stateless.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
Then the end user can check the schema and use it in an application now:
|
||||
|
||||
```
|
||||
vela show stateless
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
# Specification
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
| name | | string | true | |
|
||||
| image | | string | true | |
|
||||
+-------+-------------+--------+----------+---------+
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
Declare another component named `task` which is an abstraction for run-to-completion workload works the same.
|
||||
|
||||
<details>
|
||||
<summary>Check the details for another example to define a task based component.</summary>
|
||||
|
||||
```shell
|
||||
vela def init task -t component -o task.cue
|
||||
|
|
@ -186,16 +231,17 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
Apply above `ComponentDefinition` files to your Kubernetes cluster:
|
||||
Apply above `ComponentDefinition` files to your Kubernetes cluster to make it work:
|
||||
|
||||
```shell
|
||||
$ vela def apply stateless.cue
|
||||
ComponentDefinition stateless created in namespace vela-system.
|
||||
$ vela def apply task.cue
|
||||
ComponentDefinition task created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
## Declare an `Application`
|
||||
Now let's use the `stateless` and `task` component type.
|
||||
|
||||
## Declare an `Application` using this component
|
||||
|
||||
The `ComponentDefinition` can be instantiated in `Application` abstraction as below:
|
||||
|
||||
|
|
@ -221,8 +267,8 @@ The `ComponentDefinition` can be instantiated in `Application` abstraction as be
|
|||
- "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"
|
||||
```
|
||||
|
||||
### Under The Hood
|
||||
<details>
|
||||
<summary> Learn Details Under The Hood </summary>
|
||||
|
||||
Above application resource will generate and manage following Kubernetes resources in your target cluster based on the `output` in CUE template and user input in `Application` properties.
|
||||
|
||||
|
|
@ -268,7 +314,10 @@ spec:
|
|||
```
|
||||
</details>
|
||||
|
||||
## CUE `Context`
|
||||
You can also use [dry run](../debug/dry-run) to show what the yaml results will be rendered for debugging.
|
||||
|
||||
|
||||
## CUE `Context` for runtime information
|
||||
|
||||
KubeVela allows you to reference the runtime information of your application via `context` keyword.
|
||||
|
||||
|
|
@ -299,32 +348,40 @@ output: {
|
|||
}
|
||||
```
|
||||
|
||||
> Note that `context` information are auto-injected before resources are applied to target cluster.
|
||||
:::tip
|
||||
Note that `context` information are auto-injected before resources are applied to target cluster.
|
||||
:::
|
||||
|
||||
### Full available `context` information can be used
|
||||
The list of [all available context variables](#full-available-context-in-component) are listed at last of this doc.
|
||||
|
||||
* Check the reference docs of [definition protocol](../../platform-engineers/oam/x-definition#definition-runtime-context) to see all of the available information in KubeVela `context`.
|
||||
|
||||
## Composition
|
||||
## Compose resources in one component
|
||||
|
||||
It's common that a component definition is composed by multiple API resources, for example, a `webserver` component that is composed by a Deployment and a Service. CUE is a great solution to achieve this in simplified primitives.
|
||||
|
||||
> Another approach to do composition in KubeVela of course is [using Helm](../../tutorials/helm).
|
||||
:::tip
|
||||
Compare to [using Helm](../../tutorials/helm), this approach gives your more flexibility as you can control the abstraction any time and integrate with traits, workflows in KubeVela better.
|
||||
:::
|
||||
|
||||
## How-to
|
||||
|
||||
KubeVela requires you to define the template of workload type in `output` section, and leave all the other resource templates in `outputs` section with format as below:
|
||||
KubeVela requires you to define the template of main workload in `output` section, and leave all the other resource templates in `outputs` section with format as below:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
output: {
|
||||
<template of main workload structural data>
|
||||
}
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of auxiliary resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" like patching annotations/labels or other data during it.
|
||||
:::note
|
||||
The reason for this requirement is KubeVela needs to know it is currently rendering a workload so it could do some "magic" by traits such like patching annotations/labels or other data during it.
|
||||
:::
|
||||
|
||||
Below is the example for `webserver` definition:
|
||||
Below is the example for `webserver` definition, let's use a demo to show how to use it:
|
||||
|
||||
```cue
|
||||
```cue title="webserver.cue"
|
||||
webserver: {
|
||||
annotations: {}
|
||||
attributes: workload: definition: {
|
||||
|
|
@ -420,13 +477,20 @@ template: {
|
|||
Apply to your Kubernetes cluster:
|
||||
|
||||
```shell
|
||||
$ vela def apply webserver.cue
|
||||
vela def apply webserver.cue
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```
|
||||
ComponentDefinition webserver created in namespace vela-system.
|
||||
```
|
||||
</details>
|
||||
|
||||
The user could now declare an `Application` with it:
|
||||
|
||||
```yaml
|
||||
```yaml title="webserver-app.yaml"
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
|
|
@ -434,7 +498,7 @@ metadata:
|
|||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: hello-world
|
||||
- name: hello-webserver
|
||||
type: webserver
|
||||
properties:
|
||||
image: oamdev/hello-world
|
||||
|
|
@ -445,26 +509,196 @@ spec:
|
|||
cpu: "100m"
|
||||
```
|
||||
|
||||
It will generate and manage below Kubernetes API resources in target cluster, you can use [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) to check:
|
||||
Create this application by:
|
||||
|
||||
```
|
||||
vela up -f webserver-app.yaml
|
||||
```
|
||||
|
||||
Then you can check the resources and find the results:
|
||||
|
||||
```shell
|
||||
kubectl get deployment
|
||||
vela status webserver-demo --tree --detail
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>expected output</summary>
|
||||
|
||||
```console
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
hello-world-v1 1/1 1 1 15s
|
||||
CLUSTER NAMESPACE RESOURCE STATUS APPLY_TIME DETAIL
|
||||
local ─── default ─┬─ Service/hello-webserver-auxiliaryworkload-685d98b6d9 updated 2022-10-15 21:58:35 Type: ClusterIP
|
||||
│ Cluster-IP: 10.43.255.55
|
||||
│ External-IP: <none>
|
||||
│ Port(s): 8000/TCP
|
||||
│ Age: 66s
|
||||
└─ Deployment/hello-webserver updated 2022-10-15 21:58:35 Ready: 1/1 Up-to-date: 1
|
||||
Available: 1 Age: 66s
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## Define health check and status message for component
|
||||
|
||||
You can also define health check policy and status message when a component deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health check
|
||||
|
||||
The spec of health check is `<component-type-name>.attributes.status.healthPolicy`.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the component is healthy or not.
|
||||
|
||||
The keyword is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl get svc
|
||||
```
|
||||
```console
|
||||
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
hello-world-trait-7bdcff98f7 ClusterIP <your ip> <none> 8000/TCP 32s
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What's Next
|
||||
The health check result will be recorded into the corresponding component in `.status.services` of `Application` resource.
|
||||
|
||||
* Learn more about [defining customized trait](../traits/customize-trait) in CUE.
|
||||
* Learn how to [define health check and custom status](../traits/status) of Component.
|
||||
* Learn how to [define policy](../policy/custom-policy) in CUE.
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
name: myweb
|
||||
...
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<component-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE expression is `message`, the result must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
webserver: {
|
||||
type: "component"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
ready: {
|
||||
readyReplicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.readyReplicas != _|_ {
|
||||
readyReplicas: context.output.status.readyReplicas
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)"
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding component in `.status.services` of `Application` resource like below.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: false
|
||||
message: Ready:1/1
|
||||
name: express-server
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/component/webservice.cue#L29-L50) for more examples.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
| `context.replicaKey` | The key of replication in context. Replication is an internal policy, it will replicate resources with different keys specified. (This feature will be introduced in v1.6+.) | string |
|
||||
|
||||
|
||||
## Component definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The component definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: <ComponentDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <Function description>
|
||||
spec:
|
||||
workload: # Workload Capability Indicator
|
||||
definition:
|
||||
apiVersion: <Kubernetes Workload resource group>
|
||||
kind: <Kubernetes Workload types>
|
||||
schematic: # Component description
|
||||
cue: # Details of components defined by CUE language
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin component definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/component).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -4,9 +4,13 @@ title: Trait Definition
|
|||
|
||||
In this section we will introduce how to define a custom trait with CUE. Make sure you've learned the basic knowledge about [Definition Concept](../../getting-started/definition) and [how to manage definition](../cue/definition-edit).
|
||||
|
||||
## Generate Resources by Trait
|
||||
## Generate a Trait scaffold
|
||||
|
||||
A trait can be something similar to component that you can define operational Kubernetes API resources such as ingress, service as trait.
|
||||
A trait can be something similar to component, while they're attached operational resources.
|
||||
|
||||
- Kubernetes API resources like ingress, service, rollout.
|
||||
- The composition of these operational resources.
|
||||
- A patch of data, for example, patch sidecar to workload.
|
||||
|
||||
Let's use `vela def init` to create a basic trait scaffold:
|
||||
|
||||
|
|
@ -14,8 +18,6 @@ Let's use `vela def init` to create a basic trait scaffold:
|
|||
vela def init my-route -t trait --desc "My ingress route trait." > myroute.cue
|
||||
```
|
||||
|
||||
> Note: there's a bug in vela CLI(`<=1.4.2`), the `vela def init` command will generate `definitionRef: ""` in `attributes` which is wrong, please remove that line.
|
||||
|
||||
The content of the scaffold expected to be:
|
||||
|
||||
```cue
|
||||
|
|
@ -39,13 +41,26 @@ template: {
|
|||
}
|
||||
```
|
||||
|
||||
:::caution
|
||||
There's a bug in vela CLI(`<=1.4.2`), the `vela def init` command will generate `definitionRef: ""` in `attributes` which is wrong, please remove that line.
|
||||
:::
|
||||
|
||||
## Define a trait to compose resources
|
||||
|
||||
Unlike component definition, KubeVela requires objects in traits **MUST** be defined in `outputs` section (not `output`) in CUE template with format as below:
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
outputs: {
|
||||
<unique-name>: {
|
||||
<template of trait resource structural data>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
Actually the CUE template of trait here will be evaluated with component CUE template in the same context, so the name can't be conflict. That also explain why the `output` can't be defined in trait.
|
||||
:::
|
||||
|
||||
Below is an example that we combine `ingress` and `service` of Kubernetes into our `my-route` trait.
|
||||
|
||||
```cue
|
||||
|
|
@ -152,7 +167,9 @@ With the help of CUE, we can achieve many advanced features in trait.
|
|||
|
||||
You can define the for-loop inside the `outputs`.
|
||||
|
||||
> Note that in this case the type of `parameter` field used in the for-loop must be a map.
|
||||
:::note
|
||||
In this case the type of `parameter` field used in the for-loop must be a map.
|
||||
:::
|
||||
|
||||
Below is an example that will render multiple Kubernetes Services in one trait:
|
||||
|
||||
|
|
@ -211,7 +228,9 @@ The trait definition can send a HTTP request and capture the response to help yo
|
|||
|
||||
You can define HTTP request `method`, `url`, `body`, `header` and `trailer` in the `processing.http` section, and the returned data will be stored in `processing.output`.
|
||||
|
||||
> Please ensure the target HTTP server returns a **JSON data**. `output`.
|
||||
:::tip
|
||||
Please ensure the target HTTP server returns a **JSON data** as `output`.
|
||||
:::
|
||||
|
||||
Then you can reference the returned data from `processing.output` in `patch` or `output/outputs`.
|
||||
|
||||
|
|
@ -251,11 +270,13 @@ template: {
|
|||
|
||||
In above example, this trait definition will send request to get the `token` data, and then patch the data to given component instance.
|
||||
|
||||
## Get context data of Component parameters
|
||||
## CUE `Context` for runtime information
|
||||
|
||||
A trait definition can read the generated resources (rendered from `output` and `outputs`) of given component definition.
|
||||
|
||||
>KubeVela will ensure the component definitions are always evaluated before its traits.
|
||||
:::caution
|
||||
Generally, KubeVela will ensure the component definitions are evaluated before its traits. But there're a [stage mechanism](https://github.com/kubevela/kubevela/pull/4570) that allow trait be deployed before component.
|
||||
:::
|
||||
|
||||
Specifically, the `context.output` contains the rendered workload API resource (whose GVK is indicated by `spec.workload`in component definition), and use `context.outputs.<xx>` to contain all the other rendered API resources.
|
||||
|
||||
|
|
@ -399,8 +420,187 @@ There're several reasons:
|
|||
|
||||
So KubeVela allow patch or override in this case, please refer to [patch trait](./patch-trait) for more details. As trait and workflow step can both patch, so we write them together.
|
||||
|
||||
## What's Next
|
||||
## Define Health for Definition
|
||||
|
||||
* Learn how to [define policy](../policy/custom-policy) in CUE.
|
||||
* Learn how to [define health check and custom status](../traits/status) of Trait.
|
||||
* Learn how to [define workflow step](../workflow/workflow) in CUE.
|
||||
You can also define health check policy and status message when a trait deployed and tell the real status to end users.
|
||||
|
||||
:::caution
|
||||
Reference `parameter` defined in `template` is not supported now in health check and custom status, they work in different stage with the resource template. While we're going to support this feature in https://github.com/kubevela/kubevela/issues/4863 .
|
||||
:::
|
||||
|
||||
### Health Check
|
||||
|
||||
The spec of health check is `<trait-type-name>.attributes.status.healthPolicy`, it's similar to component definition.
|
||||
|
||||
If not defined, the health result will always be `true`, which means it will be marked as healthy immediately after resources applied to Kubernetes. You can define a CUE expression in it to notify if the trait is healthy or not.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the `context` variables.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```cue
|
||||
my-ingress: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
healthPolicy: #"""
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The health check result will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
### Custom Status
|
||||
|
||||
The spec of custom status is `<trait-type-name>.attributes.status.customStatus`, it shares the same mechanism with the health check.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The example of custom status likes below:
|
||||
|
||||
```cue
|
||||
my-service: {
|
||||
type: "trait"
|
||||
...
|
||||
attributes: {
|
||||
status: {
|
||||
customStatus: #"""
|
||||
if context.outputs.ingress.status.loadBalancer.ingress != _|_ {
|
||||
let igs = context.outputs.ingress.status.loadBalancer.ingress
|
||||
if igs[0].ip != _|_ {
|
||||
if igs[0].host != _|_ {
|
||||
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
|
||||
}
|
||||
if igs[0].host == _|_ {
|
||||
message: "Host not specified, visit the cluster or load balancer in front of the cluster with IP: " + igs[0].ip
|
||||
}
|
||||
}
|
||||
}
|
||||
"""#
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The message will be recorded into the corresponding trait in `.status.services` of `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
...
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: my-ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/vela-templates/definitions/internal/trait/gateway.cue) for more complete example.
|
||||
|
||||
|
||||
## Full available `context` in Component
|
||||
|
||||
|
||||
| Context Variable | Description | Type |
|
||||
| :------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------: |
|
||||
| `context.appName` | The app name corresponding to the current instance of the application. | string |
|
||||
| `context.namespace` | The target namespace of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.cluster` | The target cluster of the current resource is going to be deployed, it can be different with the namespace of application if overridden by some policies. | string |
|
||||
| `context.appRevision` | The app version name corresponding to the current instance of the application. | string |
|
||||
| `context.appRevisionNum` | The app version number corresponding to the current instance of the application. | int |
|
||||
| `context.name` | The component name corresponding to the current instance of the application. | string |
|
||||
| `context.revision` | The version name of the current component instance. | string |
|
||||
| `context.output` | The object structure after instantiation of current component. | Object Map |
|
||||
| `context.outputs.<resourceName>` | Structure after instantiation of current component auxiliary resources. | Object Map |
|
||||
| `context.workflowName` | The workflow name specified in annotation. | string |
|
||||
| `context.publishVersion` | The version of application instance specified in annotation. | string |
|
||||
| `context.components` | The object structure of components spec in this application. | Object Map |
|
||||
| `context.appLabels` | The labels of the current application instance. | Object Map |
|
||||
| `context.appAnnotations` | The annotations of the current application instance. | Object Map |
|
||||
|
||||
|
||||
## Trait definition in Kubernetes
|
||||
|
||||
KubeVela is fully programmable via CUE, while it leverage Kubernetes as control plane and align with the API in yaml.
|
||||
As a result, the CUE definition will be converted as Kubernetes API when applied into cluster.
|
||||
|
||||
The trait definition will be in the following API format:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: <TraitDefinition name>
|
||||
annotations:
|
||||
definition.oam.dev/description: <function description>
|
||||
spec:
|
||||
definition:
|
||||
apiVersion: <corresponding Kubernetes resource group>
|
||||
kind: <corresponding Kubernetes resource type>
|
||||
workloadRefPath: <The path to the reference field of the Workload object in the Trait>
|
||||
podDisruptive: <whether the parameter update of Trait cause the underlying resource (pod) to restart>
|
||||
manageWorkload: <Whether the workload is managed by this Trait>
|
||||
skipRevisionAffect: <Whether this Trait is not included in the calculation of version changes>
|
||||
appliesToWorkloads:
|
||||
- <Workload that TraitDefinition can adapt to>
|
||||
conflictsWith:
|
||||
- <other Traits that conflict with this><>
|
||||
revisionEnabled: <whether Trait is aware of changes in component version>
|
||||
controlPlaneOnly: <Whether resources generated by trait are dispatched to the hubcluster (local)>
|
||||
schematic: # Abstract
|
||||
cue: # There are many abstracts
|
||||
template: <CUE format template>
|
||||
```
|
||||
|
||||
You can check the detail of this format [here](../oam/x-definition).
|
||||
|
||||
## More examples to learn
|
||||
|
||||
You can check the following resources for more examples:
|
||||
|
||||
- Builtin trait definitions in the [KubeVela github repo](https://github.com/kubevela/kubevela/tree/master/vela-templates/definitions/internal/trait).
|
||||
- Definitions defined in addons in the [catalog repo](https://github.com/kubevela/catalog/tree/master/addons).
|
||||
|
|
@ -2,140 +2,4 @@
|
|||
title: Define Health for Definition
|
||||
---
|
||||
|
||||
This documentation will explain how to achieve status write back by using CUE templates in definition objects.
|
||||
|
||||
## Health Check
|
||||
|
||||
The spec of health check is `spec.status.healthPolicy`, they are the same for both Workload Type and Trait.
|
||||
|
||||
If not defined, the health result will always be `true`.
|
||||
|
||||
The keyword in CUE is `isHealth`, the result of CUE expression must be `bool` type.
|
||||
KubeVela runtime will evaluate the CUE expression periodically until it becomes healthy. Every time the controller will get all the Kubernetes resources and fill them into the context field.
|
||||
|
||||
So the context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Trait will not have the `context.output`, other fields are the same.
|
||||
|
||||
The example of health check likes below:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
spec:
|
||||
status:
|
||||
healthPolicy: |
|
||||
isHealth: (context.output.status.readyReplicas > 0) && (context.output.status.readyReplicas == context.output.status.replicas)
|
||||
...
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
spec:
|
||||
status:
|
||||
healthPolicy: |
|
||||
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
||||
...
|
||||
```
|
||||
|
||||
> Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/docs/examples/app-with-status/template.yaml) for the complete example.
|
||||
|
||||
The health check result will be recorded into the `Application` resource.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
components:
|
||||
- name: myweb
|
||||
type: worker
|
||||
properties:
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
enemies: alien
|
||||
image: busybox
|
||||
lives: "3"
|
||||
traits:
|
||||
- type: ingress
|
||||
properties:
|
||||
domain: www.example.com
|
||||
http:
|
||||
/: 80
|
||||
status:
|
||||
...
|
||||
services:
|
||||
- healthy: true
|
||||
message: "type: busybox,\t enemies:alien"
|
||||
name: myweb
|
||||
traits:
|
||||
- healthy: true
|
||||
message: 'Visiting URL: www.example.com, IP: 47.111.233.220'
|
||||
type: ingress
|
||||
status: running
|
||||
```
|
||||
|
||||
## Custom Status
|
||||
|
||||
The spec of custom status is `spec.status.customStatus`, they are the same for both Workload Type and Trait.
|
||||
|
||||
The keyword in CUE is `message`, the result of CUE expression must be `string` type.
|
||||
|
||||
The custom status has the same mechanism with health check.
|
||||
Application CRD controller will evaluate the CUE expression after the health check succeed.
|
||||
|
||||
The context will contain following information:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <K8s workload resource>
|
||||
outputs: {
|
||||
<resource1>: <K8s trait resource1>
|
||||
<resource2>: <K8s trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Trait will not have the `context.output`, other fields are the same.
|
||||
|
||||
|
||||
Please refer to [this doc](https://github.com/kubevela/kubevela/blob/master/docs/examples/app-with-status/template.yaml) for the complete example.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
spec:
|
||||
status:
|
||||
customStatus: |-
|
||||
message: "type: " + context.output.spec.template.spec.containers[0].image + ",\t enemies:" + context.outputs.gameconfig.data.enemies
|
||||
...
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
spec:
|
||||
status:
|
||||
customStatus: |-
|
||||
message: "type: "+ context.outputs.service.spec.type +",\t clusterIP:"+ context.outputs.service.spec.clusterIP+",\t ports:"+ "\(context.outputs.service.spec.ports[0].port)"+",\t domain"+context.outputs.ingress.spec.rules[0].host
|
||||
...
|
||||
```
|
||||
|
||||
## Next Step
|
||||
|
||||
* Learn how to [define custom workflow](../workflow/workflow) with CUE.
|
||||
This documentation has been merged into [component](../components/custom-component) and [trait](customize-trait).
|
||||
|
|
@ -89,6 +89,7 @@ metadata:
|
|||
name: clone-set-relation
|
||||
namespace: vela-system
|
||||
labels:
|
||||
"rules.oam.dev/resource-format": "yaml"
|
||||
"rules.oam.dev/resources": "true"
|
||||
data:
|
||||
rules: |-
|
||||
|
|
@ -108,9 +109,8 @@ kind: ConfigMap
|
|||
metadata:
|
||||
name: clone-set-relation
|
||||
namespace: vela-system
|
||||
annotations:
|
||||
"rules.oam.dev/resource-format": "json"
|
||||
labels:
|
||||
"rules.oam.dev/resource-format": "json"
|
||||
"rules.oam.dev/resources": "true"
|
||||
data:
|
||||
rules: |-
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@
|
|||
"platform-engineers/components/custom-component",
|
||||
"platform-engineers/traits/customize-trait",
|
||||
"platform-engineers/policy/custom-policy",
|
||||
"platform-engineers/traits/status",
|
||||
"platform-engineers/workflow/workflow",
|
||||
{
|
||||
"Patch and Override": [
|
||||
|
|
|
|||
Loading…
Reference in New Issue