Como adicionar uma nova função ao seu K8s PaaS em 20 minutos?

Head picture.png
Autor | Fonte de Sun Jianbo (Tian Yuan)
| Conta oficial do Alibaba Cloud Native

No mês passado, o KubeVela foi lançado oficialmente como uma plataforma de gerenciamento de aplicativos e mecanismo central simples, fácil de usar e altamente escalonável. Pode-se dizer que é uma arma mágica para engenheiros de plataforma criarem seu próprio PaaS nativo da nuvem. Em seguida, este artigo usa um exemplo prático para explicar como "lançar" um novo recurso para você com base na PaaS do KubeVela em 20 minutos.

Antes de iniciar o tutorial deste documento, certifique-se de ter instalado o KubeVela e seu ambiente K8s dependente corretamente .

A estrutura básica da extensão KubeVela

A estrutura básica do KubeVela é mostrada na figura:

1.png

Para simplificar, o KubeVela expande os recursos para os usuários adicionando o tipo de carga de trabalho e o traço . O provedor de serviços da plataforma se registra e se expande por meio do arquivo de definição e revela a funcionalidade expandida por meio do Appfile para cima. O processo básico de escrita também é fornecido nos documentos oficiais, dois dos quais são exemplos de extensão de Carga de Trabalho e um é um exemplo de extensão de Traço:

Tomamos uma WorkloadDefinition integrada como exemplo para apresentar a estrutura básica do arquivo de definição:

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
      }

À primeira vista, parece muito longo e muito complicado, mas não se preocupe, na verdade ele está dividido em duas partes:

  • Definição de parte de registro sem campos de extensão
  • Seção CUE Template para Appfile

Vamos desmontá-lo e introduzi-lo lentamente, mas na verdade é muito fácil de aprender.

Definição de parte de registro sem campos de extensão

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

Esta parte ManDaManSuan linha 11, cuja linha 3 é introduzida na webservicefunção, as linhas 5 são de formato fixo. Apenas 2 linhas possuem informações específicas:

  definitionRef:
    name: deployments.apps

O significado dessas duas linhas representa o que o nome CRD é usado por trás desta Definição e seu formato <resources>.<api-group>. Os alunos do Aprenda K8s devem saber K8s mais comumente usados ​​por api-group, versione kindlocalizar recursos, e kindcorrespondente na API restful K8s resources. Com o familiar Deploymente ingress, por exemplo, sua correspondência é a seguinte:

image.png

Aqui está um pouco de conhecimento. Por que precisamos adicionar o conceito de recursos quando temos um tipo? Como um CRD tem alguns campos como status e réplica, além do próprio tipo, e espera ser desacoplado da própria especificação para ser atualizado separadamente na API restful, portanto, além do tipo correspondente aos recursos, haverá alguns recursos adicionais, como implantação O status é expresso como deployments/status.

Portanto, acredito que você seja inteligente o suficiente para entender como a definição deve ser escrita sem extensão. A maneira mais fácil é emendá-la de acordo com o método de combinação de recursos do K8s. Basta preencher os espaços nos três colchetes angulares a seguir.

apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
  name: <这里写名称>
spec:
  definitionRef:
    name: <这里写resources>.<这里写api-group>

Isso também é válido para o registro TraitDefinition.

apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
  name: <这里写名称>
spec:
  definitionRef:
    name: <这里写resources>.<这里写api-group>

Então, coloque Ingresscomo KubeVela está escrito na extensão:

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

Além disso, algumas outras funções da camada de modelo funcional foram adicionadas ao TraitDefinition, como:

  • appliesToWorkloads: Indica em quais tipos de carga de trabalho esse atributo pode atuar.
  • conflictWith: Indica que esta característica está em conflito com outros tipos de características.
  • workloadRefPath: Indica o campo de carga de trabalho contido nesta característica. KubeVela irá preenchê-lo automaticamente ao gerar o objeto de característica. ...

Essas funções são opcionais e não estão envolvidas neste artigo. Iremos apresentá-las em detalhes em outros artigos subsequentes.

Então, aqui, acredito que você tenha dominado um modo de extensão básico sem extensões, e o resto é o modelo abstrato em torno do CUE .

Seção CUE Template para Appfile

Os alunos interessados ​​no próprio CUE podem consultar esta introdução aos princípios básicos do CUE para compreender melhor. Devido às limitações de espaço, este artigo não se aprofundará no CUE em si.

Todo mundo sabe que o Appfile do KubeVela é muito conciso para escrever, mas o objeto do K8s é um YAML relativamente complexo. Para mantê-lo conciso sem perder a escalabilidade, o KubeVela fornece uma ponte da complexidade para a simplicidade. Esta é a função do modelo CUE na definição.

Modelo de formato CUE

Vejamos primeiro um arquivo YAML de implantação, conforme mostrado abaixo, muito do conteúdo é um quadro fixo (parte do modelo), o conteúdo que realmente precisa que o usuário preencha são, na verdade, alguns campos (parte do parâmetro).

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

Em KubeVela, o arquivo de definição de formato fixo é dividido outpute as parameterduas partes. Onde o outputconteúdo é a "seção Modelos", que parameterfaz parte do argumento.

Em seguida, vamos reescrever o YAML de implantação acima no formato do modelo na Definição.

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

Esse formato é muito semelhante ao json; na verdade, é o formato do CUE, e o próprio CUE é um superconjunto do json. Em outras palavras, o formato CUE atende às regras JSON e adiciona algumas regras simples para torná-lo mais fácil de ler e usar:

  • O estilo de comentário da linguagem C.
  • As aspas duplas que indicam o nome do campo podem ser padronizadas sem símbolos especiais.
  • A vírgula no final do valor do campo pode ser padronizada e não há erro se a vírgula no final do campo for gravada.
  • A cinta externa pode ser omitida.

Parâmetro de modelo no formato CUE - referência de variável

A parte do modelo está escrita, vamos construir a parte do parâmetro, e este parâmetro é na verdade uma referência de variável.

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

Conforme mostrado no exemplo acima, os parâmetros do modelo KubeVela são realizados por meio parameterdesta seção, mas parameteressencialmente como uma referência, substituindo outputdeterminado campo.

Definição completa e uso em Appfile

Na verdade, após a combinação das duas partes acima, já podemos escrever um arquivo de definição completo:

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

Para facilitar a depuração, em geral, pode ser previamente dividido em dois arquivos, a parte frontal da parte de descarga yaml assumida com o seguinte nome def.yaml:

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

O outro coloca o arquivo cue, supondo que o nome seja 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
                }]
            }}}
}

Primeiro, para def.cuefazer um formatado, formato, enquanto a própria ferramenta cue fará algumas verificações, também pode ser mais aprofundado para fazer o comando cue de depuração :

cue fmt def.cue

Após a depuração, você pode montar este yaml por meio de um script:

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

Em seguida, aplique esse arquivo yaml ao cluster K8s.

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

Assim que o novo recurso kubectl applyde Kubernetes entrar sem reiniciar, não atualize, os usuários do KubeVela podem ver imediatamente um novo recurso aparecer e você pode usar:

$ 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

Ele é usado no Appfile da seguinte forma:

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

A implementação vela upserá capaz de executar isso:


$ 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 

Acho que você gosta

Origin blog.51cto.com/13778063/2571763
Recomendado
Clasificación