首页 > 其他分享 >CUE语言基础入门:CUE是一门为配置而生的语言

CUE语言基础入门:CUE是一门为配置而生的语言

时间:2023-01-01 11:34:19浏览次数:68  
标签:语言 image 入门 cue CUE parameter string name


基础入门

从这一部分开始,我们会介绍 KubeVela 是如何基于 CUE 来实现抽象和扩展的。本节将主要介绍一些 CUE 的基础知识,如果你对 KubeVela 的​​核心概念​​还不了解也没有关系,对于那些想要快速了解 CUE 并做一些实践的读者,本节也同样适用。

​概述​

KubeVela 将 CUE 作为应用交付核心依赖和扩展方式的原因如下::

  • CUE 本身就是为大规模配置而设计。 CUE 能够感知非常复杂的配置文件,并且能够安全地更改可修改配置中成千上万个对象的值。这非常符合 KubeVela 的目标,即以可编程的方式,去定义和交付生产级别的应用程序。
  • CUE 支持一流的代码生成和自动化。 CUE 原生支持与现有工具以及工作流进行集成,反观其他工具则需要自定义复杂的方案才能实现。例如,需要手动使用 Go 代码生成 OpenAPI 模式。KubeVela 也是依赖 CUE 该特性进行构建开发工具和 GUI 界面的。
  • CUE 与 Go 完美集成。 KubeVela 像 Kubernetes 系统中的大多数项目一样使用 GO 进行开发。CUE 已经在 Go 中实现并提供了丰富的 API。KubeVela 以 CUE 为核心实现 Kubernetes 控制器。借助 CUE,KubeVela 可以轻松处理数据约束问题。

更多细节请查看 ​​The Configuration Complexity Curse​​​ 以及 ​​The Logic of CUE​​ 两篇文章。

​前提​

请确保你的环境中已经安装如下命令行:

  • ​cue​​ 目前 KubeVela 暂时只支持 CUE v0.2.2 版本,将在后续迭代中升级支持新的 CUE 版本。
  • ​vela​​。

​学习 CUE 命令行​

CUE 是 JSON 的超集, 我们可以像使用 JSON 一样使用 CUE,并具备以下特性:

  • C 语言风格的注释
  • 字段名称可以用双引号括起来,注意字段名称中不可以带特殊字符
  • 可选字段末尾是否有逗号
  • 允许数组中最后一个元素末尾带逗号
  • 外大括号可选

请先复制以下信息,保存为一个 ​​first.cue​​ 文件:

a: 1.5
a: float
b: 1
b: int
d: [1, 2, 3]
g: {
h: "abc"
}
e: string

接下来,我们以上面这个文件为例子,来学习 CUE 命令行的相关指令:

  • 如何格式化 CUE 文件。(如果你使用 Goland 或者类似 JetBrains IDE, 可以参考该文章配置自动格式化插件 ​​使用 Goland 设置 cuelang 的自动格式化​​。)
    该命令不仅可以格式化 CUE 文件,还能提示错误的模型,相当好用的命令。
cue fmt first.cue
  • 如何校验模型。除了 ​​cue fmt​​,你还可以使用 ​​cue vet​​ 来校验模型。
$ cue vet first.cue
some instances are incomplete; use the -c flag to show errors or suppress this message

$ cue vet first.cue -c
e: incomplete value string

提示我们:这个文件里的 e 这个变量,有数据类型 ​​string​​ 但并没有赋值。

  • 如何计算/渲染结果。 ​​cue eval​​ 可以计算 CUE 文件并且渲染出最终结果。 我们看到最终结果中并不包含 ​​a: float​​ 和 ​​b: int​​,这是因为这两个变量已经被计算填充。 其中 ​​e: string​​ 没有被明确的赋值, 故保持不变.
$ cue eval first.cue
a: 1.5
b: 1
d: [1, 2, 3]
g: {
h: "abc"
}
e: string
  • 如何指定渲染的结果。例如,我们仅想知道文件中 ​​b​​ 的渲染结果,则可以使用该参数 ​​-e​​。
$ cue eval -e b first.cue
1
  • 如何导出渲染结果。 ​​cue export​​ 可以导出最终渲染结果。如果一些变量没有被定义执行该命令将会报错。
$ cue export first.cue
e: incomplete value string

我们更新一下 ​​first.cue​​​ 文件,给 ​​e​​ 赋值:

a: 1.5
a: float
b: 1
b: int
d: [1, 2, 3]
g: {
h: "abc"
}
e: string
e: "abc"

然后,该命令就可以正常工作。默认情况下, 渲染结果会被格式化为 JSON 格式。

$ cue export first.cue
{
"a": 1.5,
"b": 1,
"d": [
1,
2,
3
],
"g": {
"h": "abc"
},
"e": "abc"
}
  • 如何导出 YAML 格式的渲染结果。
$ cue export first.cue --out yaml
a: 1.5
b: 1
d:
- 1
- 2
- 3
g:
h: abc
e: abc
  • 如何导出指定变量的结果。
$ cue export -e g first.cue
{
"h": "abc"
}

以上, 你已经学习完所有常用的 CUE 命令行指令。

​学习 CUE 语言​

在熟悉完常用 CUE 命令行指令后,我们来进一步学习 CUE 语言。

先了解 CUE 的数据类型。以下是它的基础数据类型:

// float
a: 1.5

// int
b: 1

// string
c: "blahblahblah"

// array
d: [1, 2, 3, 1, 2, 3, 1, 2, 3]

// bool
e: true

// struct
f: {
a: 1.5
b: 1
d: [1, 2, 3, 1, 2, 3, 1, 2, 3]
g: {
h: "abc"
}
}

// null
j: null

如何自定义 CUE 类型?使用 ​​#​​ 符号来指定一些表示 CUE 类型的变量。

#abc: string

我们将上述内容保存到 ​​second.cue​​​ 文件。 执行 ​​cue export​​​ 不会报 ​​#abc​​ 是一个类型不完整的值。

$ cue export second.cue
{}

你还可以定义更复杂的自定义结构,比如:

#abc: {
x: int
y: string
z: {
a: float
b: bool
}
}

自定义结构在 KubeVela 中被广泛用于模块定义(X-Definitions)和进行验证。

​定义一个 CUE 模板​

下面,我们开始尝试利用刚刚学习到的知识,来定义 CUE 模版。

  1. 定义结构体变量 ​​parameter​​.
parameter: {
name: string
image: string
}

保存上述变量到文件 ​​deployment.cue​​.

  1. 定义更复杂的结构变量 ​​template​​​ 同时引用变量 ​​parameter​​.
template: {
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
}]
}}}
}

熟悉 Kubernetes 的你可能已经知道,这是 Kubernetes Deployment 的模板。 ​​parameter​​ 为模版的参数部分。

添加上述内容到文件 ​​deployment.cue​​.

  1. 随后, 我们通过更新以下内容来完成变量赋值:
parameter:{
name: "mytest"
image: "nginx:v1"
}
  1. 最后, 导出渲染结果为 YAML 格式:
$ cue export deployment.cue -e template --out yaml

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

以上,你就得到了一个 Kubernetes Deployment 类型的模板。

​CUE 的更多用法​

  • 设计开放的结构体和数组。如果在数组或者结构体中使用 ​​...​​,则说明该对象为开放的。
  • 数组对象 ​​[...string]​​​ ,说明该对象可以容纳多个字符串元素。 如果不添加 ​​...​​​, 该对象 ​​[string]​​​ 说明数组只能容纳一个类型为 ​​string​​ 的元素。
  • 如下所示的结构体说明可以包含未知字段。
{
abc: string
...
}
  • 使用运算符 ​​|​​​ 来表示两种类型的值。如下所示,变量 ​​a​​ 表示类型可以是字符串或者整数类型。
a: string | int
  • 使用符号 ​​*​​​ 定义变量的默认值。通常它与符号 ​​|​​​ 配合使用, 代表某种类型的默认值。如下所示,变量 ​​a​​​ 类型为 ​​int​​​,默认值为 ​​1​​。
a: *1 | int
  • 让一些变量可被选填。 某些情况下,一些变量不一定被使用,这些变量就是可选变量,我们可以使用 ​​?:​​​ 定义此类变量。 如下所示, ​​a​​​ 是可选变量, 自定义 ​​#my​​​ 对象中 ​​x​​​ 和 ​​z​​​ 为可选变量, 而 ​​y​​ 为必填字段。
a ?: int

#my: {
x ?: string
y : int
z ?:float
}

选填变量可以被跳过,这经常和条件判断逻辑一起使用。 具体来说,如果某些字段不存在,则 CUE 语法为 ​​if _variable_!= _ | _​​ ,如下所示:

parameter: {
name: string
image: string
config?: [...#Config]
}
output: {
...
spec: {
containers: [{
name: parameter.name
image: parameter.image
if parameter.config != _|_ {
config: parameter.config
}
}]
}
...
}
  • 使用运算符 ​​&​​ 来运算两个变量。
a: *1 | int
b: 3
c: a & b

保存上述内容到 ​​third.cue​​ 文件。

你可以使用 ​​cue eval​​ 来验证结果:

$ cue eval third.cue
a: 1
b: 3
c: 3
  • 需要执行条件判断。当你执行一些级联操作时,不同的值会影响不同的结果,条件判断就非常有用。 因此,你可以在模版中执行 ​​if..else​​ 的逻辑。
price: number
feel: *"good" | string
// Feel bad if price is too high
if price > 100 {
feel: "bad"
}
price: 200

保存上述内容到 ​​fourth.cue​​ 文件。

你可以使用 ​​cue eval​​ 来验证结果:

$ cue eval fourth.cue
price: 200
feel: "bad"

另一个示例是将布尔类型作为参数。

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"}]
}
}]
}
...
}
  • 使用 For 循环。 我们为了避免减少重复代码,常常使用 For 循环。
  • 映射遍历。
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
},
]
}]
}
}
  • 类型遍历。
#a: {
"hello": "Barcelona"
"nihao": "Shanghai"
}

for k, v in #a {
"\(k)": {
nameLen: len(v)
value: v
}
}
  • 切片遍历。
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
},
]
}]
}
}
  • 循环内使用条件判断
parameter: [
{
name: "empty"
}, {
name: "xx1"
},
]

dataFrom: [ for _, v in parameter {
if v.name != "empty" {
name: v.name
}
}]

结果是:

cue eval ../blog/a.cue -e dataFrom
[{}, {
name: "xx1"
}]
  • 将条件判断作为循环的条件
parameter: [
{
name: "empty"
}, {
name: "xx1"
},
]

dataFrom: [ for _, v in parameter if v.name != “empty” { name: v.name }]

结果是:

cue eval …/blog/a.cue -e dataFrom [{ name: “xx1” }]

另外,可以使用 ​​"\( _my-statement_ )"​​ 进行字符串内部计算,比如上面类型循环示例中,获取值的长度等等操作。

​导入 CUE 内部包​

CUE 有很多 ​​internal packages​​ 可以被 KubeVela 使用,这样可以满足更多的开发需求。

比如,使用 ​​strings.Join​​ 方法将字符串数组拼接成字符串。

import ("strings")

parameter: {
outputs: [{ip: "1.1.1.1", hostname: "xxx.com"}, {ip: "2.2.2.2", hostname: "yyy.com"}]
}
output: {
spec: {
if len(parameter.outputs) > 0 {
_x: [ for _, v in parameter.outputs {
"\(v.ip) \(v.hostname)"
}]
message: "Visiting URL: " + strings.Join(_x, "")
}
}
}

至此,你已经学会了基础的 CUE 知识,如果你还想了解更多的 CUE 实践细节,可以参考其​​官方文档​​。

在本部分接下来的章节里,我们会开始介绍 KubeVela 如何使用 CUE 像胶水一样衔接不同的资源,请确保你对 KubeVela 的​​核心概念​​有所了解。


标签:语言,image,入门,cue,CUE,parameter,string,name
From: https://blog.51cto.com/zhangxueliang/5982848

相关文章

  • 极客编程python入门-序列化
    序列化我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。序列化......
  • 函数入门
    函数的作用:函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段。定义一个函数函数代码块以def关键词开头,后接函数标识符名称和圆括号()。任何传入参数......
  • NLP入门必知必会(一):Word Vectors
     Datawhale干货 作者:芦冬生,Datawhale优秀学习者,北京理工大学自然语言处理(NLP)是信息时代最重要的技术之一,也是人工智能的重要组成部分。NLP的应用无处不在,因为人们几乎......
  • python编程 ——从入门到实践——第四章,操作列表
    1、遍历列表——for循环的基本形式magicians=['alice','david','carolina']forainmagicians:#for循环会读取列表中的第一个字符串,然后和a对应,再打印,然后再读取第......
  • C语言两结构体之间的成员互换
    今天在写一个通讯录实现程序的时候,遇到个让我突然卡壳的问题,不知道怎么进行两个结构体之间的成员互换......结构体成员有“姓名”,“性别”,“年龄”,“地址”,“电话”,目的就......
  • NumPy - 入门
    目录NumPy,是NumericalPython的简称,它是目前Python数值计算中最为重要的基础包。大多数计算包都提供了基于NumPy的科学函数功能,将NumPy的数组对象作为数据交换的通......
  • SAP MM 模块的入门者,想学习 ABAP 编程语言应该如何入手?
    本人自2007年计算机专业研究生毕业加入SAP成都研究院,在这之前也从未听说过ABAP这门编程语言,我算是ABAP零基础开始学习。根据我的过往经验,可以先简单了解一下ABAP......
  • 用c语言将三个数字从大到小排列
    #include<stdio.h>intmain(){inta=0;intb=0;intc=0;scanf("%d%d%d",&a,&b,&c);//先确定最大值a,然后比较b和c的大小if(a<b){inttmp=a;a=b;b=......
  • Linux 监控和调试利器 Sysdig 入门教程
    Sysdig简介Sysdig官网上对自己的介绍是:OpenSourceUniversalSystemVisibilityWithNativeContaierSupport.它的定位是系统监控、分析和排障的工具,其实在Linux......
  • 【kubernetes入门到精通】Kubernetes的健康监测机制以及常见ExitCode问题分析「探索篇
    kubernetes进行Killed我们服务的问题背景无论是在微服务体系还是云原生体系的开发迭代过程中,通常都会以Kubernetes进行容器化部署,但是这也往往带来了很多意外的场景和情况......