github.com/oam-dev/kubevela@v1.9.11/design/vela-cli/def_zh.md (about)

     1  ---
     2  title: 使用CLI编写X-Definitions
     3  ---
     4  
     5  ## 简介
     6  
     7  `vela def` 是一组用来帮助用户管理编辑KubeVela中的Definition(包括 ComponentDefinition, TraitDefinition 等)的命令行工具。
     8  
     9  ## 使用背景
    10  
    11  在 KubeVela 中,Definition 的主要能力由 CUE 格式的 Template 来定义,作为一种基于 JSON 格式的语言,CUE 格式的 Template 与原生 Kubernetes 中的 YAML 格式并不相互兼容,在将 CUE 格式的 Template 嵌入 Kubernetes 的 YAML 中时,我们需要将 CUE 转换成为字符串格式,这使得 Definition 在原生 Kubernetes 工具 kubectl 中的使用变得较为复杂。比如一个简单的给已有 Component 打标签的 TraitDefinition 可以通过 `kubectl get trait labels -n vela-system -o yaml` 来获取。
    12  
    13  ```yaml
    14  apiVersion: core.oam.dev/v1beta1
    15  kind: TraitDefinition
    16  metadata:
    17    annotations:
    18      definition.oam.dev/description: Add labels for your Workload.
    19      meta.helm.sh/release-name: kubevela
    20      meta.helm.sh/release-namespace: vela-system
    21    creationTimestamp: "2021-08-05T07:06:58Z"
    22    generation: 1
    23    labels:
    24      app.kubernetes.io/managed-by: Helm
    25    name: labels
    26    namespace: vela-system
    27    resourceVersion: "8423"
    28    uid: 51a7f8b1-f14d-4776-b538-02ac54a55661
    29  spec:
    30    appliesToWorkloads:
    31    - deployments.apps
    32    podDisruptive: true
    33    schematic:
    34      cue:
    35        template: "patch: spec: template: metadata: labels: {\n\tfor k, v in parameter
    36          {\n\t\t\"\\(k)\": v\n\t}\n}\nparameter: [string]: string\n"
    37  status:
    38    configMapRef: schema-labels
    39    latestRevision:
    40      name: labels-v1
    41      revision: 1
    42      revisionHash: fe7fa9da440dc9d3
    43  ```
    44  
    45  可以看到,作为表达该 Definition 能力核心的 `spec.schematic.cue.template` 是一个经过转化的 CUE 字符串,但很难辨识与编辑。
    46  
    47  另一方面,CUE 语言虽然具有很强的表达能力,但作为一种较新语言的它对于很多 Kubernetes 开发者来说,相对有些陌生,直接编写 CUE 格式可能会花一些时间上手。
    48  
    49  因此,KubeVela 团队在 CLI 工具中加入了一系列相关功能,帮助开发者能够便捷的设计使用各种 Definition 。
    50  
    51  ## 设计
    52  
    53  上文提到的 CUE 与 YAML 混合的 Definition 在 v1.1 版本中,转换为了 CUE 格式的单一描述文件,更加清晰简练的表达了 Definition 的内容与能力。比如上述的 labels 就可以用以下文件来表达
    54  
    55  ```json
    56  // labels.cue
    57  labels: {
    58          annotations: {}
    59          attributes: {
    60                  appliesToWorkloads: ["deployments.apps"]
    61                  podDisruptive: true
    62          }
    63          description: "Add labels for your Workload."
    64          labels: {}
    65          type: "trait"
    66  }
    67  template: {
    68          patch: spec: template: metadata: labels: {
    69                  for k, v in parameter {
    70                          "\(k)": v
    71                  }
    72          }
    73          parameter: [string]: string
    74  }
    75  ```
    76  
    77  其中,第一部分 `labels: {...}` 表达了该 Definition 的基本信息(包括其类型、描述、标签以及基本属性),而第二部分 `template: {...}` 则表达了该 Definition 具体的能力。借用 `vela def` 命令组,KubeVela 用户可以直接直接与 CUE 格式的文件打交道,而不需要直接面对较为复杂的 YAML 文件。
    78  
    79  ## 详细文档
    80  
    81  ### init
    82  
    83  `vela def init` 是一个用来帮助用户初始化新的 Definition 的脚手架命令。用户可以通过 `vela def init my-trait -t trait --desc "My trait description."` 来创建一个新的空白 TraitDefinition ,如下
    84  
    85  ```json
    86  "my-trait": {
    87          annotations: {}
    88          attributes: {
    89                  appliesToWorkloads: []
    90                  conflictsWith: []
    91                  definitionRef:   ""
    92                  podDisruptive:   false
    93                  workloadRefPath: ""
    94          }
    95          description: "My trait description."
    96          labels: {}
    97          type: "trait"
    98  }
    99  template: {
   100          patch: {}
   101          parameter: {}
   102  }
   103  ```
   104  
   105  或者是采用 `vela def init my-comp --interactive` 来交互式地创建新的 Definition 。
   106  
   107  ```bash
   108  $ vela def init my-comp --interactive
   109  Please choose one definition type from the following values: component, trait, policy, workload, scope, workflow-step
   110  > Definition type: component
   111  > Definition description: My component definition.
   112  Please enter the location the template YAML file to build definition. Leave it empty to generate default template.
   113  > Definition template filename: 
   114  Please enter the output location of the generated definition. Leave it empty to print definition to stdout.
   115  > Definition output filename: my-component.cue
   116  Definition written to my-component.cue
   117  ```
   118  
   119  除此之外,如果用户创建 ComponentDefinition 的目的是一个 Deployment(或者是其他的 Kubernetes Object ),而这个 Deployment 已经有了 YAML 格式的模版,用户还可以通过 `--template-yaml` 参数来完成从 YAML 到 CUE 的自动转换。例如如下的 `my-deployment.yaml`
   120  
   121  ```yaml
   122  apiVersion: apps/v1
   123  kind: Deployment
   124  metadata:
   125    name: hello-world
   126  spec:
   127    replicas: 1
   128    selector:
   129      matchLabels:
   130        app.kubernetes.io/name: hello-world
   131    template:
   132      metadata:
   133        labels:
   134          app.kubernetes.io/name: hello-world
   135      spec:
   136        containers:
   137        - name: hello-world
   138          image: somefive/hello-world
   139          ports: 
   140          - name: http
   141            containerPort: 80
   142            protocol: TCP
   143  ---
   144  apiVersion: v1
   145  kind: Service
   146  metadata:
   147    name: hello-world-service
   148  spec:
   149    selector:
   150      app: hello-world
   151    ports:
   152    - name: http
   153      protocol: TCP
   154      port: 80
   155      targetPort: 8080
   156    type: LoadBalancer
   157  ```
   158  
   159  运行 `vela def init my-comp -t component --desc "My component." --template-yaml ./my-deployment.yaml` 可以得到 CUE 格式的 ComponentDefinition
   160  
   161  ```json
   162  "my-comp": {
   163          annotations: {}
   164          attributes: workload: definition: {
   165                  apiVersion: "<change me> apps/v1"
   166                  kind:       "<change me> Deployment"
   167          }
   168          description: "My component."
   169          labels: {}
   170          type: "component"
   171  }
   172  template: {
   173          output: {
   174                  metadata: name: "hello-world"
   175                  spec: {
   176                          replicas: 1
   177                          selector: matchLabels: "app.kubernetes.io/name": "hello-world"
   178                          template: {
   179                                  metadata: labels: "app.kubernetes.io/name": "hello-world"
   180                                  spec: containers: [{
   181                                          name:  "hello-world"
   182                                          image: "somefive/hello-world"
   183                                          ports: [{
   184                                                  name:          "http"
   185                                                  containerPort: 80
   186                                                  protocol:      "TCP"
   187                                          }]
   188                                  }]
   189                          }
   190                  }
   191                  apiVersion: "apps/v1"
   192                  kind:       "Deployment"
   193          }
   194          outputs: "hello-world-service": {
   195                  metadata: name: "hello-world-service"
   196                  spec: {
   197                          ports: [{
   198                                  name:       "http"
   199                                  protocol:   "TCP"
   200                                  port:       80
   201                                  targetPort: 8080
   202                          }]
   203                          selector: app: "hello-world"
   204                          type: "LoadBalancer"
   205                  }
   206                  apiVersion: "v1"
   207                  kind:       "Service"
   208          }
   209          parameter: {}
   210  
   211  }
   212  ```
   213  
   214  接下来,用户就可以在该文件的基础上进一步做进一步的修改了。比如将属性中对于 **workload.definition** 中的 *\<change me\>* 去掉。
   215  
   216  ### vet
   217  
   218  在初始化 Definition 文件之后,可以运行 `vela def vet my-comp.cue` 来校验 Definition 是否在语法上有错误。比如如果少写了一个括号,该命令能够帮助用户识别出来。
   219  
   220  ```bash
   221  $ vela def vet my-comp.cue
   222  Validation succeed.
   223  ```
   224  
   225  ### render / apply
   226  
   227  确认 Definition 撰写无误后,开发者可以运行 `vela def apply my-comp.cue --namespace my-namespace` 来将该 Definition 应用在 Kubernetes 的 my-namespace 命名空间中。如果想了解一下 CUE 格式的 Definition 文件会被渲染成什么样的 Kubernetes YAML 文件,可以使用 `vela def apply my-comp.cue --dry-run` 或者 `vela def render my-comp.cue -o my-comp.yaml` 来预先渲染一下 YAML 文件进行确认。
   228  
   229  ```yaml
   230  apiVersion: core.oam.dev/v1beta1
   231  kind: ComponentDefinition
   232  metadata:
   233    annotations:
   234      definition.oam.dev/description: My component.
   235    labels: {}
   236    name: my-comp
   237    namespace: vela-system
   238  spec:
   239    schematic:
   240      cue:
   241        template: |
   242          output: {
   243                  metadata: name: "hello-world"
   244                  spec: {
   245                          replicas: 1
   246                          selector: matchLabels: "app.kubernetes.io/name": "hello-world"
   247                          template: {
   248                                  metadata: labels: "app.kubernetes.io/name": "hello-world"
   249                                  spec: containers: [{
   250                                          name:  "hello-world"
   251                                          image: "somefive/hello-world"
   252                                          ports: [{
   253                                                  name:          "http"
   254                                                  containerPort: 80
   255                                                  protocol:      "TCP"
   256                                          }]
   257                                  }]
   258                          }
   259                  }
   260                  apiVersion: "apps/v11"
   261                  kind:       "Deployment"
   262          }
   263          outputs: "hello-world-service": {
   264                  metadata: name: "hello-world-service"
   265                  spec: {
   266                          ports: [{
   267                                  name:       "http"
   268                                  protocol:   "TCP"
   269                                  port:       80
   270                                  targetPort: 8080
   271                          }]
   272                          selector: app: "hello-world"
   273                          type: "LoadBalancer"
   274                  }
   275                  apiVersion: "v1"
   276                  kind:       "Service"
   277          }
   278          parameter: {}
   279    workload:
   280      definition:
   281        apiVersion: apps/v1
   282        kind: Deployment
   283  ```
   284  
   285  ```bash
   286  $ vela def apply my-comp.cue -n my-namespace
   287  ComponentDefinition my-comp created in namespace my-namespace.
   288  ```
   289  
   290  ### get / list / edit / del
   291  
   292  在 apply 命令后,开发者可以采用原生的 kubectl 来对结果进行确认,但是正如我们上文提到的,YAML 格式的结果会相对复杂。使用 `vela def get` 命令可以自动将其转换成 CUE 格式,方便用户查看。
   293  
   294  ```bash
   295  $ vela def get my-comp -t component
   296  ```
   297  
   298  或者用户可以通过 `vela def list` 命令来查看当前系统中安装的所有 Definition(可以指定命名空间及类型)。
   299  
   300  ```bash
   301  $ vela def list -n my-namespace -t component
   302  NAME                    TYPE                    NAMESPACE       DESCRIPTION  
   303  my-comp                 ComponentDefinition     my-namespace    My component.
   304  ```
   305  
   306  同样的,在使用 `vela def edit` 命令来编辑 Definition 时,用户也只需要对转换过的 CUE 格式 Definition 进行修改,该命令会自动完成格式转换。用户也可以通过设定环境变量 `EDITOR` 来使用自己想要使用的编辑器。
   307  
   308  ```bash
   309  $ EDITOR=vim vela def edit my-comp
   310  ```
   311  
   312  类似的,用户可以运行 `vela def del` 来删除相应的 Definition。
   313  
   314  ```bash
   315  $ vela def del my-comp -n my-namespace  
   316  Are you sure to delete the following definition in namespace my-namespace?
   317  ComponentDefinition my-comp: My component.
   318  [yes|no] > yes
   319  ComponentDefinition my-comp in namespace my-namespace deleted.
   320  ```
   321