Fix (#257)
* Fix * updates * updates Co-authored-by: 段少 <duanwei.duan@alibaba-inc.com>
This commit is contained in:
parent
98f62a2aa6
commit
5d1999347e
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Practical Case
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Practical Case
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Practical Case
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Practical Case
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Use Case
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -155,7 +155,7 @@ The Workflow is based on modular design. Each Workflow module is defined by a De
|
|||
|
||||
> Especially, workflow works in application level, if you specify workflow, the resources won't be deployed if you don't specify any step to deploy it.
|
||||
|
||||
If you're a platform builder who's familiar with Kubernetes, you can learn to [define your own workflow step by using CUE](../platform-engineers/workflow/steps).
|
||||
If you're a platform builder who's familiar with Kubernetes, you can learn to [define your own workflow step by using CUE](../platform-engineers/workflow/workflow).
|
||||
|
||||
## What's Next
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: Integrated Cloud Services
|
||||
title: Integrated Cloud Services # Deprecated
|
||||
---
|
||||
|
||||
Cloud-oriented development is now becoming the norm, there is an urgent need to integrate cloud resources from different sources and types. Whether it is the most basic object storage, cloud database, or load balancing, it is all faced with the challenges of hybrid cloud, multi-cloud and other complex environments, and KubeVela is perfect for the needs.
|
||||
|
|
@ -130,4 +130,4 @@ If the out-of-the-box cloud resources don't cover your needs, you can still use
|
|||
|
||||
- [Component Observability](./component-observability)
|
||||
- [Data Pass Between Components ](./component-dependency-parameter)
|
||||
- [Multi-Cluster and Environment](./multi-app-env-cluster)
|
||||
- [Multi-Cluster and Environment](../case-studies/multi-app-env-cluster)
|
||||
|
|
@ -69,7 +69,7 @@ NAME COMPONENT TYPE PHASE HEALTHY STATUS AGE
|
|||
policy-demo nginx-server webservice running true 65s
|
||||
```
|
||||
|
||||
If you want to learn more about `env-binding`, please refer to **[Multi Cluster Deployment](../multi-app-env-cluster)**.
|
||||
If you want to learn more about `env-binding`, please refer to **[Multi Cluster Deployment](../../case-studies/multi-app-env-cluster)**.
|
||||
|
||||
## Appendix: Parameter List
|
||||
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ Get to know about how to customize:
|
|||
* [Component](../components/custom-component)
|
||||
* [Trait](../traits/customize-trait)
|
||||
* [Policy](../policy/custom-policy)
|
||||
* [Workflow](../workflow/steps)
|
||||
* [Workflow](../workflow/workflow)
|
||||
|
||||
[1]: ../oam/oam-model
|
||||
[2]: ../oam/x-definition
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
---
|
||||
title: Workflow Context
|
||||
---
|
||||
|
||||
When defining the CUE template of the WorkflowStepDefinition,
|
||||
you can use the `context` to get metadata of the Application.
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
}
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
workload: patch: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: context.name
|
||||
version: context.labels["version"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When defining the CUE template of the WorkflowStepDefinition,
|
||||
you can use the `context` to get metadata of the Application.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```yaml
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: my-step
|
||||
spec:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
}
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
workload: patch: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: context.name
|
||||
version: context.labels["version"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When we deploy the following Application:
|
||||
|
||||
```yaml
|
||||
kind: Application
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
version: v1.0
|
||||
spec:
|
||||
workflow:
|
||||
steps:
|
||||
- name: example
|
||||
type: my-step
|
||||
properties:
|
||||
component: example
|
||||
```
|
||||
|
||||
Now `context.XXX` will be filled with the corresponding Application's metadata:
|
||||
|
||||
```
|
||||
apply: op.#ApplyComponent & {
|
||||
...
|
||||
app: "example-app" // context.name
|
||||
version: "v1.0" // context.labels["version"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: CUE Actions
|
||||
title: Appendix - CUE Actions
|
||||
---
|
||||
|
||||
This doc will illustrate the CUE actions provided in `vela/op` stdlib package.
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Custom Workflow
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
---
|
||||
title: Data Flow
|
||||
---
|
||||
|
||||
## What's Data Flow
|
||||
|
||||
In KubeVela, data flow enables users to pass data from one workflow step to another.
|
||||
You can orchestrate the data flow by specifying declarative config -- inputs and outputs of each step.
|
||||
This doc will explain how to specify data inputs and outputs.
|
||||
|
||||
> Full example available at: https://github.com/oam-dev/kubevela/blob/master/docs/examples/workflow
|
||||
|
||||
## Outputs
|
||||
|
||||
An output exports the data corresponding to a key in the CUE template of a workflow step.
|
||||
Once the workflow step has finished running, the output will have the data from the key.
|
||||
|
||||
Here is an example to specify the output in Application:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
- name: deploy-server1
|
||||
type: apply-component
|
||||
properties:
|
||||
component: "server1"
|
||||
outputs:
|
||||
- name: server1IP
|
||||
# Any key can be exported from the CUE template of the Definition
|
||||
exportKey: "myIP"
|
||||
```
|
||||
|
||||
Here is an example CUE template that contains the export key:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-component
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
}
|
||||
// load component from application
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
}
|
||||
// apply workload to Kubernetes cluster
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
}
|
||||
// export podIP
|
||||
myIP: apply.workload.status.podIP
|
||||
```
|
||||
|
||||
The output can then be used by the input in the following.
|
||||
|
||||
## Inputs
|
||||
|
||||
An input takes the data of an output to fill a parameter in the CUE template of a workflow step.
|
||||
The parameter will be filled before running the workflow step.
|
||||
|
||||
Here is an example to specify the input in Application:
|
||||
|
||||
```yaml
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
...
|
||||
- name: deploy-server2
|
||||
type: apply-with-ip
|
||||
inputs:
|
||||
- from: server1IP
|
||||
parameterKey: serverIP
|
||||
properties:
|
||||
component: "server2"
|
||||
```
|
||||
|
||||
Here is an example CUE template that takes the input parameter:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-with-ip
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
// the input value will be used to fill this parameter
|
||||
serverIP?: string
|
||||
}
|
||||
// load component from application
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
value: {}
|
||||
}
|
||||
// apply workload to Kubernetes cluster
|
||||
apply: op.#Apply & {
|
||||
value: {
|
||||
component.value.workload
|
||||
metadata: name: parameter.component
|
||||
if parameter.serverIP!=_|_{
|
||||
// this data will override the env fields of the workload container
|
||||
spec: containers: [{env: [{name: "PrefixIP",value: parameter.serverIP}]}]
|
||||
}
|
||||
}
|
||||
}
|
||||
// wait until workload.status equal "Running"
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: apply.value.status.phase =="Running"
|
||||
}
|
||||
```
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
---
|
||||
title: Steps
|
||||
---
|
||||
|
||||
## What's a Step
|
||||
|
||||
A Workflow Step instantiates from a Definition and runs the instance.
|
||||
It corresponds to find a Definition by the `type` field:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
- name: deploy-server1
|
||||
# This is the name of the Definition to actually create an executable instance
|
||||
type: apply-component
|
||||
properties:
|
||||
component: server1
|
||||
...
|
||||
```
|
||||
|
||||
## How to define a Step
|
||||
|
||||
The platform admin prepares the WorkflowStepDefinitions for developers to use.
|
||||
Basically the Definition provides the templated process to automate operation tasks.
|
||||
This hides the complexities and exposes only high-level parameters to simplify user experience.
|
||||
Here's an example of a Definition:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-component
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
prefixIP?: string
|
||||
}
|
||||
// load component from application
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
}
|
||||
// apply workload to Kubernetes cluster
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
}
|
||||
// wait until workload.status equal "Running"
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: apply.workload.status.phase =="Running"
|
||||
}
|
||||
// export podIP
|
||||
myIP: apply.workload.status.podIP
|
||||
```
|
||||
|
||||
## User Parameters
|
||||
|
||||
Inside the CUE template, the parameters exposed to users are defined in the `parameters` key.
|
||||
The workflow step properties from the Application will be used to fill the parameters.
|
||||
Besides properties, we also support data flow to input parameter values from outputs of other steps.
|
||||
|
||||
## CUE Actions
|
||||
|
||||
The rest of CUE keys are actions that will be executed in order by KubeVela.
|
||||
To learn about how to compose such actions, read [CUE Actions Reference](./cue-actions)
|
||||
|
|
@ -16,18 +16,17 @@ We can use `vela def` to define workflow steps by writing `Cue templates`. Let's
|
|||
|
||||
### Workflow Steps
|
||||
|
||||
KubeVela provides several CUE actions for writing workflow steps. These actions are provided by the `vela/op` package.
|
||||
KubeVela provides several CUE actions for writing workflow steps. These actions are provided by the `vela/op` package. In order to achieve the above scenario, we need to use the following three CUE actions:
|
||||
|
||||
| Action | Description | Parameter |
|
||||
| :---: | :--: | :-- |
|
||||
| ApplyApplication | Apply all the resources in Application. | - |
|
||||
| Read | Read resources in Kubernetes cluster. | value: the resource metadata to be get. And after successful execution, `value` will be updated with resource definition in cluster.<br /> err: if an error occurs, the `err` will contain the error message. |
|
||||
| ConditionalWait | The workflow step will be blocked until the condition is met. | continue: The workflow step will be blocked until the value becomes `true`. |
|
||||
| ... | ... | ... |
|
||||
| [ApplyApplication](./cue-actions#apply) | Apply all the resources in Application. | - |
|
||||
| [Read](./cue-actions#read) | Read resources in Kubernetes cluster. | value: the resource metadata to be get. And after successful execution, `value` will be updated with resource definition in cluster.<br /> err: if an error occurs, the `err` will contain the error message. |
|
||||
| [ConditionalWait](./cue-actions#conditionalwait) | The workflow step will be blocked until the condition is met. | continue: The workflow step will be blocked until the value becomes `true`. |
|
||||
|
||||
> For all the workflow actions, please refer to [Cue Actions](./cue-actions)
|
||||
|
||||
We need two `WorkflowStepDefinitions` to complete the Application:
|
||||
After this, we need two `WorkflowStepDefinitions` to complete the Application:
|
||||
|
||||
1. Apply Tomcat and wait till it's status become running. We need to write a custom workflow step for it.
|
||||
2. Send Slack notifications, we can use the built-in [webhook-notification] step for it.
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 实践案例
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 实践案例
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 实践案例
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 实践案例
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 实践案例
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -158,7 +158,7 @@ KubeVela 的工作流机制允许用户自定义应用部署计划中的步骤
|
|||
|
||||
关于工作流,你可以从[指定环境部署](../end-user/workflow/multi-env)这个工作流节点类型开始逐次了解更多 KubeVela 当前的内置工作流节点类型。
|
||||
|
||||
如果你是熟悉 Kubernetes 的平台管理员,你可以[学习创建自定义工作流节点类型](../platform-engineers/workflow/steps),或者通过[设计文档](https://github.com/oam-dev/kubevela/blob/master/design/vela-core/workflow_policy.md)了解工作流系统背后的设计和架构.
|
||||
如果你是熟悉 Kubernetes 的平台管理员,你可以[学习创建自定义工作流节点类型](../platform-engineers/workflow/workflow),或者通过[设计文档](https://github.com/oam-dev/kubevela/blob/master/design/vela-core/workflow_policy.md)了解工作流系统背后的设计和架构.
|
||||
|
||||
## 下一步
|
||||
|
||||
|
|
|
|||
|
|
@ -123,5 +123,5 @@ EOF
|
|||
|
||||
- [组件可观测性](../../component-observability)
|
||||
- [应用组件间的依赖和参数传递](../../component-dependency-parameter)
|
||||
- [多应用、多环境、多集群编排](../../multi-app-env-cluster)
|
||||
- [多应用、多环境、多集群编排](../../../case-studies/multi-app-env-cluster)
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ NAME COMPONENT TYPE PHASE HEALTHY STATUS AGE
|
|||
policy-demo nginx-server webservice running true 65s
|
||||
```
|
||||
|
||||
如果你想使用 `env-binding` 在多集群环境下创建应用部署计划,请参考 **[应用多集群部署](../multi-app-env-cluster)** 。
|
||||
如果你想使用 `env-binding` 在多集群环境下创建应用部署计划,请参考 **[应用多集群部署](../../case-studies/multi-app-env-cluster)** 。
|
||||
|
||||
## 参数说明
|
||||
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ KubeVela 背后提供的开箱即用的能力,包括组件、运维功能、
|
|||
* 了解更多[自定义组件](../components/custom-component)的功能。
|
||||
* 了解更多[自定义运维能力](../traits/customize-trait)的功能。
|
||||
* 了解[自定义策略](../policy/custom-policy)背后的功能。
|
||||
* 了解[自定义工作流](../workflow/custom-workflow)背后的功能。
|
||||
* 了解[自定义工作流](../workflow/workflow)背后的功能。
|
||||
|
||||
[1]: ../oam/oam-model
|
||||
[2]: ../oam/x-definition
|
||||
|
|
|
|||
|
|
@ -0,0 +1,245 @@
|
|||
---
|
||||
title: 更多用法
|
||||
---
|
||||
|
||||
CUE 作为一种配置语言,可以让你在定义对象的时候使用更多进阶用法。
|
||||
|
||||
## 一次渲染多个资源
|
||||
|
||||
你可以在 `outputs` 里定义 For 循环。
|
||||
|
||||
> 注意在 For 循环里的 `parameter` 字段必须是 map 类型。
|
||||
|
||||
看看如下这个例子,在一个 `TraitDefinition` 对象里渲染多个 `Service`:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: expose
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
parameter: {
|
||||
http: [string]: int
|
||||
}
|
||||
|
||||
outputs: {
|
||||
for k, v in parameter.http {
|
||||
"\(k)": {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [{
|
||||
port: v
|
||||
targetPort: v
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这个运维特征可以这样使用:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: testapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
...
|
||||
traits:
|
||||
- type: expose
|
||||
properties:
|
||||
http:
|
||||
myservice1: 8080
|
||||
myservice2: 8081
|
||||
```
|
||||
|
||||
## 自定义运维特征里执行 HTTP Request
|
||||
|
||||
`TraitDefinition` 对象可以发送 HTTP 请求并获取应答,让你可以通过关键字 `processing` 来渲染资源。
|
||||
|
||||
你可以在 `processing.http` 里定义 HTTP 请求的 `method`, `url`, `body`, `header` 和 `trailer`,然后返回的数据将被存储在 `processing.output` 中。
|
||||
|
||||
> 请确保目标 HTTP 服务器返回的数据是 JSON 格式
|
||||
|
||||
接着,你就可以通过 `patch` 或者 `output/outputs` 里的 `processing.output` 来引用返回数据了。
|
||||
|
||||
下面是一个示例:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: auth-service
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
parameter: {
|
||||
serviceURL: string
|
||||
}
|
||||
|
||||
processing: {
|
||||
output: {
|
||||
token?: string
|
||||
}
|
||||
// The target server will return a JSON data with `token` as key.
|
||||
http: {
|
||||
method: *"GET" | string
|
||||
url: parameter.serviceURL
|
||||
request: {
|
||||
body?: bytes
|
||||
header: {}
|
||||
trailer: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patch: {
|
||||
data: token: processing.output.token
|
||||
}
|
||||
```
|
||||
|
||||
在上面这个例子中,`TraitDefinition` 对象发送请求来获取 `token` 的数据,然后将这些数据补丁给组件实例。
|
||||
|
||||
## 数据传递
|
||||
|
||||
`TraitDefinition` 对象可以读取特定 `ComponentDefinition` 对象生成的 API 资源(渲染自 `output` 和 `outputs`)。
|
||||
|
||||
> KubeVela 保证了 `ComponentDefinition` 一定会在 `TraitDefinition` 之前渲染
|
||||
|
||||
具体来说,`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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
---
|
||||
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
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在渲染 `worker` `ComponentDefinition` 时,具体发生了:
|
||||
1. 渲染的 `Deployment` 资源放在 `context.output` 中。
|
||||
2. 其它类型资源则放进 `context.outputs.<xx>` 中,同时 `<xx>` 是在特指 `template.outputs` 的唯一名字
|
||||
|
||||
因而,`TraitDefinition` 对象可以从 `context` 里读取渲染后的 API 资源(比如 `context.outputs.gameconfig.data.enemies` 这个字段)。
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
title: 自定义运维特征
|
||||
---
|
||||
|
||||
|
||||
本节介绍如何自定义运维特征,为用户的组件增添任何需要的运维特征能力。
|
||||
|
||||
### 开始之前
|
||||
|
||||
请先阅读和理解 [运维特征定义](../oam/x-definition.md#运维特征定义(traitdefinition))
|
||||
|
||||
### 如何使用
|
||||
|
||||
我们首先为你展示一个简单的示例,比如直接引用已有的 Kubernetes API 资源 Ingress。来编写一个下面这样的 YAML 文件:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: customize-ingress
|
||||
spec:
|
||||
definitionRef:
|
||||
name: ingresses.networking.k8s.io
|
||||
```
|
||||
|
||||
为了和我们已经内置的 ingress 有所区分,我们将其命名为 `customize-ingress`。然后我们部署到运行时集群:
|
||||
|
||||
```
|
||||
$ kubectl apply -f customize-ingress.yaml
|
||||
traitdefinition.core.oam.dev/customize-ingress created
|
||||
```
|
||||
|
||||
创建成功。这时候,你的用户可以通过 `vela traits` 查看到这个能力:
|
||||
|
||||
```
|
||||
$ vela traits
|
||||
NAME NAMESPACE APPLIES-TO CONFLICTS-WITH POD-DISRUPTIVE DESCRIPTION
|
||||
customize-ingress default false description not defined
|
||||
ingress default false description not defined
|
||||
annotations vela-system deployments.apps true Add annotations for your Workload.
|
||||
configmap vela-system deployments.apps true Create/Attach configmaps to workloads.
|
||||
cpuscaler vela-system deployments.apps false Automatically scale the component based on CPU usage.
|
||||
expose vela-system deployments.apps false Expose port to enable web traffic for your component.
|
||||
hostalias vela-system deployment.apps false Add host aliases to workloads.
|
||||
labels vela-system deployments.apps true Add labels for your Workload.
|
||||
lifecycle vela-system deployments.apps true Add lifecycle hooks to workloads.
|
||||
resource vela-system deployments.apps true Add resource requests and limits to workloads.
|
||||
rollout vela-system false rollout the component
|
||||
scaler vela-system deployments.apps false Manually scale the component.
|
||||
service-binding vela-system webservice,worker false Binding secrets of cloud resources to component env
|
||||
sidecar vela-system deployments.apps true Inject a sidecar container to the component.
|
||||
volumes vela-system deployments.apps true Add volumes for your Workload.
|
||||
```
|
||||
|
||||
最后用户只需要把这个自定义的运维特征,放入一个与之匹配的组件中进行使用即可:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: testapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
cmd:
|
||||
- node
|
||||
- server.js
|
||||
image: oamdev/testapp:v1
|
||||
port: 8080
|
||||
traits:
|
||||
- type: customize-ingress
|
||||
properties:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /testpath
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: test
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
参照上面的开发过程,你可以继续自定义其它需要的 Kubernetes 资源来提供给你的用户。
|
||||
|
||||
请注意:这种自定义运维特征的方式中,是无法设置诸如 `annotations` 这样的元信息(metadata),来作为运维特征属性的。也就是说,当你只想简单引入自己的 CRD 资源或者控制器作为运维特征时,可以遵循这种做法。
|
||||
|
||||
#### 使用 CUE 来自定义运维特征
|
||||
|
||||
我们更推荐你使用 CUE 模版来自定义运维特征。这种方法给你可以模版化任何资源和资源的灵活性。比如,我们可以组合自定义 `Service` 和 `ingeress` 成为一个运维特征来使用。
|
||||
|
||||
在用法上,你需要把所有的运维特征定义在 `outputs` 里(注意,不是 `output`),格式如下:
|
||||
|
||||
|
||||
```cue
|
||||
outputs: <unique-name>:
|
||||
<full template data>
|
||||
```
|
||||
|
||||
我们下面同样使用一个 `ingress` 和 `Service` 的示例进行讲解:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: cue-ingress
|
||||
spec:
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
parameter: {
|
||||
domain: string
|
||||
http: [string]: int
|
||||
}
|
||||
|
||||
// 我们可以在一个运维特征 CUE 模版定义多个 outputs
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: {
|
||||
annotations: {
|
||||
address-type: "intranet"
|
||||
}
|
||||
}
|
||||
spec: {
|
||||
selector:
|
||||
app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
|
||||
type: "LoadBalancer"
|
||||
}
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
spec: {
|
||||
rules: [{
|
||||
host: parameter.domain
|
||||
http: {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
可以看到,`parameter` 字段让我们可以自由自定义和传递业务参数。同时在 `metadata` 的 `annotations` 里可以标记任何你们需要的信息,我们上文的例子里标记了 `Service` 是一个给内网使用的负载均衡。
|
||||
|
||||
接下来我们把这个 cue-ingress YMAL 部署到运行时集群,成功之后用户同样可以通过 `vela traits` 命令,查看到这个新生成的运维特征:
|
||||
|
||||
```shell
|
||||
$ kubectl apply -f cue-ingress.yaml
|
||||
traitdefinition.core.oam.dev/cue-ingress created
|
||||
$ vela traits
|
||||
NAME NAMESPACE APPLIES-TO CONFLICTS-WITH POD-DISRUPTIVE DESCRIPTION
|
||||
cue-ingress default false description not defined
|
||||
ingress default false description not defined
|
||||
annotations vela-system deployments.apps true Add annotations for your Workload.
|
||||
configmap vela-system deployments.apps true Create/Attach configmaps to workloads.
|
||||
cpuscaler vela-system deployments.apps false Automatically scale the component based on CPU usage.
|
||||
expose vela-system deployments.apps false Expose port to enable web traffic for your component.
|
||||
hostalias vela-system deployment.apps false Add host aliases to workloads.
|
||||
labels vela-system deployments.apps true Add labels for your Workload.
|
||||
lifecycle vela-system deployments.apps true Add lifecycle hooks to workloads.
|
||||
resource vela-system deployments.apps true Add resource requests and limits to workloads.
|
||||
rollout vela-system false rollout the component
|
||||
scaler vela-system deployments.apps false Manually scale the component.
|
||||
service-binding vela-system webservice,worker false Binding secrets of cloud resources to component env
|
||||
sidecar vela-system deployments.apps true Inject a sidecar container to the component.
|
||||
volumes vela-system deployments.apps true Add volumes for your Workload.
|
||||
```
|
||||
|
||||
最后用户将这个运维特征放入对应组件,通过应用部署计划完成交付:
|
||||
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: testapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
cmd:
|
||||
- node
|
||||
- server.js
|
||||
image: oamdev/testapp:v1
|
||||
port: 8080
|
||||
traits:
|
||||
- type: cue-ingress
|
||||
properties:
|
||||
domain: test.my.domain
|
||||
http:
|
||||
"/api": 8080
|
||||
```
|
||||
|
||||
基于 CUE 的运维特征定义方式,也提供了满足于更多业务场景的用法,比如给运维特征打补丁、传递数据等等。后面的文档将进一步介绍相关内容。
|
||||
|
|
@ -0,0 +1,505 @@
|
|||
---
|
||||
title: 补丁型特征
|
||||
---
|
||||
|
||||
在自定义运维特征中,使用补丁型特征是一种比较常用的形式。
|
||||
|
||||
它让我们可以修改、补丁某些属性给组件对象(一般是工作负载)来完成特定操作,比如更新 `sidecar` 和节点亲和性(node affinity)的规则(并且,这个操作一定是在资源往集群部署前就已经生效)。
|
||||
|
||||
当我们的组件是从第三方提供并自定义而来的时候,由于它们的模版往往是固定不可变的,所以能使用补丁型特征就显得尤为有用了。
|
||||
|
||||
> 尽管运维特征是由 CUE 来定义,它能打补丁的组件类型并不限,不管是来自 CUE、Helm 还是其余支持的模版格式
|
||||
|
||||
下面,我们通过一个节点亲和性(node affinity)的例子,讲解如何使用补丁型特征:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "affinity specify node affinity and toleration"
|
||||
name: node-affinity
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {
|
||||
spec: template: spec: {
|
||||
if parameter.affinity != _|_ {
|
||||
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: [{
|
||||
matchExpressions: [
|
||||
for k, v in parameter.affinity {
|
||||
key: k
|
||||
operator: "In"
|
||||
values: v
|
||||
},
|
||||
]}]
|
||||
}
|
||||
if parameter.tolerations != _|_ {
|
||||
tolerations: [
|
||||
for k, v in parameter.tolerations {
|
||||
effect: "NoSchedule"
|
||||
key: k
|
||||
operator: "Equal"
|
||||
value: v
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
affinity?: [string]: [...string]
|
||||
tolerations?: [string]: string
|
||||
}
|
||||
```
|
||||
|
||||
具体来说,我们上面的这个补丁型特征,假定了使用它的组件对象将会使用 `spec.template.spec.affinity` 这个字段。因此,我们需要用 `appliesToWorkloads` 来指明,让当前运维特征被应用到拥有这个字段的对应工作负载实例上。
|
||||
|
||||
另一个重要的字段是 `podDisruptive`,这个补丁型特征将修改 Pod 模板字段,因此对该运维特征的任何字段进行更改,都会导致 Pod 重启。我们应该增加 `podDisruptive` 并且设置它的值为 true,以此告诉用户这个运维特征生效后将导致 Pod 重新启动。
|
||||
|
||||
现在用户只需要,声明他们希望增加一个节点亲和性的规则到组件实例当中:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: testapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/testapp:v1
|
||||
traits:
|
||||
- type: "node-affinity"
|
||||
properties:
|
||||
affinity:
|
||||
server-owner: ["owner1","owner2"]
|
||||
resource-pool: ["pool1","pool2","pool3"]
|
||||
tolerations:
|
||||
resource-pool: "broken-pool1"
|
||||
server-owner: "old-owner"
|
||||
```
|
||||
|
||||
### 待解决的短板
|
||||
|
||||
默认来说,补丁型特征是通过 CUE 的 `merge` 操作来实现的。它有以下限制:
|
||||
|
||||
- 不能处理有冲突的字段名
|
||||
- 比方说,在一个组件实例中已经设置过这样的值 `replicas=5`,那一旦有运维特征实例,尝试给 `replicas` 字段的值打补丁就会失败。所以我们建议你提前规划好,不要在组件和运维特征之间使用重复的字段名。
|
||||
- 数组列表被补丁时,会按索引顺序进行合并。如果数组里出现了重复的值,将导致问题。为了规避这个风险,请查询后面的解决方案。
|
||||
|
||||
### 策略补丁
|
||||
|
||||
策略补丁,通过增加注解(annotation)而生效,并支持如下两种模式。
|
||||
|
||||
> 请注意,这里开始并不是 CUE 官方提供的功能, 而是 KubeVela 扩展开发而来
|
||||
|
||||
#### 1. 使用 `+patchKey=<key_name>` 注解
|
||||
|
||||
这个注解,是给数组列表打补丁用的。它的执行方式也不遵循 CUE 官方的方式,而是将每一个数组列表视作对象,并执行如下的策略:
|
||||
- 如果发现重复的键名,补丁数据会直接替换掉它的值
|
||||
- 如果没有重复键名,补丁则会自动附加这些数据
|
||||
|
||||
下面来看看,一个使用 'patchKey' 的策略补丁:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "add sidecar to the app"
|
||||
name: sidecar
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {
|
||||
// +patchKey=name
|
||||
spec: template: spec: containers: [parameter]
|
||||
}
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
command?: [...string]
|
||||
}
|
||||
```
|
||||
在上述的这个例子中,我们定义了要 `patchKey` 的字段 `name`,是来自容器的参数键名。如果工作负载中并没有同名的容器,那么一个 sidecar 容器就会被加到 `spec.template.spec.containers` 数组列表中。如果工作负载中有重名的 `sidecar` 运维特征,则会执行 merge 操作而不是附加。
|
||||
|
||||
如果 `patch` 和 `outputs` 同时存在于一个运维特征定义中,`patch` 会率先被执行然后再渲染 `outputs`。
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "expose the app"
|
||||
name: expose
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {spec: template: metadata: labels: app: context.name}
|
||||
outputs: service: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
http: [string]: int
|
||||
}
|
||||
```
|
||||
在上面这个运维特征定义中,我们将会把一个 `Service` 添加到给定的组件实例上。同时会先去给工作负载类型打上补丁数据,然后基于模版里的 `outputs` 渲染余下的资源。
|
||||
|
||||
#### 2. 使用 `+patchStrategy=retainkeys` 注解
|
||||
|
||||
这个注解的策略,与 Kubernetes 官方的 [retainkeys](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/#use-strategic-merge-patch-to-update-a-deployment-using-the-retainkeys-strategy) 策略类似。
|
||||
|
||||
在一些场景下,整个对象需要被一起替换掉,使用 `retainkeys` 就是最适合的办法。
|
||||
|
||||
假定一个 `Deployment` 对象是这样编写的:
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: retainkeys-demo
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
type: rollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 30%
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: retainkeys-demo-ctr
|
||||
image: nginx
|
||||
```
|
||||
|
||||
现在如果我们想替换掉 `rollingUpdate` 策略,你可以这样写:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: recreate
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
extension:
|
||||
template: |-
|
||||
patch: {
|
||||
spec: {
|
||||
// +patchStrategy=retainKeys
|
||||
strategy: type: "Recreate"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这个 YAML 资源将变更为:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: retainkeys-demo
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: retainkeys-demo-ctr
|
||||
image: nginx
|
||||
```
|
||||
## 更多补丁型特征的使用场景
|
||||
|
||||
补丁型特征,针对组件层面做些整体操作时,非常有用。我们看看还可以满足哪些需求:
|
||||
|
||||
### 增加标签
|
||||
|
||||
比如说,我们要给组件实例打上 `virtualgroup` 的通用标签。
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "Add virtual group labels"
|
||||
name: virtualgroup
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {
|
||||
spec: template: {
|
||||
metadata: labels: {
|
||||
if parameter.scope == "namespace" {
|
||||
"app.namespace.virtual.group": parameter.group
|
||||
}
|
||||
if parameter.scope == "cluster" {
|
||||
"app.cluster.virtual.group": parameter.group
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
group: *"default" | string
|
||||
scope: *"namespace" | string
|
||||
}
|
||||
```
|
||||
|
||||
然后这样用就可以了:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
traits:
|
||||
- type: virtualgroup
|
||||
properties:
|
||||
group: "my-group1"
|
||||
scope: "cluster"
|
||||
```
|
||||
|
||||
### 增加注解
|
||||
|
||||
与通用标签类似,你也可以给组件实例打补丁,增加一些注解。注解的格式,必须是 JSON。
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "Specify auto scale by annotation"
|
||||
name: kautoscale
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import "encoding/json"
|
||||
|
||||
patch: {
|
||||
metadata: annotations: {
|
||||
"my.custom.autoscale.annotation": json.Marshal({
|
||||
"minReplicas": parameter.min
|
||||
"maxReplicas": parameter.max
|
||||
})
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
min: *1 | int
|
||||
max: *3 | int
|
||||
}
|
||||
```
|
||||
|
||||
### 增加 Pod 环境变量
|
||||
|
||||
给 Pod 去注入环境变量也是非常常见的操作。
|
||||
|
||||
> 这种使用方式依赖策略补丁而生效, 所以记得加上 `+patchKey=name`
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "add env into your pods"
|
||||
name: env
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {
|
||||
spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [{
|
||||
name: context.name
|
||||
// +patchKey=name
|
||||
env: [
|
||||
for k, v in parameter.env {
|
||||
name: k
|
||||
value: v
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
env: [string]: string
|
||||
}
|
||||
```
|
||||
|
||||
### 基于外部鉴权服务注入 `ServiceAccount`
|
||||
|
||||
在这个场景下,service-account 是从一个鉴权服务中动态获取、再通过打补丁给到应用的。
|
||||
|
||||
我们这里展示的是,将 UID token 放进 `HTTP header` 的例子。你也可以用 `HTTP body` 来完成需求。
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "dynamically specify service account"
|
||||
name: service-account
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
processing: {
|
||||
output: {
|
||||
credentials?: string
|
||||
}
|
||||
http: {
|
||||
method: *"GET" | string
|
||||
url: parameter.serviceURL
|
||||
request: {
|
||||
header: {
|
||||
"authorization.token": parameter.uidtoken
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
patch: {
|
||||
spec: template: spec: serviceAccountName: processing.output.credentials
|
||||
}
|
||||
|
||||
parameter: {
|
||||
uidtoken: string
|
||||
serviceURL: string
|
||||
}
|
||||
```
|
||||
|
||||
### 增加 `InitContainer`
|
||||
|
||||
[`InitContainer`](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-initialization/#create-a-pod-that-has-an-init-container) 常用于预定义镜像内的操作,并且在承载应用的容器运行前就跑起来。
|
||||
|
||||
看看示例:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "add an init container and use shared volume with pod"
|
||||
name: init-container
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: {
|
||||
spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [{
|
||||
name: context.name
|
||||
// +patchKey=name
|
||||
volumeMounts: [{
|
||||
name: parameter.mountName
|
||||
mountPath: parameter.appMountPath
|
||||
}]
|
||||
}]
|
||||
initContainers: [{
|
||||
name: parameter.name
|
||||
image: parameter.image
|
||||
if parameter.command != _|_ {
|
||||
command: parameter.command
|
||||
}
|
||||
|
||||
// +patchKey=name
|
||||
volumeMounts: [{
|
||||
name: parameter.mountName
|
||||
mountPath: parameter.initMountPath
|
||||
}]
|
||||
}]
|
||||
// +patchKey=name
|
||||
volumes: [{
|
||||
name: parameter.mountName
|
||||
emptyDir: {}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
command?: [...string]
|
||||
mountName: *"workdir" | string
|
||||
appMountPath: string
|
||||
initMountPath: string
|
||||
}
|
||||
```
|
||||
|
||||
用法像这样:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: testapp
|
||||
spec:
|
||||
components:
|
||||
- name: express-server
|
||||
type: webservice
|
||||
properties:
|
||||
image: oamdev/testapp:v1
|
||||
traits:
|
||||
- type: "init-container"
|
||||
properties:
|
||||
name: "install-container"
|
||||
image: "busybox"
|
||||
command:
|
||||
- wget
|
||||
- "-O"
|
||||
- "/work-dir/index.html"
|
||||
- http://info.cern.ch
|
||||
mountName: "workdir"
|
||||
appMountPath: "/usr/share/nginx/html"
|
||||
initMountPath: "/work-dir"
|
||||
```
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
title: 状态回写
|
||||
---
|
||||
|
||||
本文档将为你讲解,如何通过 CUE 模版在定义对象时实现状态回写。
|
||||
|
||||
## 健康检查
|
||||
|
||||
不管是组件定义中,还是运维特征定义中,健康检查对应的配置项都是 `spec.status.healthPolicy`。如果没有定义,它的值默认是 `true`。
|
||||
|
||||
在 CUE 里的关键词是 `isHealth`,CUE 表达式结果必须是 `bool` 类型。
|
||||
KubeVela 运行时会一直检查 CUE 表达式,直至其状态显示为健康。每次控制器都会获取所有的 Kubernetes 资源,并将他们填充到 context 字段中。
|
||||
|
||||
所以 context 字段会包含如下信息:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <Kubernetes workload resource>
|
||||
outputs: {
|
||||
<resource1>: <Kubernetes trait resource1>
|
||||
<resource2>: <Kubernetes trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
`Trait` 对象,没有 `context.output` 这个字段,其它字段相同。
|
||||
|
||||
我们看看健康检查的例子:
|
||||
|
||||
```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
|
||||
...
|
||||
```
|
||||
|
||||
健康检查的结果将会记录到 `Application` 对象中。
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## 自定义状态
|
||||
|
||||
不管是组件定义中,还是运维特征定义中,自定义状态对应的配置项都是 `spec.status.customStatus`。
|
||||
|
||||
在 CUE 中的关键词是 `message`。同时,CUE 表达式的结果必须是 `string` 类型。
|
||||
|
||||
自定义状态和健康检查的原理一致。`Application` 对象的 CRD 控制器都会检查 CUE 表达式,直至显示健康通过。
|
||||
|
||||
context 字段包含如下信息:
|
||||
|
||||
```cue
|
||||
context:{
|
||||
name: <component name>
|
||||
appName: <app name>
|
||||
output: <Kubernetes workload resource>
|
||||
outputs: {
|
||||
<resource1>: <Kubernetes trait resource1>
|
||||
<resource2>: <Kubernetes trait resource2>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`Trait` 对象不会有 `context.output` 这个字段, 其它字段一致.
|
||||
|
||||
查看示例:
|
||||
|
||||
```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
|
||||
...
|
||||
```
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
---
|
||||
title: 工作流上下文
|
||||
---
|
||||
|
||||
用户在定义 WorkflowStepDefinition 时可以使用 `context` 来获取该 Application 的任意元信息。
|
||||
|
||||
下面是一个例子:
|
||||
|
||||
```yaml
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: my-step
|
||||
spec:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
}
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
workload: patch: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: context.name
|
||||
version: context.labels["version"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
当我们部署如下的 Application 时:
|
||||
|
||||
```yaml
|
||||
kind: Application
|
||||
metadata:
|
||||
name: example-app
|
||||
labels:
|
||||
version: v1.0
|
||||
spec:
|
||||
workflow:
|
||||
steps:
|
||||
- name: example
|
||||
type: my-step
|
||||
properties:
|
||||
component: example
|
||||
```
|
||||
|
||||
这时候 `context.XXX` 将填写相应的 Application 元信息:
|
||||
|
||||
```
|
||||
apply: op.#ApplyComponent & {
|
||||
...
|
||||
app: "example-app" // context.name
|
||||
version: "v1.0" // context.labels["version"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: CUE 操作
|
||||
title: 附录:CUE 操作符
|
||||
---
|
||||
|
||||
这个文档介绍 step 定义过程中,可以使用的 CUE 操作类型。这些操作均由 `vela/op` 包提供。
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: 自定义工作流
|
||||
---
|
||||
|
||||
TBD
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
---
|
||||
title: 数据流
|
||||
---
|
||||
|
||||
## 数据流是什么
|
||||
|
||||
KubeVela 里的数据流是用来赋能用户在不同的工作流步骤里传递数据的手段。
|
||||
用户使用数据流的方式是通过编写声明式的字段:即每一个步骤的输入输出 (inputs/outputs)。
|
||||
这篇文档将阐述如何通过编写这些字段来使用数据流功能。
|
||||
|
||||
> 完整版例子请参考这个链接: https://github.com/oam-dev/kubevela/blob/master/docs/examples/workflow
|
||||
|
||||
## 输出字段 (Outputs)
|
||||
|
||||
一个输出字段可以将一个步骤对应的 CUE 模板中的某个 Key 的数据给输出出来。
|
||||
输出的数据可以在工作流接下来的步骤中被当做输入来使用。
|
||||
|
||||
下面是一个如何在 Application 中编写输出字段 (Outputs) 的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
- name: deploy-server1
|
||||
type: apply-component
|
||||
properties:
|
||||
component: "server1"
|
||||
outputs:
|
||||
- name: server1IP
|
||||
# 任何键值都可以从定义的 CUE 模板导出
|
||||
exportKey: "myIP"
|
||||
```
|
||||
|
||||
与上面对应,使用一个 CUE 模版提供输出字段如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-component
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
}
|
||||
// 从 Application 中加载组件
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
}
|
||||
// 将组件部署到集群中
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
}
|
||||
// 输出 podIP
|
||||
myIP: apply.workload.status.podIP
|
||||
```
|
||||
|
||||
可以看到,当我们在 WorkflowStepDefinition 的 CUE 模板里定义 `myIP` 字段,并且当 Application 里 outputs 的 exportKey 也指定了 `myIP` 字段时,它的值将被输出出去。我们将在下面看到输出值该如何使用。
|
||||
|
||||
## 输入字段 (Inputs)
|
||||
|
||||
输入字段可以对应前面输出的值,然后将输出的值用于填值该步骤的 CUE 模板的指定参数。
|
||||
参数会在工作流步骤运行前先被填值。
|
||||
|
||||
下面是一个如何在 Application 中编写输入字段 (Outputs) 的例子:
|
||||
|
||||
```yaml
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
...
|
||||
- name: deploy-server2
|
||||
type: apply-with-ip
|
||||
inputs:
|
||||
- from: server1IP
|
||||
parameterKey: serverIP
|
||||
properties:
|
||||
component: "server2"
|
||||
```
|
||||
|
||||
可以看到,`deploy-server2` 工作流步骤中 inputs 有一个 `from: server1IP` 对应了之前的 `deploy-server1` 步骤的一个输出字段。
|
||||
到这里前面的输出值这时候将被用来给 `deploy-server2` 的参数 `serverIP` 填值。
|
||||
|
||||
下面是 `deploy-server2` 对应的 `apply-with-ip` WorkflowStepDefinition 的定义:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-with-ip
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
// 输入值将用于填充该参数
|
||||
serverIP?: string
|
||||
}
|
||||
// 加载组件
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
value: {}
|
||||
}
|
||||
// 将组件部署到集群中
|
||||
apply: op.#Apply & {
|
||||
value: {
|
||||
component.value.workload
|
||||
metadata: name: parameter.component
|
||||
if parameter.serverIP!=_|_{
|
||||
// 该字段将覆盖工作负载容器的 env 字段
|
||||
spec: containers: [{env: [{name: "PrefixIP",value: parameter.serverIP}]}]
|
||||
}
|
||||
}
|
||||
}
|
||||
// 等待直至 workload.status 变成 "Running"
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: apply.value.status.phase =="Running"
|
||||
}
|
||||
```
|
||||
|
||||
可以看到,这个步骤渲染的对象是需要拿到 `serverIP`,也就是之前部署的服务的 IP 来作为环境变量传入。
|
||||
至此,我们完成了一个完整的数据流传递的例子。
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
---
|
||||
title: 工作流步骤
|
||||
---
|
||||
|
||||
## 工作流步骤是什么
|
||||
|
||||
一个工作流步骤 (Step) 从一个定义 (Definition) 的模板出发来实例化出一个对象,并运行它。
|
||||
工作流步骤是通过 `type` 字段来找到对应的定义:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
spec:
|
||||
...
|
||||
workflow:
|
||||
steps:
|
||||
- name: deploy-server1
|
||||
# type 名与对应的 WorkflowStepDefinition 名称相同
|
||||
type: apply-component
|
||||
properties:
|
||||
component: server1
|
||||
...
|
||||
```
|
||||
|
||||
## 如何定义一个步骤?
|
||||
|
||||
一般平台管理员会预先设置好工作流步骤的定义 (WorkflowStepDefinition) 来给开发者使用。
|
||||
这些定义包含了写好模板的自动化流程去执行过程式任务。
|
||||
这样一来,那些复杂的底层信息会被屏蔽掉,而暴露给用户的都是简单易用的参数。
|
||||
|
||||
下面是一个定义的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
name: apply-component
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import ("vela/op")
|
||||
parameter: {
|
||||
component: string
|
||||
prefixIP?: string
|
||||
}
|
||||
// 加载组件
|
||||
component: op.#Load & {
|
||||
component: parameter.component
|
||||
}
|
||||
// 将组件部署到集群中
|
||||
apply: op.#ApplyComponent & {
|
||||
component: parameter.component
|
||||
}
|
||||
// 等待直至 workload.status 变成 "Running"
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: apply.workload.status.phase =="Running"
|
||||
}
|
||||
// 输出 podIP
|
||||
myIP: apply.workload.status.podIP
|
||||
```
|
||||
|
||||
## 用户参数
|
||||
|
||||
在 CUE 模板里面,暴露给用户的参数将被定义在 `parameters` 字段中。
|
||||
在 Application 中的工作流步骤的属性值将被用来给这些参数填值。
|
||||
此外,我们还支持了使用数据流的方式用其他步骤的输出来为一个步骤的参数填值。
|
||||
|
||||
## CUE 动作指令
|
||||
|
||||
剩下的 CUE 字段将作为动作指令被逐步执行。
|
||||
如需知晓更多关于如何编写这些 CUE 动作指令的细节,敬请阅读[CUE 操作文档](./cue-actions)。
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: 工作流
|
||||
title: 自定义工作流
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
|
@ -16,18 +16,17 @@ KubeVela 的工作流机制允许你自定义应用部署计划中的步骤,
|
|||
|
||||
### 编写工作流步骤
|
||||
|
||||
KubeVela 提供了一些 CUE 操作类型用于编写工作流步骤。这些操作均由 `vela/op` 包提供。
|
||||
KubeVela 提供了一些 CUE 操作类型用于编写工作流步骤。这些操作均由 `vela/op` 包提供。为了实现上述场景,我们需要使用以下 3 个 CUE 操作:
|
||||
|
||||
| 操作名 | 说明 | 参数 |
|
||||
| :---: | :--: | :-- |
|
||||
| ApplyApplication | 部署应用中的所有资源 | - |
|
||||
| Read | 读取 Kubernetes 集群中的资源。 | value: 描述需要被读取资源的元数据,比如 kind、name 等,操作完成后,集群中资源的数据会被填充到 `value` 上。<br /> err: 如果读取操作发生错误,这里会以字符串的方式指示错误信息。 |
|
||||
| ConditionalWait | 会让 Workflow Step 处于等待状态,直到条件被满足。 | continue: 当该字段为 true 时,Workflow Step 才会恢复继续执行。 |
|
||||
| ... | ... | ... |
|
||||
| [ApplyApplication](./cue-actions#apply) | 部署应用中的所有资源 | - |
|
||||
| [Read](./cue-actions#read) | 读取 Kubernetes 集群中的资源。 | value: 描述需要被读取资源的元数据,比如 kind、name 等,操作完成后,集群中资源的数据会被填充到 `value` 上。<br /> err: 如果读取操作发生错误,这里会以字符串的方式指示错误信息。 |
|
||||
| [ConditionalWait](./cue-actions#conditionalwait) | 会让 Workflow Step 处于等待状态,直到条件被满足。 | continue: 当该字段为 true 时,Workflow Step 才会恢复继续执行。 |
|
||||
|
||||
> 所有的操作类型可参考 [Cue Actions](./cue-actions)
|
||||
|
||||
为了完成这个场景,我们需要两个 `WorkflowStepDefinition`:
|
||||
在此基础上,我们需要两个 `WorkflowStepDefinition`:
|
||||
|
||||
1. 部署 Tomcat,并且等待 Deployment 的状态变为 running,这一步需要自定义工作流步骤来实现。
|
||||
2. 发送 Slack 通知,这一步可以使用 KubeVela 内置的 [webhook-notification] 步骤来实现。
|
||||
|
|
|
|||
28
sidebars.js
28
sidebars.js
|
|
@ -21,6 +21,18 @@ module.exports = {
|
|||
'core-concepts/application',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Case Studies',
|
||||
collapsed: false,
|
||||
items: [
|
||||
'case-studies/jenkins-cicd',
|
||||
// 'case-studies/multi-app-env-cluster',
|
||||
// 'case-studies/workflow-edge-computing', // 待完成
|
||||
// 'case-studies/li-auto-inc', 暂时下掉,应该改写成一个 10 - 15 分钟体验的产品 lab 例子
|
||||
// 'case-studies/workflow-with-ocm',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'End User Guide',
|
||||
|
|
@ -107,17 +119,6 @@ module.exports = {
|
|||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Case Studies',
|
||||
collapsed: false,
|
||||
items: [
|
||||
'case-studies/jenkins-cicd'
|
||||
// 'case-studies/workflow-edge-computing', // 待完成
|
||||
// 'case-studies/li-auto-inc', 暂时下掉,应该改写成一个 10 - 15 分钟体验的产品 lab 例子
|
||||
// 'case-studies/workflow-with-ocm',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Platform Admin Guide',
|
||||
|
|
@ -165,9 +166,8 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
'Workflow System': [
|
||||
'platform-engineers/workflow/steps',
|
||||
'platform-engineers/workflow/context',
|
||||
'platform-engineers/workflow/data-flow',
|
||||
'platform-engineers/workflow/workflow',
|
||||
'platform-engineers/workflow/built-in-workflow-defs',
|
||||
'platform-engineers/workflow/cue-actions',
|
||||
]
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue