kubectl 源码分析

news2024/9/23 17:23:23

Cobra库

k8s各组件的cli部分都使用Cobra库实现,Cobra 中文文档 - 掘金 (juejin.cn),获取方式如下:

go get -u github.com/spf13/cobra@latest

cobra库中的Command结构体的字段,用于定义命令行工具的行为和选项。它们的作用如下:

Use: 命令名称。
Aliases: 命令的别名。
SuggestFor: 命令建议使用的单词列表。
Short: 命令简短描述。
GroupID: 命令所属的命令组。
Long: 命令详细描述。
Example: 命令的使用示例。
ValidArgs: 命令接受的参数列表。
ValidArgsFunction: 命令用于提供动态参数补全的函数。
Args: 命令的位置参数列表。
ArgAliases: 位置参数的别名。
BashCompletionFunction: 生成Bash补全的函数。
Deprecated: 命令是否已经过时的标志。
Annotations: 命令的附加注释信息。
Version: 命令版本号。
PersistentPreRun: 每次执行该命令之前都会执行的函数。
PersistentPreRunE: 每次执行该命令之前都会执行的返回错误的函数。
PreRun: 每次执行该命令之前都会执行的函数。
PreRunE: 每次执行该命令之前都会执行的返回错误的函数。
Run: 执行命令的函数。
RunE: 执行命令的返回错误的函数,RunE与Run的差别是,RunE执行有错误会直接return,Run无论是否有错误,都会继续执行后面PostRun和PersistentPostRun等逻辑。
PostRun: 每次执行该命令之后都会执行的函数。
PostRunE: 每次执行该命令之后都会执行的返回错误的函数。
PersistentPostRun: 每次执行该命令之后都会执行的函数。
PersistentPostRunE: 每次执行该命令之后都会执行的返回错误的函数。
FParseErrWhitelist : 忽略特定的解析错误
CompletionOptions :控制 shell 自动完成的选项
TraverseChildren: 解析父命令的标志后再执行子命令
Hidden : 隐藏命令,不在可用命令列表中显示
SilenceErrors : 静默下游错误
SilenceUsage : 静默错误时不显示用法
DisableFlagParsing : 禁用标志解析
DisableAutoGenTag : 禁用自动生成的标记
DisableFlagsInUseLine : 在打印帮助或生成文档时禁用“[flags]”在用法行中的添加
DisableSuggestions : 禁用基于Levenshtein距离的建议
SuggestionsMinimumDistance : 显示建议的最小Levenshtein距离

kubectl执行流程

创建cobra.Command对象

    主要流程在cmd.NewDefaultKubectlCommand()中,构建KubectlOptions对象(Kubectl Command的配置对象),指定插件、命令行参数、通用配置和输入输出流,然后调用NewDefaultKubectlCommandWithArgs函数创建Command对象,NewDefaultKubectlCommandWithArgs中调用NewKubectlCommand构建Command对象。

  • 创建&cobra.Command{实例,指定Run函数(执行cmd.help)。指定PersistentPreRunE函数,在Run前进行初始化。指定PersistentPostRunE函数,在Run后执行,将配置写入到磁盘。
  • 为所有的子命令和flag设置规范化函数cliflag.WarnWordSepNormalizeFunc,当参数中包含 "_" 时,会将参数中的 "_" 替换为 "-",同时提示警告信息。
  • addProfilingFlags(flags):增加性能调优的参数开关,统计CPU,内存等相关信息,用于性能优化
  • 添加bool类型全局标志warnings-as-errors,默认值为false
  • 创建ConfigFlags对象,设置命令参数,将参数解析值绑定到kubeConfigFlags
  • 添加一个是否匹配client与server版本的参数match-server-version
  • addCmdHeaderHooks(cmds, kubeConfigFlags):为为rest client 增加HTTP Header,依照SIG CLI KEP 859标准
  • 将kubeconfig对象包装成一个Factory类型,Factory是一个通用对象,它提供了与kube-apiserver的交互方式,以及验证资源对象等方法。 Factory接口封装了 DynamicClient、KubernetesClientSet(简称ClientSet)及RESTClient 3种client-go客户端与kube-apiserver交互的方式。
  • 添加所有的子命令,将所有命令存放在不同的group数组中,然后groups.Add(cmds)将所有的子命令添加,groups.Add函数中会调用cobra库中的AddCommand方法添加子命令。
  • 添加其他子命令。
  • 返回command对象

Command对象的执行

  创建了cobra.Command对象后,调用Kubectl封装的RunNoErrOutput方法,进入Command对象的执行。

  • 设置全局规范化参数cliflag.WordSepNormalizeFunc,将参数中的 "_" 替换为 "-"。
  • flag解析错误打印设置,如果有错误不打印使用方法
  • 日志相关设置
  • 调用 cmd.Execute() 函数执行command

  每个子命令的主要处理逻辑(cobra.Command.Run函数CompleteValidateRun三个函数,其中 complete() 函数中会将命令行参数整理对命令行options进行初始化,设置一些默认值;Validate() 函数会对options中的选项进行检查,打印相应的错误提示信息;Run()函数中执行各子命令的主要处理流程。

创建资源对象的过程(kubectl create -f FILENAME)

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

  • Factory是一个通用对象,它提供了与kube-apiserver的交互方式,以及验证资源对象等方法。 Factory接口封装了 DynamicClient、KubernetesClientSet(简称ClientSet)及RESTClient 3种client-go客户端与kube-apiserver交互的方式。
  • Builder用于将命令行获取的参数转换成资源对象(Resource Object)。它实现了一种通用的资源对象转换功能。
  • Kubernetes Visitor中存在多种实现方法, 不同实现方法的作用不同,如下:

RunCreate()函数流程

raw参数处理。

首先通过f.NewBuilder()实例化Builder对象, 通过函数Unstructured()、 Schema()、 ContinueOnError()、NamespaceParam()、 FilenameParam()、LabelSelectorParam()、 Flatten()对参数赋值和初始化, 将参数保存到Builder对象中。 最后通过Do()函数生成最终的rusult对象,设置rusult.visitor。

   // 实例化builder对象
r := f.NewBuilder().
	// 以map的方式传输数据对象,对响应内容中的数据做一层封装,这样就可以保留所有字段而不需要首先解析成一个struct
	Unstructured().
	//
	Schema(schema).
	// 配置result对象在出现错误的行为,意思很明显,在出错后继续
	ContinueOnError().
	// 基于命令行参数设置查询的namespace
	NamespaceParam(cmdNamespace).DefaultNamespace().
	// 解析文件名参数 参数 -f,文件名被存放在 b.paths 中
	FilenameParam(enforceNamespace,&o.FilenameOptions).
	// 解析标签选择器 参数 -l
	LabelSelectorParam(o.Selector). 
	// 将对象展开,比如对象是[a, b], 如果没有flatten就是完成访问[a,b]作为一个整体,反之, 让外层函数分别访问a,b
    Flatten().
	// 基于之前的配置,生成最终的result对象
    Do()

Do函数中设置rusult.visitor多层匿名函数嵌套关系如下:

result.Visitor = DecoratedVisitor {    // 在函数Do函数中通过NewDecoratedVisitor函数执设置,并且注册了SetNamespace、RequireNamespace、FilterNamespace、RetrieveLazy等修饰函数。
	visitor: ContinueOnErrorVisitor {    // 在函数Do函数中,如果b.continueOnError为真设置,b.continueOnError在函数ContinueOnError()设置。
		visitor: FlattenListVisitor {    // 在函数Do函数中设置,这个感觉有点多余,在后面的流程中还会设置一个FlattenListVisitor。
			visitor: FilteredVisitor {    // 在函数visitByPaths中,含有Selector时设置,对每个对象对应的info对象进行检查,检查函数为FilterByLabelSelector(selector)。
				visitor: FlattenListVisitor {    // 在函数visitByPaths中,b.flatten为真时设置,b.flatten在上面的Flatten()函数中设为true。
					Visitor: EagerVisitorList {    // 在函数visitByPaths中将b.paths强转成EagerVisitorList,调用关系:Do() -> b.visitorResult() -> b.visitByPaths()。
						[]b.paths FileVisitor {    // 每个文件对应一个FileVisitor,所有的FileVisitor被append到 b.paths 数组中。
							StreamVisitor: StreamVisitor {
								Reader: r,
								mapper: mapper,
								Source: source,    
								Schema: b.schema,
							},
						},
					},
				},
			},
		},
	},
} 

执行Result.Visit(),该函数中会按照上面多层嵌套关系执行每一个Visit函数,按顺序 处理逻辑如下:

  • 从 DecoratedVisitor.Visit 一直到 EagerVisitorList.Visit都是在函数开始就直接执行对象的成员visitor的Visit函数,直到FileVisitor.Visit中才是先执行本身的流程,然后再执行对象的成员visitor的Visit函数。
  • FileVisitor:打开xml文件,读取里面的数据到一个io.Reader中,然后执行StreamVisitor.Visit。
  • StreamVisitor:对xml文件中的数据进行解码,然后执行 infoForData 函数将解码后的数据转换成info对象,然后执行 EagerVisitorList定义的VisitorFunc(通过 FileVisitor 转传入)。
  • EagerVisitorList:将所有的err信息收集到一个集合中返回,如果StreamVisitor出现错误直接 return,如果没有错误执行FlattenListVisitor定义的VisitorFunc
  • FlattenListVisitor:如果yaml文件中包含多个资源对象,将runtime.ObjectTyper解析成多个runtime.Object,再转换为多个Info,逐个调用VisitorFunc,即执行FilteredVisitor定义的VisitFunc函数。
  • FilteredVisitor:对Info进行检验, 进行Selector检查。如果不满足条件,则返回error信息,如果满足条件则执行VisitorFunc,即FlattenListVisitor定义的VisitFunc函数
  • FlattenListVisitor:因为上面已经执行过一次FlattenListVisitor了,这里会直接执行ContinueOnErrorVisitor定义的VisitorFunc
  • ContinueOnErrorVisitor:将Visitor调用过程中产生的错误保留在[]error中,然后执行DecoratedVisitor定义的VisitorFunc
  • DecoratedVisitor:执行注册过的VisitorFunc,然后执行result指定的VisitorFunc。
  • Result指定的VisitFunc:通过Helper.Create向kube-apiserver发送创建资源的请求,然后将与kube-apiserver交互后得到的结果通过info.Refresh函数更新到info.Object中。Helper.Create最终会进入createResource函数
func (m *Helper) createResource(c RESTClient, resource, namespace string, obj runtime.Object, options *metav1.CreateOptions) (runtime.Object, error) {
	// RESTFUL接口风格中,POST请求对应的就时CREATE方法
	return c.Post(). 
	NamespaceIfScoped(namespace,m.NamespaceScoped).
	Resource(resource).
	VersionedParams(options,metav1.ParameterCodec).
	Body(obj).
	// 发送请求
	Do(context.TODO()).
	// 将请求结果转换成runtime.Object
	Get()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1360520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能优化-OpenMP基础教程(五)-全面讲解OpenMP基本编程方法

本文主要介绍OpenMP编程的编程要素和实战,包括并行域管理详细实战、任务分担详细实战。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:高性能(HPC)开发基础教程 🎀C…

Linux与安全

本心、输入输出、结果 文章目录 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第八部分:Linux、安全 前言 Linux 文件系统解释应该知道的 18 个最常用的 Linux 命令HTTPS如何工作? 数据是如何加密和解密的?为什么HTTPS在数据传输过程…

IntelliJ IDEA远程查看修改Ubuntu上AOSP源码

IntelliJ IDEA远程查看修改Ubuntu上的源码 本人操作环境windows10,软件版本IntelliJ IDEA 2023.2.3,虚拟机Ubuntu 22.04.3 LTS 1、Ubuntu系统安装openssh 查看是否安装: ssh -V 如果未安装: sudo apt install openssh-server # 开机自启…

php 数组中的元素进行排列组合

需求背景:计算出数组[A,B,C,D]各种排列组合,希望得到的是数据如下图 直接上代码: private function finish_combination($array, &$groupResult [], $splite ,){$result [];$finish_result [];$this->diffArrayItems($array, $…

springboot实现ChatGPT式调用(一次调用,持续返回)

下边实现了一个持续返回100以内随机数的接口,在接口超时之前会每隔1秒返回一个随机数 GetMapping(value "/getRandomNum", produces MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter getRandomNum() {SseEmitter emitter new SseEmitter();Th…

使用STM32的定时器和PWM实现LCD1602的背光控制

使用STM32的定时器和PWM功能来控制LCD1602的背光是一种常见的方法,它可以实现背光的亮度调节和闪烁效果。在本文中,我们将讨论如何利用STM32的定时器和PWM来实现LCD1602的背光控制,并提供相应的代码示例。 1. 硬件连接和初始化 首先&#x…

负责任的人工智能与人机环境系统智能

负责任的人工智能是指在人工智能系统的设计、开发、管理、使用和维护过程中,所有相关的角色(包括设计者、开发者、管理者、使用者、维护者等等)都承担其行为的道义、法律和社会责任。这意味着这些角色需要确保人工智能系统的设计与使用符合伦…

C++完成使用map Update数据 二进制数据

1、在LXMysql.h和LXMysql.cpp分别定义和编写关于pin语句的代码 //获取更新数据的sql语句 where语句中用户要包含where 更新std::string GetUpdatesql(XDATA kv, std::string table, std::string where); std::string LXMysql::GetUpdatesql(XDATA kv, std::string table, std…

window服务器thinkphp队列监听服务

经常使用linux的同学们应该对使用宝塔来做队列监听一定非常熟悉,但对于windows系统下,如何去做队列的监听?是一个很麻烦的事情。 本文将通过windows系统的服务来实现队列的监听。 对于thinkphp6 queue如何使用,不再赘述。其它系…

Java经典框架之Zookeeper

Zookeeper Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Zookeeper的介绍和安装 2. …

JavaScript 基础学习笔记(四):循环语句、while循环、中止循环、无限循环、for 语句

目录 一、循环语句 1.1 while循环 1.2 中止循环 1.3 无限循环 二、综合案例-ATM存取款机 三、for 语句 一、循环语句 1.1 while循环 while : 在…. 期间, 所以 while循环 就是在满足条件期间,重复执行某些代码。 语法: while (条件表…

vue3-admin-element框架实现动态路由(根据接口返回)

第一步:在src-utils-handleRoutes,修改代码: export function convertRouter(routers) {let array routersrouters []for (let i in array) {for(let s in asyncRoutes){if (array[i].path asyncRoutes[s].path) {routers.push(asyncRout…

如何下载 ASTR 数据

ASTR (Advanced Spaceborne Thermal Emission and Reflection Radiometer) 卫星是由美国宇航局 (NASA) 和日本国家航空航天局 (JAXA) 合作开发和运营的。ASTR 主要用于地球观测,其主要仪器包括三个子系统: VNIR (Visible and Near Infrared) 子系统&…

C++矩阵例题分析(3):螺旋矩阵

一、审题 时间限制:1000ms 内存限制:256MB 各平台平均AC率:14.89% 题目描述 输出一个n*n大小的螺旋矩阵。 螺旋矩阵的样子: 输入描述 共一行,一个正整数n,表示矩阵变长的长度…

掌握 Postman Newman:快速启动 API 测试自动化

Postman 中的 Newman 是什么? Newman 是一个 CLI(命令行界面)工具,用于运行 Postman 中的集合(Collection)和环境(Environment)来进行自动化测试。它允许直接从命令行运行 Postman …

Docker数据卷详解

文章目录 数据卷1 cp命令2 数据卷2.1 数据卷类型2.2 宿主机数据卷2.3 命名的数据卷2.4 匿名数据卷2.5 清理数据卷2.6 数据卷容器 数据卷 ​ 当我们在使用docker容器的时候,会产生一系列的数据文件,这些数据文件在我们删除docker容器时是会消失的&#x…

thinkphp学习04-控制器定义

控制器,即 controller,控制器文件存放在 controller 目录下; 如果想改变系统默认的控制器文件目录,可以在 config 下 route.php 配置: 将controller修改为controller123,就会报错,说明这个配置…

Tecplot 各版本安装指南

Tecplot下载链接 https://pan.baidu.com/s/1XbzjHnho8zIF7eC4KBFmgA?pwd0531 1.鼠标右击【Tecplot 360 EX 2023(64bit)】压缩包(win11及以上系统需先点击“显示更多选项”)【解压到 Tecplot 360 EX 2023(64bit)】。①解压前:需要先关闭“所…

C# 使用匿名管道进行本地进程间通信

目录 写在前面 代码实现 客户端进程 服务端进程 调用示例 写在前面 相对于命名管道通讯方式而言,匿名管道开销更小,更轻松便捷;缺点就是无法进行网络通讯,只能在本机使用,应用场景相对狭窄;适合于本地…