开发者学堂课程【Kubernetes 云原生管理实践:课时1:Kubernetes 应用管理领域总览和入门实践】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/293/detail/3438
课时1:Kubernetes 应用管理领域总览和入门实践
四、CUE configuration language
1、K8s yaml 管理的窘境
(1)Templating, Overlay, DSL
oam 如何作为 kuberneters 应用层抽象,kuberneters 本身是服务器端的能力,开发者使用时往往需要更为简单的模版,分享一篇文章,文章中很好的描述了kuberneters 配置管理的一些解决方法,对比了三种解决方法,第一种是templating,最简单的解法,直接在愿配置的基础上暴露几个参数,比如heim就采用这种方法,第二种l ayering 能够保留原配置并通过叠加方式做更改,比如kustomize就是采用这种方法,第三种是 dcl,比较偏向跟编程语言一样,提供抽象和库,从而达到高度重合的目的,borgcfg 外面有个开源板,jsonet都采用这种方法,cue也可以归类为第三种,它也是从borgcfg 和 jsonet 自然演进的下一代技术。
(2)简单统一→复杂多样→简单统一,
比如yaml,发现重复内容多或者有更好管理思路,又开发一系列工具和格式,最后又导致整个社区又开始变得多样化和不统一,最后又希望回到简单统一的方式,又回到开发下一代yaml格式,如此循环往复迭代下去,而cue出现在从复杂多样到简单统一时间节点上,cue如何统一管理配置,通过实战深入解cue并且回答问题。
2、CUE 用法入门
(1)进入cue官方网站,点Tutorials会出现一系列相应教程,通过教程逐个了解cue。
Cue,JSON Superset,创建cue,创建cue的文件test.cue,输入cue export test . cue,可以看到返回了JSON的文件,说明cue可以返回JSON Superset。
{
"list": [
1,
2,
3
],
"one": 1,
"two": 2,
"two-and-a-half": 2.5
}
(2)Types are values,通过里面的例子进行了解,
moscow: {
name :"Moscow"
pop:11.92M
capital: true
}
municipality: {
name :string
pop:int
capital: bool
}
在cue里面每个string都是集合,使用cue对不同集合取交集,比如失败,因为需要具体的数字,moscow是具体的数字,但是可以把municipality变成一个定义,但是只是export master,可以把定义跟值取交集,这时export成功,因为moscow值也是对应的type,如果type更改,export就不成功了,说明cue里面,type也是一个值,一个type和一个value怎么取交集,value里面更具体的type,cue取交集的操作,就是把集合不断的具体化,改成42,成功,改成string | int,也成功。
moscow: {
name :"42"
pop:11.92M
capital: true
}
municipality: {
name :string | int
pop:int
capital: bool
}
改成moscow,也可以。
moscow: {
name :"moscow"
pop:11.92M
capital: true
}
municipality: {
name :string | int
pop:int
capital: bool
}
定义另一个,也可以。
moscow:#Municipality& #municipality2 & f {
name :"moscow"
pop:11.92M
capital: true
}
municipality: {
name :string | int
pop:int
capital: bool
}
Municipality2: {
name :string
pop:int
capital: bool
}
如果改成int,就失败。
moscow:#Municipality& #municipality2 & f {
name :"moscow"
pop:11.92M
capital: true
}
municipality: {
name :string | int
pop:int
capital: bool
}
Municipality2: {
name :int
pop:int
capital: bool
}
(3)Duplicate Fields
允许多个字段重复,cue不断对string集合取交集,如果是一模一样的就不会产生冲突,没问题。
a: 4
a: 4
s:[b:2]
s:{c:2}
l:[1,2]
l: [1,2]
(4)Constraints
cue里面可以表达一些constraints,限制,跟type关系类似,有一定的关系,cue eval test . cue,violo从schema里面把human:true//always true 继承过来,如果export是不成功的,把它变成定义,跟定义取交集时,把定义里面的值赋予进来,把没有定义的字段暴露出来,export会告诉字段它不认识,如果加...,相当允许,可以加任意字段,export成功。
(5)Validation
#Language {
tag:string
name: =~"Alp(Lu)" // Must start with an
}
languages: [ . . . #Language ]
相当于用cue,yaml文件的验证方式,cue vet test . cue data . yaml,把no变成“no”,把dutch变成Dutch,没有错误,顺序没有关系,cue只是对内容取交集,在交集的操作里面,没有太大的关系,cue export test . cue,顺序改变也是暴露一样的内容。
a:{x:int,y:2}
a: {x: 1, y: int}
b: {x: 1, y: int}
b: {x: int, y: 2}
跟以继承为手段的工具最大的区别,像哪些工具,非常关注顺序,在大型协作里面反而不方便,像不关注顺序反而更容易去协作。更快速编写单层结构,自动next下去,跟之前一模一样,成功。
b: {x: 1, y: int}
b: {x: int, y: 2}
a: x: int
a:y:2
// a: {x: int, y: 2}
a: {x: 1, y: int}
3、用 CUE 管理 k8syaml
cue在kubernetes里的实践。
tree ./original I head
services
frontend
bartender
kube. yaml
breaddispatcher
kube. yaml
host
kube.yaml
Maitred
cp-a original tmp
cd tmp
cue mod init下载下来
写import代码
cd services 跑进文件夹
tree cue . mod I head
里面有
module. cue
pkg
Usr
cat cue . mod/module . cue
cd services
cue import ./...把里面所有的yaml都变成cue的一种定义,或者是cue的文件,cue import是失败的,有多个包和文件,要把所有的文件统一p kube名字
Cue import ./ . ..-p kube
失败,因为一个文件里面包含多个kubernetes object,如果不同的object在同一个kube包里,会产生冲突。
加前缀。
Cue import ./.. -p kube -l ' st rings. ToCamel(kind) ' -l metadata, name -f
可以看到cue文件都生成了。
Tree .I head
services
Frontend
bartender
kube . cue
kube. yaml
breaddispatcher
kube. cue
kube . yaml
打开cue文件,可以看到里面的yaml都变成了cue的定义,加的前缀就是kind,它的名字,每个集合都有不同的前缀,文件里面不仅有yaml格式,还有prometheus相关的格式,存的string类型放在里面,也是yaml的弊端,在cue里面相当于可以自动监测yaml和json string自动转化成cue的格式,这也是非常先进的东西,把所有的内容通过yaml marshal的方式放到原来字段里面,相当于用cue统一管理kubernetes配置,prometheus配置。可以看到跟yaml文件一模一样。
cue eval ./mon/prometheus -e configMap . prometheus
cue evaL -C ./...> snapshot
在文件里面存在大量重复的内容,尝试去除重复的内容,
cp frontend/breaddispatcher/kube . cue
创建cue文件,减少service和deployment里面重复的内容,每个service都有不同的名字,定义成类似于一个参数id,会把labels和ports,template相应重复的内容削减掉,报错,没有label,不符合要求,把component统一定义成string类型,输入
ls -d*/| sed 's/.$//' | xargs -I DIR sh -c 'cd DIR; echo "package kube
#Component: \"DIRI\"
" > kube.cue; cd ..'
根据目录名字加上cue文件,cue文件定义component具体的值,目录名字根据mon加上了component值,自动取交集,因为原先缺少component label,自动加上label,cue一秒就会成功,输入cue evaL -C ./...> snapshot2成功。
diff snapshot snapshot2
保存cp snap
shot2 snapshot
find .| grep kube.cueI xargs Wc| tail -1
1792 3616 34815 total
cue trim ./....利用工具,在kube.cue中统一定义label,prot,template,cue trim自动的调整,把重复的削减掉,可以看到整个文件的行数少了很多,500行。
find .|grep kube.cue|xargs wc|tail - 1
1223 2374 22903 total
cue evaL -C ./...> snapshot2
行数减少很多,但是得到没有任何的区别,得到的都是一样的结果,
diff snapshot snapshot2 | WCc
把共同的字段定义出来,削减配置的行数,添加内容,统一配置。
$ cat <> kube. cue
daemonSet:[ID=_ ]:_ spec & {
apiVersion: "apps/v1"
kind:"DaemonSet"
_name:ID
}
statefulSet: [ID=_ ]:_ spec & {
apiVersion: "apps/v1"
ind:"StatefulSet"
_name :ID
}
deployment: [ID=_ ]: spec & {
apiVersion:"apps/v1"
kind:"Deployment"
_name:ID
spec:replicas: *1 | int
}
configMap: [ID=_ ]: {
metadata :name: ID
metadata: labels: component: #Component
}
_spec: {
_name: string
metadata :name:_ name
metadata: labels: component: #Component
spec: selector: {}
spec: template: {
metadata: labels: {
app:_name
component: #Component
domain :"prod"
}
spec: containers: [{name: name}]
}
}
EOF
$ cue fmt
//Define the export option and set the default to true
//for all ports defined in all containers.
_spec: spec: template: spec: containers: {...(
ports:{..(
export: *truel false //include the port in the service
}]
for x in [deployment, daemonSet, statefulSet] for k,v in x {
service: "\(k)": {
spec: selector: v. spec. template. metadata. labels
spec: ports:[
for c in v. spec . template. spec. containers
for p in c.ports
if p._ export {
let Port = p. containerPort // Port is an alias
port: *Port |int
targetPort: *Port|int
}
]
}
多个export存在,deployment, daemonSet, statefulSet对相应的service自动生成port的字段,它里面的port跟service port对应起来,有if else的操作,如果是export会给相应的service给它port填上,port的名字和数值,cue里面有for,if else的操作。
$ cat <> inf ra/events/kube . cue
deployment: events: spec: template: spec: containers: [{ports: [{_ export: false),_] }]
EOF
$ cat <> infra/tasks/kube. cue
deployment: tasks: spec: template: spec: containers: [{ports: [{_ export: false),_] }]
E0F
$ cat <>infra/watcher/kube. cue
deployment: watcher: spec: template: spec: containers: [{ports: [{_ export: false),_] }]
EOF
把配置进一步减少
cue trim ./....
find .|grep kube.cue|xargs wc|tail - 1
把很多行变成一行
cue trim ./....-s
五、CUE 跟 OAM 的关系
还有更多减少配置的方法,整个过程充分了解如何通过cue更好的管理,更搞笑的减少重复的配置,使用 Kubernetes oam 相关的配置文件,更加舒服。
通过样例可以知道cue即可以作为配置,也可以作为配置验证和管理工具,cue 也可以把各种各样的格式统一起来,比如 kubernetes yaml 或者 prometheus。通过 cue 的模版达到用 GitOps/laC 的目的,运行在任何以恶 oam 平台上。
1、OAM 是服务器端的更高级别抽象,达到以应用为中心。
2、CUE 是客户端工具,为了更高效准确地编写和管理配置文件。
3、OAM 可以通过 CUE 透出更简单易用的模板: CUE templates→GitOps/laC→OAM