mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
update docs & fix vela cap uninstall. (#1319)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Managing Capabilities
|
||||
|
||||
In KubeVela, developers can install more capabilities (i.e. new workload types and traits) from any GitHub repo that contains OAM definition files. We call these GitHub repos as _Capability Centers_.
|
||||
In KubeVela, developers can install more capabilities (i.e. new component types and traits) from any GitHub repo that contains OAM definition files. We call these GitHub repos as _Capability Centers_.
|
||||
|
||||
KubeVela is able to discover OAM definition files in this repo automatically and sync them to your own KubeVela platform.
|
||||
|
||||
@@ -44,88 +44,88 @@ Or, list all available capabilities in certain center.
|
||||
|
||||
```bash
|
||||
$ vela cap ls my-center
|
||||
NAME CENTER TYPE DEFINITION STATUS APPLIES-TO
|
||||
kubewatch my-center trait kubewatches.labs.bitnami.com uninstalled []
|
||||
NAME CENTER TYPE DEFINITION STATUS APPLIES-TO
|
||||
clonesetservice my-center componentDefinition clonesets.apps.kruise.io uninstalled []
|
||||
```
|
||||
|
||||
## Install a capability from capability center
|
||||
|
||||
Now let's try to install the new trait named `kubewatch` from `my-center` to your own KubeVela platform.
|
||||
Now let's try to install the new component named `clonesetservice` from `my-center` to your own KubeVela platform.
|
||||
|
||||
> [KubeWatch](https://github.com/bitnami-labs/kubewatch) is a Kubernetes plugin that watches events and publishes notifications to Slack channel etc. We can use it as a trait to watch important changes of your app and notify the platform administrators via Slack.
|
||||
You need to install OpenKruise first.
|
||||
|
||||
Install `kubewatch` trait from `my-center`.
|
||||
```shell
|
||||
helm install kruise https://github.com/openkruise/kruise/releases/download/v0.7.0/kruise-chart.tgz
|
||||
```
|
||||
|
||||
Install `clonesetservice` component from `my-center`.
|
||||
|
||||
```bash
|
||||
$ vela cap install my-center/kubewatch
|
||||
Installing trait capability kubewatch
|
||||
"my-repo" has been added to your repositories
|
||||
2020/11/06 16:19:30 [debug] creating 1 resource(s)
|
||||
2020/11/06 16:19:30 [debug] CRD kubewatches.labs.bitnami.com is already present. Skipping.
|
||||
2020/11/06 16:19:37 [debug] creating 3 resource(s)
|
||||
Successfully installed chart (kubewatch) with release name (kubewatch)
|
||||
Successfully installed capability kubewatch from my-center
|
||||
$ vela cap install my-center/clonesetservice
|
||||
Installing component capability clonesetservice
|
||||
Successfully installed capability clonesetservice from my-center
|
||||
```
|
||||
|
||||
## Use the newly installed capability
|
||||
|
||||
Let's check the `kubewatch` trait appears in your platform firstly:
|
||||
Let's check the `clonesetservice` appears in your platform firstly:
|
||||
|
||||
```bash
|
||||
$ vela traits
|
||||
Synchronizing capabilities from cluster⌛ ...
|
||||
Sync capabilities successfully ✅ (no changes)
|
||||
TYPE CATEGORY DESCRIPTION
|
||||
kubewatch trait Add a watch for resource
|
||||
...
|
||||
$ vela components
|
||||
NAME NAMESPACE WORKLOAD DESCRIPTION
|
||||
clonesetservice vela-system clonesets.apps.kruise.io 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.
|
||||
```
|
||||
|
||||
Great! Now let's deploy an app via Appfile.
|
||||
|
||||
|
||||
```bash
|
||||
$ cat << EOF > vela.yaml
|
||||
name: testapp
|
||||
services:
|
||||
testsvc:
|
||||
type: webservice
|
||||
type: clonesetservice
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
route:
|
||||
domain: testsvc.example.com
|
||||
EOF
|
||||
```
|
||||
|
||||
```bash
|
||||
$ vela up
|
||||
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...
|
||||
Updating: core.oam.dev/v1alpha2, Kind=HealthScope in default
|
||||
✅ App has been deployed 🚀🚀🚀
|
||||
Port forward: vela port-forward testapp
|
||||
SSH: vela exec testapp
|
||||
Logging: vela logs testapp
|
||||
App status: vela status testapp
|
||||
Service status: vela status testapp --svc testsvc
|
||||
```
|
||||
|
||||
Then let's add `kubewatch` as a trait in this Appfile.
|
||||
then you can Get a cloneset in your environment.
|
||||
|
||||
```bash
|
||||
$ cat << EOF >> vela.yaml
|
||||
kubewatch:
|
||||
webhook: https://hooks.slack.com/<your-token>
|
||||
EOF
|
||||
```shell
|
||||
$ kubectl get clonesets.apps.kruise.io
|
||||
NAME DESIRED UPDATED UPDATED_READY READY TOTAL AGE
|
||||
testsvc 1 1 1 1 1 46s
|
||||
```
|
||||
|
||||
> The `https://hooks.slack.com/<your-token>` is the Slack channel that your platform administrators are keeping an eye on.
|
||||
|
||||
Update the deployment:
|
||||
|
||||
```
|
||||
$ vela up
|
||||
```
|
||||
|
||||
Now, your platform administrators should receive notifications whenever important changes happen to your app. For example, a fresh new deployment.
|
||||
|
||||

|
||||
|
||||
## Uninstall a capability
|
||||
|
||||
> NOTE: make sure no apps are using the capability before uninstalling.
|
||||
|
||||
```bash
|
||||
$ vela cap uninstall my-center/kubewatch
|
||||
Successfully removed chart (kubewatch) with release name (kubewatch)
|
||||
$ vela cap uninstall my-center/clonesetservice
|
||||
Successfully uninstalled capability clonesetservice
|
||||
```
|
||||
|
||||
@@ -50,7 +50,7 @@ In a word, just like the fields shown in the sample, the helm schematic module d
|
||||
Here is an example `Application`.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
|
||||
@@ -5,7 +5,7 @@ and [virtualgroup](https://github.com/oam-dev/kubevela/blob/master/docs/examples
|
||||
to a Helm based component.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
@@ -65,7 +65,7 @@ workload.
|
||||
Let's make several changes on the configuration of the sample application.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: myapp
|
||||
|
||||
@@ -314,7 +314,7 @@ func uninstallCap(client client.Client, cap types.Capability, ioStreams cmdutil.
|
||||
case types.TypeScope:
|
||||
return fmt.Errorf("uninstall scope capability was not supported yet")
|
||||
case types.TypeComponentDefinition:
|
||||
// TODO(yangsoon): support uninstall componentDefinition here
|
||||
obj = &v1beta1.ComponentDefinition{ObjectMeta: v1.ObjectMeta{Name: cap.Name, Namespace: types.DefaultKubeVelaNS}}
|
||||
}
|
||||
if err := client.Delete(ctx, obj); err != nil {
|
||||
return err
|
||||
@@ -344,7 +344,9 @@ func uninstallCap(client client.Client, cap types.Capability, ioStreams cmdutil.
|
||||
case types.TypeScope:
|
||||
// TODO(wonderflow): add scope remove here.
|
||||
case types.TypeComponentDefinition:
|
||||
// TODO(yangsoon): add componenetDefinition remove here
|
||||
if err := os.Remove(filepath.Join(capdir, "", cap.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ioStreams.Infof("Successfully uninstalled capability %s", cap.Name)
|
||||
return nil
|
||||
|
||||
@@ -43,7 +43,7 @@ const DescriptionUndefined = "description not defined"
|
||||
|
||||
// GetCapabilitiesFromCluster will get capability from K8s cluster
|
||||
func GetCapabilitiesFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, error) {
|
||||
workloads, _, err := GetWorkloadsFromCluster(ctx, namespace, c, selector)
|
||||
workloads, _, err := GetComponentsFromCluster(ctx, namespace, c, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -89,6 +89,45 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c common.Arg
|
||||
return templates, templateErrors, nil
|
||||
}
|
||||
|
||||
// GetComponentsFromCluster will get capability from K8s cluster
|
||||
func GetComponentsFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := c.GetClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dm, err := discoverymapper.New(c.Config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var templates []types.Capability
|
||||
var componentsDefs v1beta1.ComponentDefinitionList
|
||||
err = newClient.List(ctx, &componentsDefs, &client.ListOptions{Namespace: namespace, LabelSelector: selector})
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("list ComponentDefinition err: %w", err)
|
||||
}
|
||||
|
||||
var templateErrors []error
|
||||
for _, cd := range componentsDefs.Items {
|
||||
ref, err := util.ConvertWorkloadGVK2Definition(dm, cd.Spec.Workload.Definition)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "convert workload definition `%s` failed", cd.Name))
|
||||
continue
|
||||
}
|
||||
tmp, err := HandleDefinition(cd.Name, ref.Name, cd.Annotations, cd.Spec.Extension, types.TypeComponentDefinition, nil, cd.Spec.Schematic)
|
||||
if err != nil {
|
||||
templateErrors = append(templateErrors, errors.Wrapf(err, "handle workload template `%s` failed", cd.Name))
|
||||
continue
|
||||
}
|
||||
tmp.Namespace = namespace
|
||||
if tmp, err = validateCapabilities(tmp, dm, cd.Name, ref); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
templates = append(templates, tmp)
|
||||
}
|
||||
return templates, templateErrors, nil
|
||||
}
|
||||
|
||||
// GetTraitsFromCluster will get capability from K8s cluster
|
||||
func GetTraitsFromCluster(ctx context.Context, namespace string, c common.Args, selector labels.Selector) ([]types.Capability, []error, error) {
|
||||
newClient, err := c.GetClient()
|
||||
|
||||
@@ -45,7 +45,7 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
deployment := types.Capability{
|
||||
Namespace: "testdef",
|
||||
Name: DeployName,
|
||||
Type: types.TypeWorkload,
|
||||
Type: types.TypeComponentDefinition,
|
||||
CrdName: "deployments.apps",
|
||||
Description: "description not defined",
|
||||
Parameters: []types.Parameter{
|
||||
@@ -78,7 +78,7 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
websvc := types.Capability{
|
||||
Namespace: "testdef",
|
||||
Name: WebserviceName,
|
||||
Type: types.TypeWorkload,
|
||||
Type: types.TypeComponentDefinition,
|
||||
Description: "description not defined",
|
||||
Parameters: []types.Parameter{{
|
||||
Name: "env", Type: cue.ListKind,
|
||||
@@ -108,10 +108,10 @@ var _ = Describe("DefinitionFiles", func() {
|
||||
|
||||
// Notice!! DefinitionPath Object is Cluster Scope object
|
||||
// which means objects created in other DefinitionNamespace will also affect here.
|
||||
It("getworkload", func() {
|
||||
workloadDefs, _, err := GetWorkloadsFromCluster(context.Background(), DefinitionNamespace, common.Args{Config: cfg, Schema: scheme}, selector)
|
||||
It("getcomponents", func() {
|
||||
workloadDefs, _, err := GetComponentsFromCluster(context.Background(), DefinitionNamespace, common.Args{Config: cfg, Schema: scheme}, selector)
|
||||
Expect(err).Should(BeNil())
|
||||
logf.Log.Info(fmt.Sprintf("Getting workload definitions %v", workloadDefs))
|
||||
logf.Log.Info(fmt.Sprintf("Getting component definitions %v", workloadDefs))
|
||||
for i := range workloadDefs {
|
||||
// CueTemplate should always be fulfilled, even those whose CueTemplateURI is assigend,
|
||||
By("check CueTemplate is fulfilled")
|
||||
|
||||
@@ -87,9 +87,17 @@ func LoadInstalledCapabilityWithType(userNamespace string, c common.Args, capT t
|
||||
return caps, nil
|
||||
case types.TypeScope:
|
||||
case types.TypeComponentDefinition:
|
||||
// TODO(yangsoon): support ComponentDefinition here
|
||||
caps, _, err := GetComponentsFromCluster(context.TODO(), userNamespace, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
systemCaps, _, err := GetComponentsFromCluster(context.TODO(), types.DefaultKubeVelaNS, c, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caps = append(caps, systemCaps...)
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ var testEnv *envtest.Environment
|
||||
var definitionDir string
|
||||
var td corev1beta1.TraitDefinition
|
||||
var wd, websvcWD corev1beta1.WorkloadDefinition
|
||||
var cd, websvcCD corev1beta1.ComponentDefinition
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
@@ -101,6 +102,15 @@ var _ = BeforeSuite(func(done Done) {
|
||||
logf.Log.Info("Creating workload definition", "data", wd)
|
||||
Expect(k8sClient.Create(ctx, &wd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
componentdata, err := ioutil.ReadFile("testdata/componentDef.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
Expect(yaml.Unmarshal(componentdata, &cd)).Should(BeNil())
|
||||
|
||||
cd.Namespace = DefinitionNamespace
|
||||
logf.Log.Info("Creating component definition", "data", cd)
|
||||
Expect(k8sClient.Create(ctx, &cd)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
websvcWorkloadData, err := ioutil.ReadFile("testdata/websvcWorkloadDef.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -109,6 +119,14 @@ var _ = BeforeSuite(func(done Done) {
|
||||
logf.Log.Info("Creating workload definition whose CUE template from remote", "data", &websvcWD)
|
||||
Expect(k8sClient.Create(ctx, &websvcWD)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
websvcComponentDefData, err := ioutil.ReadFile("testdata/websvcComponentDef.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
Expect(yaml.Unmarshal(websvcComponentDefData, &websvcCD)).Should(BeNil())
|
||||
websvcCD.Namespace = DefinitionNamespace
|
||||
logf.Log.Info("Creating component definition whose CUE template from remote", "data", &websvcCD)
|
||||
Expect(k8sClient.Create(ctx, &websvcCD)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
close(done)
|
||||
}, 60)
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: deployments.testapps
|
||||
labels:
|
||||
usecase: forplugintest
|
||||
spec:
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
containers: [{
|
||||
image: parameter.image
|
||||
name: context.name
|
||||
env: parameter.env
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
protocol: "TCP"
|
||||
name: "default"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
// +usage=Which port do you want customer traffic sent to
|
||||
// +short=p
|
||||
port: *8080 | int
|
||||
env: [...{
|
||||
name: string
|
||||
value: string
|
||||
}]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: webservice.testapps
|
||||
labels:
|
||||
usecase: forplugintest
|
||||
spec:
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
replicas: 1
|
||||
podSpec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
env: parameter.env
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Which port do you want customer traffic sent to
|
||||
// +short=p
|
||||
port: *6379 | int
|
||||
|
||||
env: [...{
|
||||
name: string
|
||||
value?: string
|
||||
valueFrom?: {
|
||||
secretKeyRef: {
|
||||
name: string
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
Reference in New Issue
Block a user