k8s创建资源对象过程

我们都知道,K8S中一切皆资源,在使用K8S时,所有的pod或者controller都是通过yaml文件进行创建的。

那么接下来,就和大家一起看一下K8S是如何创建资源的。

创建资源对象的过程

Deployment是一种常见的资源对象。在Kubernetes系统中创建资源对象有很多种方法。本节将对用kubectl create命令创建Deployment资源对象的过程进行分析。kubectl资源对象创建过程如图所示。

使用kubectl创建资源对象是Kubernetes中最常见的操作之一,内部运行原理是客户端与服务端进行一次HTTP请求的交互。Kubernetes整个系统架构的设计方向是通用和具有高扩展性,所以以上功能在代码实现上略微复杂。

创建资源对象的流程可分为:

  1. \1. 实例化Factory接口
  2. \2. 通过Builder和Visitor将资源对象描述文件(deployment.yaml)文本格式转换成资源对象。
  3. \3. 将资源对象以HTTP请求的方式发送给kube-apiserver,并得到响应结果。
  4. \4. 最终根据Visitor匿名函数集的errors判断是否成功创建了资源对象。

1. 编写资源对象描述文件

Kubernetes系统的资源对象可以使用JSON或YAML文件来描述,一般使用YAML文件居多。下面提供了一个简单的Deployment Example资源对象文件:

本文主要了解k8s创建资源对象的过程,因此代码使用截图代替。

通过kubectl create命令与kube-apiserver交互并创建资源对象,执行命令如下:

kubectl create -f nginx-deployment.yaml

2. 实例化Factory接口

在执行每一个kubectl命令之前,都需要执行实例化cmdutil.Factory接口对象的操作。Factory是一个通用对象,它提供了与kube-apiserver的交互方式,以及验证资源对象等方法。cmdutil.Factory接口代码示例如下:

源码使用最新版本k8s进行阅读: vendor/k8s.io/kubectl/pkg/cmd/cmd.go:332

f := cmdutil.NewFactory(matchVersionKubeConfigFlags)

vendor/k8s.io/kubectl/pkg/cmd/util/factory.go:40

cmdutil.Factory接口说明如下:

  • • DynamicClient:动态客户端。
  • • KubernetesClientSet:ClientSet客户端。
  • • RESTClient:RESTClient客户端。
  • • NewBuilder:实例化Builder,Builder用于将命令行获取的参数转换成资源对象。
  • • Validator:验证资源对象。

cmdutil.Factory接口封装了3种client-go客户端与kube-apiserver交互的方式,分别是DynamicClient、KubernetesClientSet(简称ClientSet)及RESTClient。3种交互方式各有不同的应用场景。

关于三种客户端的介绍,将会在下一篇文章详细介绍client-go客户端的使用。

PS:动动小手关注我,后续继续学习crd与client-go的使用。

3. Builder构建资源对象

Builder用于将命令行获取的参数转换成资源对象(Resource Object)。它实现了一种通用的资源对象转换功能。Builder结构体保存了命令行获取的各种参数,并通过不同函数处理不同参数,将其转换成资源对象。Builder的实现类似于Builder建造者设计模式,提供了一种实例化对象的最佳方式。代码示例如下: vendor/k8s.io/kubectl/pkg/cmd/create/create.go:251

首先通过f.NewBuilder实例化Builder对象,通过函数Unstructured、Schema、ContinueOnError、NamespaceParam、FilenameParam、LabelSelectorParam、Flatten对参数赋值和初始化,将参数保存到Builder对象中。最后通过Do函数完成对资源的创建。

其中,FilenameParam函数用于识别kubectl create命令行参数是通过哪种方式传入资源对象描述文件的,kubectl目前支持3种方式:

  • • 第1种,标准输入Stdin(即cat deployment.yaml|kubectl create-f);
  • • 第2种,本地文件(即kubectl create-f deployment.yaml);
  • • 第3种,网络文件(即kubectl create-f http:///deployment.yaml)。

4. Visitor多层匿名函数嵌套

在Builder Do函数中,Result对象中的结果由Visitor执行并产生,Visitor的设计模式类似于Visitor访问者模式。Visitor接口定义如下:

vendor/k8s.io/cli-runtime/pkg/resource/interfaces.go:94

Visitor接口包含Visit方法,实现了Visit(VisitorFunc) error的结构体都可以成为Visitor。其中,VisitorFunc是一个匿名函数,它接收Info与error信息,Info结构用于存储RESTClient请求的返回结果,而VisitorFunc匿名函数则生成或处理Info结构。

Visitor的设计较为复杂,并非单纯实现了访问者模式,它相当于一个匿名函数集。在Kubernetes源码中,Visitor被设计为可以多层嵌套(即多层匿名函数嵌套,使用一个Visitor嵌套另一个Visitor)。直接阅读Visitor源码,会比较晦涩,为了更好地理解Visitor的工作原理,这里提供了代码示例。Visitor Example代码示例如下:

在Visitor Example代码示例中,定义了Visitor接口,增加了VisitorList对象,该对象相当于多个Visitor匿名函数的集合。另外,增加了3个Visitor的类,分别实现Visit方法,在每一个VisitorFunc执行之前(before)和执行之后(after)分别输出print信息。Visitor Example代码执行结果输出如下:

通过Visitor代码示例的输出,能够更好地理解Visitor的多层嵌套关系。在main函数中,首先将Visitor1嵌入VisitorList中,VisitorList是Visitor的集合,可存放多个Visitor。然后将VisitorList嵌入Visitor2中,接着将Visitor2嵌入Visitor3中。最终形成Visitor3{Visitor2{VisitorList{Visitor1}}}的嵌套关系。

根据输出结果,最先执行的是Visitor1中fn匿名函数之前的代码,然后是VisitorList、Visitor2和Visitor3中fn匿名函数之前的代码。紧接着执行VisitFunc(visitor.Visit)。最后执行Visitor3、Visitor2、VisitorList、Visitor1的fn匿名函数之后的代码。整个多层嵌套关系的执行过程有些类似于递归操作。

多层嵌套关系理解起来有点困难,如果读者看过电影《盗梦空间》的话,该过程可以类比为其中的场景。每次执行Visitor相当于进入盗梦空间中的另一层梦境,在触发执行了visitFunc return后,就开始从每一层梦境中苏醒过来。

回到Kubernetes源码中的Visitor,再次阅读源码时,就容易理解了。Visitor中的VisitorList(存放Visitor的集合)有两种,定义在vendor/k8s.io/cli-runtime/pkg/resource/visitor.go中,代码示例如下:

  • • EagerVisitorList:当遍历执行Visitor时,如果遇到错误,则保留错误信息,继续遍历执行下一个Visitor。最后一起返回所有错误。
  • • VisitorList:当遍历执行Visitor时,如果遇到错误,则立刻返回。

Kubernetes Visitor中存在多种实现方法,不同实现方法的作用不同

下面将资源创建(kubectl create-f yaml/deployment.yaml)过程中的Visitor多层匿名函数嵌套关系整理了出来:

EagerVisitorList{FileVisitor{StreamVisitor{FlattenListVisitor{FlattenListVisitor{ContinueOnErrorVisitor{DecoratedVisitor{result.Visit{}}}}}}}}

EagerVisitorList是Visitor集合,集合中包含FileVisitor和StreamVisitor,执行FileVisitor和StreamVisitor并保留执行后的error信息,然后继续执行下面的Visitor。FileVisitor和StreamVisitor将资源对象描述文件(deployment.yaml)的内容通过infoForData函数转换成Info对象。FlattenListVisitor将资源对象描述文件中定义的资源类型转换成Info对象。ContinueOnErrorVisitor将Visitor调用过程中产生的错误保留在[]error中。DecoratedVisitor会执行注册过的VisitorFunc,分别介绍如下。

  • • resource.SetNamespace:设置命名空间(Namespace),确保每个Info对象都有命名空间。
  • • resource.RequireNamespace:设置命名空间,并检查资源对象描述文件中提供的命名空间与命令行参数(--namespace)提供的命名空间是否相符,如果不相符则返回错误。
  • • resource.RetrieveLazy:如果info.Object为空,则根据info的Namepsace和Name等字段调用Helper获取obj,并更新info的Object字段。

由result.Visit执行createAndRefresh:第1步,通过Helper.Create向kube-apiserver发送创建资源的请求,Helper对client-go的RESTClient进行了封装,在此基础上实现了Get、List、Watch、Delete、Create、Patch、Replace等方法,实现了与kube-apiserver的交互功能;第2步,将与kube-apiserver交互后得到的结果通过info.Refresh函数更新到info.Object中。最后逐个退出Visitor,其过程为

DecoratedVisitor→ContinueOnErrorVisitor → FlattenListVisitor →FlattenListVisitor → StreamVisitor →FileVisitor→EagerVisitorList。

最终根据Visitor的error信息为空判断创建资源请求执行成功。

相关推荐
老大白菜42 分钟前
Windows 11 安装 Dify 完整指南 非docker环境
windows·docker·容器
tntlbb5 小时前
Ubuntu20.4 VPN+Docker代理配置
运维·ubuntu·docker·容器
Gabriel_liao5 小时前
Docker安装Neo4j
docker·容器·neo4j
有一个好名字5 小时前
zookeeper分布式锁模拟12306买票
分布式·zookeeper·云原生
Anna_Tong8 小时前
云原生大数据计算服务 MaxCompute 是什么?
大数据·阿里云·云原生·maxcompute·odps
豆豆豆豆变8 小时前
Docker轻量级可视化工具Portainer
docker·容器·自动化运维
花晓木8 小时前
k8s etcd 数据损坏处理方式
容器·kubernetes·etcd
运维&陈同学8 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero
花晓木9 小时前
k8s备份 ETCD , 使用velero工具进行备份
容器·kubernetes·etcd
大熊程序猿9 小时前
xxl-job docker 安装
运维·docker·容器