kubernetes代码阅读-apiserver基础篇
apiserver是整个kubernetes的核心模块,做的事情多,代码量也较大。市面上已经有不少apiserver代码解读的文章了,但问题在于,由于k8s的代码变化很快,想写一篇长久能用的未必能做到。所以,我参照了《Kubernetes权威指南》和浙大SEL实验室的一些文章,先把我看到的东西记下来,待后观是否有用。 kubernetes源代码版本1.2.0 代码阅读方法先简单讲讲整个代码的目录结构
可以看到,关键实现代码都放在pkg这个目录下。对于apiserver这种跨度很广的组件而言,唯一有效的阅读方式估计就是
0. apiserver主要实现了什么?apiserver是k8s系统中所有对象的增删查改盯的http/restful式服务端,其中盯是指watch操作。数据最终存储在分布式一致的etcd存储内,apiserver本身是无状态的,提供了这些数据访问的认证鉴权、缓存、api版本适配转换等一系列的功能。
对于http服务和使用go语言实现方式,可以看go-restful的文档和例子,对这个有基本的了解,这个文档对入门者和一知半解者极为有效! 1. 对象的数据结构古人有言,程序就是算法+数据结构,搞懂了数据结构,整个程序的处理过程就明白了一半。对于apiserver的任何一个api请求来说,上图说明了所有的数据结构关系。 k8s放在etcd内的存储对象是api.Pod对象(无版本),从不同版本的请求路径标识来操作,例如
其中用于处理业务数据的关键数据结构是APIGroupVersion,里面的几个成员变量的作用是:
2. 入口和启动
3. API分组、多版本的初始化注册(Rest)k8s采用ApiGroup来管理所有的api分组和版本升级,目前有的API分组包括
在这个文档里面讲述了实现ApiGroup的几个目标,包括api分组演化,对旧版API的向后兼容(Backwards compatibility),包括用户可以自定义自己的api等。接下来我们看看他么是怎么初始化注册的,这里都是缩减版代码,去掉了其他部分。 kubernetes/pkg/master/master.go
func New(c *Config) (*Master,error) { m.InstallAPIs(c) }
func (m *Master) InstallAPIs(c *Config) { if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v",err) } }
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, 那么,这里的 GET /api/v1/namespaces/{namespace}/pods/{name}
k8s使用的一个第三方库
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 这里的 // REST implements a RESTStorage for pods against etcd type REST struct { *etcdgeneric.Etcd proxyTransport http.RoundTripper } 由于PodStorage.Pod是一个REST类型,而REST类型采用了Go语言的struct匿名内部成员,天然就拥有Get,List等方法。 kubernetes/pkg/apiserver/api_installer.go 最后在这里把PodStorage转换成了Getter对象,并最终注册到 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |