kubevela 是 OAM 的实现,虽然是今年才发布的项目,但我们可以通过结合 kubevela 帮助我们更好地了解 OAM。
vela 安装:
$ vela install
- Installing Vela Core Chart:
created namespace vela-system
install chart vela-core, version v0.3.0, desc : A Helm chart for Kube Vela core, contains 36 file
Automatically discover capabilities successfully ✅ Add(8) Update(0) Delete(0)
⠋ Waiting Capability ready to install ...
TYPE CATEGORY DESCRIPTION
+task workload Describes jobs that run code or a script to completion.
+webservice workload Describes long-running, scalable, containerized services that have a stable
network endpoint to receive external network traffic from customers. If workload
type is skipped for any service defined in Appfile, it will be defaulted to
`webservice` type.
+worker workload Describes long-running, scalable, containerized services that running at
backend. They do NOT have network endpoint to receive external network
traffic.
+autoscale trait Automatically scales workloads by resource utilization metrics or cron
triggers.
+metrics trait Configures monitoring metrics for your service.
+rollout trait Configures Canary deployment strategy for your application.
+route trait Configures external access to your service.
+scaler trait Configures replicas for your service.
- Finished successfully.
可以看到kubevela
提供了 8 种资源,workload
类型的task
、webservice
、worker
,traint
类型的autoscale
,metrics
,rollout
,route
和scaler
。
这里出现了两个概念workload
和traint
,这是 OAM 定义的资源概念:
workload
类似于 k8s 的自定义资源(CR)的概念,用于基础设施人员自定义资源component
用于定义应用程序的基本组件,可以理解成一个job,一个db或一个deployment,一个 Component 中只能引用一个workload
taint
可以用于定义 component
的运维属性,比如路由,限流熔断策略,由最终的ApplicationConfiguration
将其和 component
组装ApplicationConfiguration
定义了一个应用程序的配置,通过component
和taint
模板,定义一个具体的运行实例可以看到 OAM 核心就是 组合和装配。
简单了解了 OAM 的几个概念之后,我们来看看 kubevela 提供哪些 workload
:
$ kubectl get WorkloadDefinition
NAME DEFINITION-NAME
task jobs.batch
webservice deployments.apps
worker deployments.apps
vela
提供了三种 workload: task, webservice, worker。其中 task 对应 k8s 中的 job.batch,webservice 和 worker 都是 deployments, webservice 提供更多能力,比如端口,环境变量,config设置等,下面是 webservice 的 workloadDefinition 定义:
$ kubectl get WorkloadDefinition webservice -oyaml | yq r - spec.extension.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
if parameter["cmd"] != _|_ {
command: parameter.cmd
}
if parameter["env"] != _|_ {
env: parameter.env
}
if context["config"] != _|_ {
env: context.config
}
ports: [{
containerPort: parameter.port
}]
if parameter["cpu"] != _|_ {
resources: {
limits:
cpu: parameter.cpu
requests:
cpu: parameter.cpu
}
}
}]
}
}
}
}
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]
// +usage=Which port do you want customer traffic sent to
// +short=p
port: *80 | int
// +usage=Define arguments by using environment variables
env?: [...{
// +usage=Environment variable name
name: string
// +usage=The value of the environment variable
value?: string
// +usage=Specifies a source the value of this var should come from
valueFrom?: {
// +usage=Selects a key of a secret in the pod's namespace
secretKeyRef: {
// +usage=The name of the secret in the pod's namespace to select from
name: string
// +usage=The key of the secret to select from. Must be a valid secret key
key: string
}
}
}]
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
cpu?: string
}
提供的traits
:
$ kubectl get traitDefinitions
NAME DEFINITION-NAME
autoscale autoscalers.standard.oam.dev
metrics metricstraits.standard.oam.dev
rollout canaries.flagger.app
route routes.standard.oam.dev
scaler manualscalertraits.core.oam.dev
vela
提供了五种 trait,自动扩容,metrics指标,回滚,路由和手动扩容,以最常见的 route 为例,我们看看 traits 的定义:
$ kubectl get traitDefinitions route -oyaml | yq r - spec.extension.template
output: {
apiVersion: "standard.oam.dev/v1alpha1"
kind: "Route"
spec: {
host: parameter.domain
if parameter.issuer != "" {
tls: {
issuerName: parameter.issuer
}
}
if parameter["rules"] != _|_ {
rules: parameter.rules
}
provider: *"nginx" | parameter.provider
}
}
parameter: {
// +usage= Domain name
domain: *"" | string
issuer: *"" | string
rules?: [...{
path: string
rewriteTarget: *"" | string
}]
provider?: string
}
最后是 scopes, scopes 表示作用域,主要用于分组和管理,比如可以将一个 component 划归到多个 scopes,一个scopes 也可以包含多个 component,因为在日常中 scopes 概念用的比较,因为用的比较少,这里就不细讲了,vela 提供了一个 healthscopes :
$ kubectl get scopedefinitions
NAME DEFINITION-NAME
healthscopes.core.oam.dev healthscopes.core.oam.dev
了解 OAM 应用的基本组成之后,我们基于 vela 来创建一个 Application ,并看他如何创建的。
我们构建一个webservice应用,这里就使用官方提供的案例:
$ cat vela.yaml
name: first-vela-app
services:
testsvc:
type: webservice
image: crccheck/hello-world
port: 8000
route:
domain: testsvc.example.com
$ vela up -f vela.yaml
Parsing vela appfile ...
Load Template ...
Rendering configs for service (testsvc)...
Writing deploy config to (.vela/deploy.yaml)
Applying application ...
Checking if app has been deployed...
App has not been deployed, creating a new deployment...
✅ App has been deployed ???
Port forward: vela port-forward first-vela-app
SSH: vela exec first-vela-app
Logging: vela logs first-vela-app
App status: vela status first-vela-app
Service status: vela status first-vela-app --svc testsvc
vela 会将 Appfile
渲染成 Application
资源。
我们看看 website 的Application
:
# kubectl get Application first-vela-app -oyaml
apiVersion: core.oam.dev/v1alpha2
kind: Application
metadata:
creationTimestamp: "2021-01-26T08:24:53Z"
generation: 1
name: first-vela-app
namespace: default
resourceVersion: "2662687"
selfLink: /apis/core.oam.dev/v1alpha2/namespaces/default/applications/first-vela-app
uid: a603e28a-b52a-4b5f-ae6c-be57de887c51
spec:
components:
- name: testsvc
scopes:
healthscopes.core.oam.dev: first-vela-app-default-health
settings:
image: crccheck/hello-world
port: 8000
traits:
- name: route
properties:
domain: testsvc.example.com
type: webservice
这个 Application
是 kubevela 的 appfile 服务端映射,其下层实现是由 ApplicationConfiguration
来做的。
我们可以看看ApplicationConfiguration
:
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
creationTimestamp: "2021-01-26T04:23:03Z"
finalizers:
- scope.finalizer.core.oam.dev
generation: 1
labels:
application.oam.dev: first-vela-app
name: first-vela-app
namespace: default
ownerReferences:
- apiVersion: core.oam.dev/v1alpha2
controller: true
kind: Application
name: first-vela-app
uid: 5b2c0284-0bd1-4c4c-a671-0fa8c7684b26
resourceVersion: "39680262"
selfLink: /apis/core.oam.dev/v1alpha2/namespaces/default/applicationconfigurations/first-vela-app
uid: 00bc284d-c57f-4b52-a177-31753520c619
spec:
components:
- componentName: testsvc
scopes:
- scopeRef:
apiVersion: core.oam.dev/v1alpha2
kind: HealthScope
name: first-vela-app-default-health
traits:
- trait:
apiVersion: standard.oam.dev/v1alpha1
kind: Route
metadata:
labels:
trait.oam.dev/type: route
spec:
host: testsvc.example.com
provider: nginx
status:
conditions:
- lastTransitionTime: "2021-01-31T22:49:03Z"
reason: ReconcileSuccess
status: "True"
type: Synced
dependency: {}
observedGeneration: 1
workloads:
- componentName: testsvc
componentRevisionName: testsvc-v3
scopes:
- scopeRef:
apiVersion: core.oam.dev/v1alpha2
kind: HealthScope
name: first-vela-app-default-health
traits:
- traitRef:
apiVersion: standard.oam.dev/v1alpha1
kind: Route
name: testsvc-route-c4575497d
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: testsvc
包含了一个 testsvc 的component
,这个 component 包含了一个 scopes 和 traits。
application 会根据 type 配置从 workload模板 中创建一个 component,我们看看 testsvc 的 component:
# kubectl get components testsvc -oyaml
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
creationTimestamp: "2021-01-26T08:24:55Z"
generation: 1
labels:
application.oam.dev: first-vela-app
name: testsvc
namespace: default
ownerReferences:
- apiVersion: core.oam.dev/v1alpha2
controller: true
kind: Application
name: first-vela-app
uid: a603e28a-b52a-4b5f-ae6c-be57de887c51
resourceVersion: "2662686"
selfLink: /apis/core.oam.dev/v1alpha2/namespaces/default/components/testsvc
uid: eb6a8f1a-c8e5-4140-b5e8-ad5864862c4b
spec:
workload:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
workload.oam.dev/type: webservice
spec:
selector:
matchLabels:
app.oam.dev/component: testsvc
template:
metadata:
labels:
app.oam.dev/component: testsvc
spec:
containers:
- image: crccheck/hello-world
name: testsvc
ports:
- containerPort: 8000
我们可以看到ApplicationConfiguration
和 Component
这两个资源都有 ownerReferences
,在 owner 资源被删除的时候,Kubernetes 垃圾收集器会自动将附属的资源清除。
OAM 提供了三种核心的模板来创建一个应用, components,traits 和 scopes,components 一般定义一些和基础设施相关模板,由平台团队提供,traits 定义和基础运维相关模板,由运维人员定义,scopes 偏向于两者都关心的部分。通过将应用拆分成不同的层次,让各部分只关注自己的那个专注的那个点,而不用对全局的关注。
vela 算是 OAM 的一种落地实现,定义几种通用的资源(worker,webservices,routes…),再通过 Appfile 渲染生成 Application。本质上和基于 helm 开发一套符合 OAM 标准的模板依赖一样,不过 vela 是运行在集群内部,对应用会更强的控制,和 helm 这种从集群中退下来(v3去掉tiller)变成纯粹部署工具的理念还是有些区别的。