编程知识 cdmana.com

How to bring a new feature to your k8s PAAS in 20 minutes?

 The first figure .png author | Sun Jianbo ( tianyuan ) source | Alibaba cloud official account

Last month, ,KubeVela Official release 了 , As a simple and highly scalable application management platform and core engine , It can be said that the majority of platform engineers use to build their own cloud native PaaS My weapon . So this article takes a practical example , Explain how to do it in 20 Within minutes , For you based on KubeVela Of PaaS “ go online “ A new ability .

Before you officially begin the tutorial of this document , Please make sure you have the right Installed KubeVela And it depends on K8s Environmental Science .

KubeVela The basic structure of the extension

KubeVela The basic structure of is shown in the figure :

1.png

Simply speaking ,KubeVela By adding Workload Type and Trait To expand capabilities for users , The service provider of the platform through Definition File registration and extension , Go up through Appfile It shows the extended function . The basic writing process is also given in the official documents , among 2 Yes Workload An extension example of , One is Trait An extension example of :

We use a built-in WorkloadDefinition For example, let's introduce Definition The basic structure of the document :

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: webservice
  annotations:
    definition.oam.dev/description: "`Webservice` is a workload type to describe 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 `Web Service` type."
spec:
  definitionRef:
    name: deployments.apps
  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
      }

At first glance, it's quite long , It seems very complicated , But don't worry , In fact, it is divided into two parts :

  • Without extended fields Definition Registration part
  • for Appfile Extension template used (CUE Template) part

Let's take it apart and introduce , In fact, it's easy to learn .

Without extended fields Definition Registration part

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: webservice
  annotations:
    definition.oam.dev/description: "`Webservice` is a workload type to describe 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 `Web Service` type."
spec:
  definitionRef:
    name: deployments.apps

This part is full of calculation 11 That's ok , Among them is 3 OK, it's an introduction to webservice The function of ,5 Lines are fixed formats . Only 2 A line has specific information :

  definitionRef:
    name: deployments.apps

These two lines mean this Definition Behind the scenes CRD What is the name , The format is <resources>.<api-group>. understand K8s You should know K8s The most commonly used method is through api-group, version and kind Location resources , and kind stay K8s restful API The corresponding in is resources. We are familiar with Deployment and ingress For example , Its corresponding relationship is as follows :

image.png

Here's a little more , Why kind And one more resources The concept of ? Because a CRD except kind There are also some things like status,replica Such fields hope to be similar to spec Itself decoupled in restful API Update separately in , therefore resources except kind The corresponding one , There will be some extra resources, Such as Deployment Of status Expressed as deployments/status.

So I believe you're smart enough to understand that it doesn't include extension Under the circumstances ,Definition How to write , The simplest is based on K8s The combination of resources , Just fill in the following three angle brackets .

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: < Write the name here >
spec:
  definitionRef:
    name: < Write here resources>.< Write here api-group>

Register for operation and maintenance features (TraitDefinition) In the same way .

apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
  name: < Write the name here >
spec:
  definitionRef:
    name: < Write here resources>.< Write here api-group>

So the Ingress As KubeVela It's an extension of the :

apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
  name:  ingress
spec:
  definitionRef:
    name: ingresses.networking.k8s.io

besides ,TraitDefinition Some other function model layer functions have been added in , Such as :

  • appliesToWorkloads: Express this trait What can it do to Workload type .
  • conflictWith: Express this trait And what other types of trait There are conflicts .
  • workloadRefPath: Express this trait Contains workload Which field is ,KubeVela It's generating trait Object is automatically filled in . ...

These features are optional , The use of , In the following other articles, we will give you a detailed introduction to .

So here we go , I believe you have mastered one that does not contain extensions The basic extension mode of , And the rest is around CUE The abstract template of .

for Appfile Extension template used (CUE Template) part

Yes CUE Students who are interested in it can refer to this article CUE Basic introduction Do more to understand , Limited to the length of this article CUE It doesn't expand itself in detail .

As we all know KubeVela Of Appfile It's very concise , however K8s Is a relatively complex object YAML, And in order to keep it simple and extensible ,KubeVela Provides a bridge from complexity to simplicity . This is it. Definition in CUE Template The role of .

CUE format template

Let's take a look at one first Deployment Of YAML file , As shown below , A lot of it is a fixed framework ( The template section ), There are only a few fields that users need to fill in ( Parameters of the part ).

apiVersion: apps/v1
kind: Deployment
meadata:
  name: mytest
spec:
  template:
    spec:
      containers:
      - name: mytest
        env:
        - name: a
          value: b
        image: nginx:v1
    metadata:
      labels:
        app.oam.dev/component: mytest
  selector:
    matchLabels:
      app.oam.dev/component: mytest

stay KubeVela in ,Definition The fixed format of a document is divided into output and parameter Two parts . among output It's about “ The template section ”, and parameter It's the parameter part .

So let's take the top Deployment YAML Rewrite into Definition The format of the template in .

output: {
    apiVersion: "apps/v1"
    kind:       "Deployment"
    metadata: name: "mytest"
    spec: {
        selector: matchLabels: {
            "app.oam.dev/component": "mytest"
        }
        template: {
            metadata: labels: {
                "app.oam.dev/component": "mytest"
            }
            spec: {
                containers: [{
                    name:  "mytest"
                    image: "nginx:v1"
                    env: [{name:"a",value:"b"}]
                }]
            }}}
}

This format follows json It's like , In fact, this is CUE The format of , and CUE Is itself a json Superset . in other words ,CUE The format of is satisfying JSON Based on the rules , Added some simple rules , Make it easier to read and use :

  • C The annotation style of language .
  • Double quotation marks for field names can be used by default without special symbols .
  • The comma at the end of the field value can default to , The comma at the end of the field will not be wrong .
  • The outermost braces can be omitted .

CUE Template parameters for the format -- Variable references

Write the template part , Let's build the parameters section , And this parameter is actually a reference to a variable .

parameter: {
    name: string
    image: string
}
output: {
    apiVersion: "apps/v1"
    kind:       "Deployment"
    spec: {
        selector: matchLabels: {
            "app.oam.dev/component": parameter.name
        }
        template: {
            metadata: labels: {
                "app.oam.dev/component": parameter.name
            }
            spec: {
                containers: [{
                    name:  parameter.name
                    image: parameter.image
                }]
            }}}
}

As the example above shows ,KubeVela The template parameters in are defined by parameter This part is to complete , and parameter It's essentially a quotation , Replaced output Some of the fields in .

complete Definition And in Appfile Use

in fact , After the combination of the above two parts , We can already write a complete Definition file :

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: mydeploy
spec:
  definitionRef:
    name: deployments.apps
  extension:
    template: |
        parameter: {
            name: string
            image: string
        }
        output: {
            apiVersion: "apps/v1"
            kind:       "Deployment"
            spec: {
                selector: matchLabels: {
                    "app.oam.dev/component": parameter.name
                }
                template: {
                    metadata: labels: {
                        "app.oam.dev/component": parameter.name
                    }
                    spec: {
                        containers: [{
                            name:  parameter.name
                            image: parameter.image
                        }]
                    }}}
        }

For the convenience of debugging , Generally, it can be divided into two files in advance , Part of the front yaml part , Assume the name is def.yaml Such as :

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: mydeploy
spec:
  definitionRef:
    name: deployments.apps
  extension:
    template: |

The other put cue file , Assume the name is def.cue

parameter: {
    name: string
    image: string
}
output: {
    apiVersion: "apps/v1"
    kind:       "Deployment"
    spec: {
        selector: matchLabels: {
            "app.oam.dev/component": parameter.name
        }
        template: {
            metadata: labels: {
                "app.oam.dev/component": parameter.name
            }
            spec: {
                containers: [{
                    name:  parameter.name
                    image: parameter.image
                }]
            }}}
}

First pair def.cue Make a format , While formatting cue The tool itself does some validation , It can also go deeper adopt cue Command to debug :

cue fmt def.cue

After debugging , You can script this yaml assemble :

./hack/vela-templates/mergedef.sh def.yaml def.cue > mydeploy.yaml

Put this again. yaml file apply To K8s In the cluster .

$ kubectl apply -f mydeploy.yaml
workloaddefinition.core.oam.dev/mydeploy created

Once the new capabilities kubectl apply here we are Kubernetes in , Don't have to restart , No need to update ,KubeVela You can see a new capability appear and use it immediately :

$ vela worklaods
Automatically discover capabilities successfully  Add(1) Update(0) Delete(0)

TYPE           CATEGORY    DESCRIPTION
+mydeploy      workload    description not defined

NAME        DESCRIPTION
mydeploy    description not defined

stay Appfile In the following way :

name: my-extend-app
services:
  mysvc:
    type: mydeploy
    image: crccheck/hello-world
    name: mysvc

perform vela up You can get this running :

$ vela up -f docs/examples/blog-extension/my-extend-app.yaml
Parsing vela appfile ...
Loading templates ...

Rendering configs for service (mysvc)...
Writing deploy config to (.vela/deploy.yaml)

Applying deploy configs ...
Checking if app has been deployed...
App has not been deployed, creating a new deployment...
 App has been deployed 
    Port forward: vela port-forward my-extend-app
             SSH: vela exec my-extend-app
         Logging: vela logs my-extend-app
      App status: vela status my-extend-app
  Service status: vela status my-extend-app --svc mysvc

Let's take a look at the status of the app , It's working properly (HEALTHY Ready: 1/1):

$ vela status my-extend-app
About:

  Name:          my-extend-app
  Namespace:     env-application
  Created at:    2020-12-15 16:32:25.08233 +0800 CST
  Updated at:    2020-12-15 16:32:25.08233 +0800 CST

Services:

  - Name: mysvc
    Type: mydeploy
    HEALTHY Ready: 1/1

Definition Advanced usage in templates

Above, we have experienced the extension by replacing the most basic function with the template KubeVela The whole process , besides , Maybe you have some more complex needs , Such as conditional judgment , loop , Complex types, etc , Need some advanced usage .

Structural parameters

If there are some parameter types in the template that are more complex , Contains structures and nested multiple structures , You can use structure to define .

  1. Define a structure type , contain 1 A string member 、1 Integers and 1 Structural members .
#Config: {
 name:  string
 value: int
 other: {
   key: string
   value: string
 }
}
  1. Use this struct type in variables , And use it as an array .
parameter: {
 name: string
 image: string
 config: [...#Config]
}
  1. The same goal is to use variable references as well .
output: {
   ...
         spec: {
             containers: [{
                 name:  parameter.name
                 image: parameter.image
                 env: parameter.config
             }]
         }
    ...
}
  1. Appfile It's written according to parameter Defining the structure of writing .
name: my-extend-app
services:
mysvc:
 type: mydeploy
 image: crccheck/hello-world
 name: mysvc
 config:
 - name: a
   value: 1
   other:
     key: mykey
     value: myvalue

conditional

Sometimes, whether some parameters are added or not depends on a certain condition :

parameter: {
    name:   string
    image:  string
    useENV: bool
}
output: {
    ...
    spec: {
        containers: [{
            name:  parameter.name
            image: parameter.image
            if parameter.useENV == true {
                env: [{name: "my-env", value: "my-value"}]
            }
        }]
    }
    ...
}

stay Appfile It's writing values .

name: my-extend-app
services:
  mysvc:
    type: mydeploy
    image: crccheck/hello-world
    name: mysvc
    useENV: true

Default parameter

In some cases, parameters may not exist , It is not required , At this time, it is generally necessary to use the condition judgment , When a field doesn't exist , The judgment condition is _variable != _|_.

parameter: {
    name: string
    image: string
    config?: [...#Config]
}
output: {
    ...
    spec: {
        containers: [{
            name:  parameter.name
            image: parameter.image
            if parameter.config != _|_ {
                config: parameter.config
            }
        }]
    }
    ...
}

In this case Appfile Of config It's not required , Fill in and render , No rendering without filling .

The default value is

For some parameters, if you want to set a default value , It can be written in this way .

parameter: {
    name: string
    image: *"nginx:v1" | string
}
output: {
    ...
    spec: {
        containers: [{
            name:  parameter.name
            image: parameter.image
        }]
    }
    ...
}

This is the time Appfile You can not write image This parameter , By default "nginx:v1":

name: my-extend-app
services:
  mysvc:
    type: mydeploy
    name: mysvc

loop

Map A cycle of types

parameter: {
    name:  string
    image: string
    env: [string]: string
}
output: {
    spec: {
        containers: [{
            name:  parameter.name
            image: parameter.image
            env: [
                for k, v in parameter.env {
                    name:  k
                    value: v
                },
            ]
        }]
    }
}

Appfile Writing in Chinese :

name: my-extend-app
services:
  mysvc:
    type: mydeploy
    name:  "mysvc"
    image: "nginx"
    env:
      env1: value1
      env2: value2

Loop of array type

parameter: {
    name:  string
    image: string
    env: [...{name:string,value:string}]
}
output: {
  ...
     spec: {
        containers: [{
            name:  parameter.name
            image: parameter.image
            env: [
                for _, v in parameter.env {
                    name:  v.name
                    value: v.value
                },
            ]
        }]
    }
}

Appfile Writing in Chinese :

name: my-extend-app
services:
  mysvc:
    type: mydeploy
    name:  "mysvc"
    image: "nginx"
    env:
    - name: env1
      value: value1
    - name: env2
      value: value2

KubeVela Built in context Variable

You may have noticed , We are parameter As defined in name Each time the Appfile in I actually wrote it twice , Once in services below ( Every service They are distinguished by their names ), The other is in the specific name In the parameters . In fact, what is repeated here should not be written by the user again , therefore KubeVela A built-in context, It contains some general context information , Such as application name 、 Secret key, etc . Use it directly in the template context There's no need to add an extra name Parameters , KubeVela When you run the render template, it will be passed in automatically .

parameter: {
    image: string
}
output: {
  ...
    spec: {
        containers: [{
            name:  context.name
            image: parameter.image
        }]
    }
  ...
}

KubeVela Note enhancement in

KubeVela Also on the cuelang Some extensions have been made to the comments for , Easy to automatically generate documents and be CLI Use .

 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]
       ...
      }

among ,+usgae The comment at the beginning becomes the description of the parameter ,+short The opening comment is followed by CLI Abbreviations used in .

summary

In this paper, through the actual case and detailed description , Introduced to you in KubeVela The detailed process and principle of a new capability in , And the writing method of capability template .

Here you may have another question , After the platform administrator adds a new capability like this , How can users of the platform know how to use this capability ? Actually , stay KubeVela in , It's not only convenient to add new capabilities , It can also automatically for “ Ability ” Generate Markdown Using the document format ! Don't believe it , You can see KubeVela Its official website , All in References/Capabilities Directory of the ability to use the document ( such as This ), All of them are automatically generated according to the template of each ability . Last , Welcome to write some interesting extensions , Submitted to the KubeVela Of Community warehouse In the to .

If you have any questions , Welcome to nail search group numbers :23310022 Join the community .

版权声明
本文为[Alibaba cloud native]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224120454521Y.html

Scroll to Top