千家信息网

kubernetes代码阅读apiserver的示例分析

发表于:2025-02-03 作者:千家信息网编辑
千家信息网最后更新 2025年02月03日,这篇文章主要介绍了kubernetes代码阅读apiserver的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。apiserv
千家信息网最后更新 2025年02月03日kubernetes代码阅读apiserver的示例分析

这篇文章主要介绍了kubernetes代码阅读apiserver的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

apiserver是整个kubernetes的核心模块,做的事情多,代码量也较大。市面上已经有不少apiserver代码解读的文章了,但问题在于,由于k8s的代码变化很快,想写一篇长久能用的未必能做到。所以,我参照了《Kubernetes权威指南》和浙大SEL实验室的一些文章,先把我看到的东西记下来,待后观是否有用。

kubernetes源代码版本1.2.0

代码阅读方法

先简单讲讲整个代码的目录结构

目录说明
api输出接口文档用
build构建脚本
cluster适配不同I层的云,例如亚马逊AWS,微软Azure,谷歌GCE的集群启动脚本
cmd所有的二进制可执行文件入口代码,例如apiserver/scheduler/kubelet
contrib项目贡献者
docs文档,包括了用户文档、管理员文档、设计、新功能提议
example使用案例
Godeps项目中依赖使用的Go第三方包,例如docker客户端SDK,rest等
hack工具箱,各种编译、构建、测试、校验的脚本都在这里面
hooksgit提交前后触发的脚本
pkg项目代码主目录,cmd的只是个入口,这里是所有的具体实现
plugin插件,k8s认为调度器是插件的一部分,所以调度器的代码在这里
release应该是Google发版本用的?
test测试相关的工具
third_party一些第三方工具,应该不是强依赖的?
wwwUI,不过已经被移动到新项目了

可以看到,关键实现代码都放在pkg这个目录下。对于apiserver这种跨度很广的组件而言,唯一有效的阅读方式估计就是

  1. 遍历pkg下所有的目录,概览大概知道这个目录是干啥的

  2. 从cmd这个入口来看apiserver的代码,然后一点点由浅入深,看apiserver的大致实现

  3. 分特性,看具体某个大的特性是怎么实现的,例如安全,例如和etcd存储对接

  4. 在上面这几步的过程中可以看看别人的代码阅读文档,能有效的节省时间

0. apiserver主要实现了什么?

apiserver是k8s系统中所有对象的增删查改盯的http/restful式服务端,其中盯是指watch操作。数据最终存储在分布式一致的etcd存储内,apiserver本身是无状态的,提供了这些数据访问的认证鉴权、缓存、api版本适配转换等一系列的功能。

  • restful服务入门

对于http服务和使用go语言实现方式,可以看go-restful的文档和例子,对这个有基本的了解,这个文档对入门者和一知半解者极为有效!

1. 对象的数据结构

古人有言,程序就是算法+数据结构,搞懂了数据结构,整个程序的处理过程就明白了一半。对于apiserver的任何一个api请求来说,上图说明了所有的数据结构关系。

k8s放在etcd内的存储对象是api.Pod对象(无版本),从不同版本的请求路径标识来操作,例如api/v1,最后获取到的是不同版本,例如v1.Pod的json文本。这里就经历了几个过程,包括

  1. http client访问/api/v1/pod/xyz,想要获取这个Pod的数据

  2. 从etcd获取到api.Pod对象

  3. api.Pod对象转换为v1.Pod对象

  4. v1.Pod对象序列化为json或yaml文本

  5. 文本通过http的response体,返回给http client

其中用于处理业务数据的关键数据结构是APIGroupVersion,里面的几个成员变量的作用是:

成员作用
GroupVersion包含 api/v1这样的string,用于标识这个实例
Serializer对象序列化和反序列化器
Converter这是一个强大的数据结构,这里放的是个接口,本体在/pkg/conversion/conversion.go,几乎可以转换任意一种对象到另一种,只要你事先注入了相应的转换函数
Storage这个map的key,用于对象的url,value是一个rest.Storage结构,用于对接etcd存储,在初始化注册时,会把这个map化开,化为真正的rest服务到存储的一条龙服务

2. 入口和启动

文件主要数据结构/函数用途
kubernetes/cmd/kube-apiserver/apiserver.go
入口
kubernetes/cmd/kube-apiserver/app/options/options.gostruct APIServer启动选项
kubernetes/cmd/kube-apiserver/apiserver.gofunc Run初始化一些客户端、启动master对象
kubernetes/pkg/genericapiserver/genericapiserver.gofunc Run启动安全和非安全的http服务

3. API分组、多版本的初始化注册(Rest)

k8s采用ApiGroup来管理所有的api分组和版本升级,目前有的API分组包括

  1. 核心组,REST路径在 /api/v1 ,但这个路径不是固定的,v1是当前的版本。与之相对应的代码里面的apiVersion 字段的值是 v1

  2. 扩展组,REST路径在 /apis/extensions/$VERSION,相对应的代码里面的 apiVersion: extensions/$VERSION (例如当前的apiVersion: extensions/v1beta1)。这里提供的API对象今后有可能会被移动到别的组内。

  3. "componentconfig"和 "metrics"这这些组。

在这个文档里面讲述了实现ApiGroup的几个目标,包括api分组演化,对旧版API的向后兼容(Backwards compatibility),包括用户可以自定义自己的api等。接下来我们看看他么是怎么初始化注册的,这里都是缩减版代码,去掉了其他部分。

kubernetes/pkg/master/master.go
  • api注册入口

func New(c *Config) (*Master, error) {        m.InstallAPIs(c)}
  • 根据Config往APIGroupsInfo内增加组信息,然后通过InstallAPIGroups进行注册

func (m *Master) InstallAPIs(c *Config) {        if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {                glog.Fatalf("Error in registering group versions: %v", err)        }}
  • 转换为APIGroupVersion这个关键数据结构,然后进行注册

func (s *GenericAPIServer) installAPIGroup(apiGroupInfo *APIGroupInfo) error {                apiGroupVersion, err := s.getAPIGroupVersion(apiGroupInfo, groupVersion, apiPrefix)                if err := apiGroupVersion.InstallREST(s.HandlerContainer); err != nil {                        return fmt.Errorf("Unable to setup API %v: %v", apiGroupInfo, err)                }}               
  • 关键数据结构

kubernetes/pkg/apiserver/apiserver.go
type APIGroupVersion struct {        Storage map[string]rest.Storage        Root string        // GroupVersion is the external group version        GroupVersion unversioned.GroupVersion}

实际注册的Storage的map如下:

kubernetes/pkg/master/master.go
        m.v1ResourcesStorage = map[string]rest.Storage{                "pods":             podStorage.Pod,                "pods/attach":      podStorage.Attach,                "pods/status":      podStorage.Status,                "pods/log":         podStorage.Log,                "pods/exec":        podStorage.Exec,                "pods/portforward": podStorage.PortForward,                "pods/proxy":       podStorage.Proxy,                "pods/binding":     podStorage.Binding,                "bindings":         podStorage.Binding,

那么,这里的map[string]rest.Storage最后是怎么变成一个具体的API来提供服务的呢?例如这么一个URL:

GET /api/v1/namespaces/{namespace}/pods/{name}
  • restful服务的实现

k8s使用的一个第三方库github.com/emicklei/go-restful,里面提供了一组核心的对象,看例子

数据结构功能在k8s内的位置
restful.Container代表一个http rest服务对象,包括一组restful.WebServicegenericapiserver.go - GenericAPIServer.HandlerContainer
restful.WebService由多个restful.Route组成,处理这些路径下所有的特殊的MIME类型等api_installer.go - NewWebService()
restful.Route路径--处理函数映射mapapi_installer.go - registerResourceHandlers()
  • 实际注册过程

kubernetes/pkg/apiserver/api_installer.go
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService, proxyHandler http.Handler) (*unversioned.APIResource, error) {}

最终的API注册过程是在这个函数中完成的,把一个rest.Storage对象转换为实际的getter, lister等处理函数,并和实际的url关联起来。

4.etcd存储的操作(ORM)

上面已经基本厘清了从http请求 -> restful.Route -> rest.Storage这条线路,那rest.Storage仅仅是一个接口,有何德何能,可以真正的操作etcd呢?

这段也是牵涉到多个文件,但还比较清晰,首先,所有的对象都有增删改查这些操作,如果为Pod单独搞一套,Controller单独搞一套,那代码会非常重复,不可复用,所以存储的关键目录是在这里:

kubernetes/pkg/registry/generic/etcd/etcd.go

这个文件定义了所有的对etcd对象的操作,get,list,create等,但具体的对象是啥,这个文件不关心;etcd客户端地址,这个文件也不关心。这些信息都是在具体的PodStorage对象创建的时候注入的。以Pod为例子,文件在:

kubernetes/pkg/registry/pod/etcd/etcd.go

这里的NewStorage方法,把上述的信息注入了etcd里面去,生成了PodStorage这个对象。

// REST implements a RESTStorage for pods against etcdtype REST struct {        *etcdgeneric.Etcd        proxyTransport http.RoundTripper}

由于PodStorage.Pod是一个REST类型,而REST类型采用了Go语言的struct匿名内部成员,天然就拥有Get, List等方法。

kubernetes/pkg/apiserver/api_installer.go

最后在这里把PodStorage转换成了Getter对象,并最终注册到ApiGroup里面去。

感谢你能够认真阅读完这篇文章,希望小编分享的"kubernetes代码阅读apiserver的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

对象 代码 数据 结构 数据结构 版本 服务 文档 存储 文件 目录 入口 路径 关键 函数 过程 处理 实际 篇文章 脚本 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 中宏黄金互联网科技怎么样 小学生网络安全课程视频 紫康网络技术和爱尔眼科 字段的信息在数据库引擎中 计算机网络技术大专考什么 怎么测试服务器是否可以注册 命令行设置服务器ip地址 苏州柒零叁网络技术怎么样 计算机网络技术问答 软件开发公司报表格式 DL380服务器管理IP 卖网络安全产品如何分析客户需求 虹口区数据软件开发信息中心 网络安全论文 有引用 设计算机三级网络技术通过率 泰顺刀片服务器信息推荐 empower 数据库错误 cdn服务器采用什么技术 列在数据库中叫什么 云服务器安全组放行 公共场合网络安全 查询细胞膜蛋白数据库 上海众人网络安全 谈剑锋诈骗 透视互联网络科技有限公司招聘 wifi网络技术发展前景 阿里云轻量服务器怎么进系统 长宁区环保网络技术案例 战地1行动模式服务器 计算机网络技术文件共享 lol比赛中各个选手的服务器
0