YAML:k8s世界的通用语(chrono《kubernetes入门实战课》笔记整理)

 

【引入YAML概念】 

YAML语言有一个非常关键的特性,叫“声明式”(declarative),对应的另一个词“命令式”(imperative)。

  • 命令式:docker命令和dockerfile就属于命令式,特点是交互性强,注重顺序和过程,需要把所有步骤都列表清楚,让计算机明白要做什么,每步怎么做,并最终可以完成任务。就好像打车,遇到一位不熟悉路的司机,你需要告诉他,怎么走才能到达目的地。整个过程你都需要完全支配;
  • 声明式:在k8s之前比较少见,它与命令式完全相反,不需要“教”计算机怎么做,只要告诉他目标节课,它会自己想办法去完成。就好像打车,由于司机经验丰富,你说我要去哪里,他就可以自己选择最合适的道路带你去往目的地,而你只需要坐在车上观赏风景、玩玩手机就可以了。而k8s之所以可以做到,就是因为上一节中说明的它的内部架构和实现原理来决定的。master/node架构让它对整个几群的状态了如指掌,内部的众多组件和插件也能够自动监控管理应用。YAML语言,就可以做这种声明式的命令。

 

【什么是YAML】

YAML创建于2001年,https://yaml.org有详细的规范介绍。YAML是JSON的超集,支持整数、浮点数、布尔、字符串、数组和对象等数据类型。可以理解为,任何合法的JSON文档也都是YAML文档。但和JSON相比,YAML的语法更简单。比如:

  • 使用空白与缩进标识层次(类似python),可以不使用花括号和方括号;
  • 可以使用#来注释;
  • 对象(字典)的格式与JSON基本相同,但key不需要使用双引号;
  • 数组(列表)使用 - 开头的清单形式;
  • 标识对象的 :和标识数组的 - ,后面都必须有空格;
  • 可以使用 --- 在一个文件里分隔多个YAML对象。

 通过2个示例来观察YAML和JSON语法的差异:

1、数组

1)YAML中数组的表示:

 

 2)JSON中数组的表示:

  2、 声明1个master,3个worker节点:

1)YAML中的写法:

 2)JSON的写法:

 

所以使用YAML声明一个k8s资源对象,就可以用如下写法:

 

【什么是API对象】

那么如何使用YAML语言进行声明,说出我们要的目标呢?就需要依靠API对象。也就是,可以这么理解,你要定义或者创建的目标是什么,这个目标就是API对象,比如你要创建一个pod,一个node,这都是一个一个的API对象。那为什么要叫做API对象呢?因为在master节点中,apiserver,作为k8s系统的唯一入口,外部用户和内部用户都必须和它通信,那么既然是通过apiserver来做通信,来完成各种具体任务,那么用来描述这些任务目标,我们就称为API对象是比较合理的,即这些目标是我apiserver服务的对象。可以通过kubectl api-resources来查看有哪些API对象,比如我们平时熟悉的常说的pods,nodes,namespaces都是一种API对象,比较抽象,希望举例可以让我自己尽力理解。

 上图中,NAME就是对象的名字,SHORTNAMES就是资源的简写,当我们使用kubectl的时候,对这些对象,就可以通过简写方式来输入。

在使用kubectl命令的时候,可以加上 --v=9 ,就会看到详细的命令执行过程,如下图所示的get pod,当加了 --v=9,就可以看到kubectl客户端,实际上是调用了curl,想8443端口发送了GET请求,URL是:'api/v1/namespaces/default/pods'

 k8s 1.23版本,有50+的API对象,全面地描述了集群的节点、应用、配置、服务、账号等等信息,apiserver会把他们都存储在数据库etcd里,然后kubelet、scheduler、controller-manager等组件通过apiserver来操作它们,这样,就在API对象这个抽象层次实现了对整个集群的管理。

 

 【创建一个YAML文件--如何使用YAML语言描述并创建API对象】

当我们使用kubtctl运行一个镜像,命令是kubectl run ngx --image=nginx:alpine,如果用YAML声明,应该怎么写呢?也就是通过YAML语言,描述出我们想要运行一个ngx,让k8s自己去找需要的镜像,并且运行。下图就是YAML语言的声明方式,代表,我要一个POD,镜像要用nginx:alpine,这个镜像需要开放80端口。其他的部分,是k8s对API对象的强制格式要求。

 

由于API对象采用标准的HTTP协议,为了容易理解,可以对比HTTP报文格式,也把API对象分成header和body两部分理解。

1、header包含API对象的基本信息,包含三个字段:apiversion、kind、metadata。和http报文一样,header的内容,都必须要有,这是必须遵守的格式。这三个字段的信息,都被kubectl用于生成HTTP请求发给了apiserver,在--v=9的url里,都可以对比上:

1)apiversion:表示操作这种资源的API版本号,由于k8s迭代很快,不同的版本,创建的对象可能会有差异,所以最好带上具体版本号;

2)kind:表示资源对象的类型,比如pod、node、job、service等;

3)metadata:表示资源的元信息,就是描述这个资源的一些属性的。在上图中有两个元信息,一个是name,给pod起了个名字ngx-pod,一个是lables,给pod贴上便于查找的标签,分别是env和owner

2、body会与具体对象有关系,每种对象会有不同的规格定义,在YAML中,就是通过spec来定义的。上图中的spec中,只定义了一个containers数组,里面的每个元素又是一个对象,制定了名字、镜像、端口等信息。

 

综合起来看,这份YAML文件,完整描述了一个类型是pod的API对象,要求使用v1版本的API接口去管理,其他更具体的名称、标签、状态都记录在metadata和spec等字段里了。

 

【怎么使用YAML文件】

使用kubectl apply、kubectl delete,加上 -f 参数,就可以使用这个YAML文件创建和删除API对象了。以下是一个简单小实验:

1、vi一个yml文件,如下:

 2、根据yml创建这个pod:

 3、查看pod确认(我这里镜像一开始显示拉取失败了,但是后来我再来看是running了。这个过程状态我要再去理解下)

 4、根据yml删除对应pod:

 5、再查看pod,已经没有ym-pod了

 那么当我们用kubectl去apply/delete API对象的时候,k8s实际做了什么呢?k8s收到yml数据后,会调用HTTP请求中POST/DELETE方法,来对API对象做对应的操作,至于这个对象会分布在那个节点、怎么创建、怎么删除,都是k8s自己去管理调度,我们就不用操心了。

 

【怎么正确编写YAML呢】

1、如何在编写YAML的时候,知道我该怎么定义apiversion,kind,metadata,spec呢?

//API对象的所有字段,都可以在https://kubernetes.io/docs/reference/kubernetes-api/ 查到。查看时有些小技巧:

1)使用kubectl api-resources的时候,在APIVERSION可以看到:

  2)使用kubectl explain,也可以看到对应版本以及其他相关信息,比如:

  

  2、还有编写的时候缩进对齐有没有好办法帮忙一键做到呢?

//让kubectl代劳,生成一份“文档样板”,免去打字和对齐的工作。也就是使用 dry-run=client 和 -o yaml ,前者是空运行,后者是生成YAML格式,结合起来就会让kubectl不会有实际的创建动作,只是生成一个YAML文件,然后我们基于这个文件继续编写我们需要的YAML文件就好。

  示例:想要生成一个pod的YAML样板示例,可以在kubectl run后面加上这两个参数,就会生成一个绝对正确的YAML文件样板。注意这个样板YAML文件会直接如下图打印在屏幕上,如果希望可以生成“.yml”文件,需要重定向一下,比如 >aa.yml。这个pod并不会真正运行,可以通过get pods来确认:

 

 

 tips:"--dry-run=client -o yaml"比较长,不好记忆,可以定义成shell变量,用起来会更省事儿,比如:

  

  

 

正式使用k8s的时候,除了特殊情况,我们都不会使用kubectl run这个命令直接创建pod,而是通过YAML来描述对象,在用kubectl apply去发布YAML来创建对象了。 

posted @ 2022-11-16 12:09  1234roro  阅读(115)  评论(0)    收藏  举报