k8s代码走读---client-go编程交互基础
前言
代码 clone 地址:https://github.com/kubernetes/client-go。实际上在 kubernetes 的源码中也包含了这部分代码:vendor/k8s.io/client-go/
。看代码都没问题。
client-go 是 kubernetes 中比较重要的一个组件,从我上一篇文章中梳理的图中可以看出来,apiserver 是一个核心,其它组件都要和这个核心模块交互,所以 client-go 的出现就是为了统一封装对 apiserver 的交互访问。还是放这个图哈。
*我思故我在*
client-go 这种设计思路还是不错的,当然是适合 kubernetes 这样的项目,几乎所有的模块都在围绕 apiserver,那么和 apiserver 的交互就显的尤为重要,那么这部分代码的抽象封装也就顺理成章了。这种解偶方式也是挺特别的,在看了书,走读了这部分的源码之后也才发现,同样的 client 在使用方式,使用对象不一样,就需要不一样的封装方式。
kubernetes 的 client-go 根据具体使用的方式进行了基础库封装和另外 4 种(书上介绍 3 种,我认为 scale client 也是一种 client)类型的 client 封装,分别针对不同的应用场景。discovery client,dynamic client,clientset,scale client。
今天在公司讨论 sdk 的封装上就讨论到这一点,sdk 的封装很多时候不能过分也不能太简单。太简单,开发体验不好,开发者还有设置或者配置或者开发很多东西,封装太过,封装了很多开发者不想要的内容也很麻烦。所以这样的封装一定要多元化,多层次的来提供。
目录结构
认识代码还是从目录结构开始,我认为 golang 的规范做的非常好,有官方自己的代码规范工具,还有指导的工程代码目录结构规范。这里针对 client-go 我只列出我认为重要的一些目录。
目录名 |
用途 |
---|---|
discovery |
这个是 discovery client 的代码,是对 rest 客户端的进一步封装,用于发现 apiserver 所支持的能力和信息 |
dynamic |
这个是 dynamic client 的代码,是对 rest 客户端的进一步封装,动态客户端,面向处理 CRD |
examples |
这里面有一些例子,比如对 deployment 创建、修改,如何选主,workqueue 如何使用等等 |
informers |
这就是 client-go 中非常有名的 informer 机制的核心代码 |
kubernetes |
clientset 的代码,也是对 rest 客户端的进一步封装,提供复杂的资源访问和管理能力 |
listers |
为每个 k8s 资源提供 lister 功能,提供了只读缓存功能 |
metadata |
|
pkg |
主要是一些功能函数,比如版本函数 |
rest |
这是最基础的 client,其它的 client 都是基于此派生的 |
scale |
scale client 的代码 |
tools |
工具函数库,主要是和 k8s 相关的工具函数 |
util |
通用的一些工具函数 |
transport |
提供安全 tcp 链接 |
rest client 核心数据结构
首先还是从核心数据结构走起:
type RESTClient struct {
// 这个初始化的 apiserver 的地址,下面我也贴了一个 kubeconfig 文件的内容,这个地址就是 cluster 的 server。
base *url.URL
// 这个是 apiVersion
versionedAPIPath string
// 对客户端编解码的设置
content ClientContentConfig
// creates BackoffManager that is passed to requests.
createBackoffMgr func() BackoffManager
// 限流控制,是针对这个客户端的所有请求的。这个也是非常好的一个设计,一般 sdk 的设计很少考虑这个,大多数只考虑功能
rateLimiter flowcontrol.RateLimiter
// warningHandler is shared among all requests created by this client.
// If not set, defaultWarningHandler is used.
warningHandler WarningHandler
// http 请求客户端
Client *http.Client
}
clinet-go 启动配置文件
客户端启动是需要配置文件的,要知道要去链接那个 apiserver,使用那个账户信息等等。这个配置文件保存在 ~/.kube/config
。我机器上的格式如下:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxx
server: https://192.168.1.10:60002
name: local
contexts:
- context:
cluster: local
user: admin
name: master
current-context: master
kind: Config
preferences: {}
users:
- name: admin
user:
token: xxx
主要分为 clusters,contexts,users,用户保存集群信息,可以支持多个集群,多个账户访问使用,每个集群和用户有自己独立的鉴权数据或是 token。
client 封装
client-go 的 rest client 实际上在很多时候使用起来还是不方便的,而且在逐步的发展中 对 client 的要求会有多种多样,所以针对这一需求 client-go 又进行了抽象和封装,把常用到的 client 类型进行专门封装,形成独立的库,以方便直接使用,这样避免了直接使用基础 rest client 时又要进行再次编码封装。目前形成的常用到的封装 client 有这样几个:discovery client,dynamic client,clientset 和 scaleClient,scaleClient 在《kubernetes源码剖析》这本书中没有提到,但是我看了 1.14 版本的代码中是有这个的实现和介绍的。在它的代码介绍中是这样介绍的:
// scaleClient is an implementation of ScalesGetter
// which makes use of a RESTMapper and a generic REST
// client to support an discoverable resource.
// It behaves somewhat similarly to the dynamic ClientPool,
// but is more specifically scoped to Scale.
// 简单翻译最后一句话:它的功能有点像 dynamic ClientPool,但是它更聚焦在扩展能力上。
这种封装在一定程度上是可以提升开发者体验的,对开发者比较好,很多代码直接由官方来提供,而不用开发者自己再写。避免了直接使用裸的基础 client。但是这种封装也一定得有限制不能无限多,不然维护成本会很高。
后记
针对这几种客户端,我后面想写一些例子来实际跑一跑,目前只是简单的认识这些 client。当然源代码中也有例子可以参考学习,目前由于我的时间问题只是走读了代码,没有对官方的源码例子进行编译执行。实际上公司内有同学开发了一个对 k8s 事件收集的模块,这个模块的代码我也是参与开发了一部分,从编译执行上来说是没问题,之前是没有从 client-go 这部分代码上去理解,现在感觉对这部分代码的认识更深了一些。
- insert导致的性能问题大排查(r11笔记第26天)
- NYOJ-----最少乘法次数
- nyOJ-----韩信点兵
- HDUOJ-----A == B ?
- 用Oracle的眼光来学习MySQL 5.7的sys(上)(r11笔记第24天)
- Golang下通过syscall调用win32的api
- NYOJ----蛇形填数
- Golang语言 syscall 例子
- 用Oracle的眼光来学习MySQL 5.7的sys(下)(r11笔记第25天)
- HDUOJ-----Climbing Worm
- 闪回原理测试(二)(r11笔记第23天)
- SQL复习之为数据库用户赋予权限
- linux下syscall函数,SYS_gettid,SYS_tgkill
- 数据库收缩数据文件的尝试(三)(r11笔记第22天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MLQuant:基于XGBoost的金融时序交易策略(附代码)
- 探索在网页中使用“标注”
- 笔试题:了解穷举算法吗?如何用代码实现
- 硬核看房利器——Web 全景的实现
- 超级播放器tcplayer如何设置logo
- 【Flutter 实战】1.20版本更新及新增组件
- 手把手教你使用Python实现常用的假设检验 !
- Oracle 每日一题系列合集
- Arrow更好用的python时间序列处理库,你用过吗?
- 死信队列监听补充
- 手把手教你用Python查询你的物流信息
- Selenium自动登录淘宝,我无意间发现了登录漏洞!
- 【DB宝20】在Docker中分分钟即可拥有OGG Director环境
- mq监听死信队列后如何处理
- 【小白学PyTorch】7 最新版本torchvision.transforms常用API翻译与讲解