kube-ApiServer至关因而k8集群的一个入口,不论经过kubectl仍是使用remote api 直接控制,都要通过apiserver。apiserver说白了就是一个server负责监听指定的端口(http/https协议),以后处理不一样的请求,只不过加上的不少控制;apiserver是k8s系统中全部对象的增删查改盯的http/restful式服务端,其中盯是指watch操做【watch是apiserver中的重要操做之一】。数据最终存储在分布式一致的etcd存储内,apiserver自己是无状态的,提供了这些数据访问的认证鉴权、缓存、api版本适配转换等一系列的功能。git
对于http服务和使用go语言实现方式,能够看go-restful的文档和例子
github
k8s存放在etcd内的存储对象是api.Pod对象(无版本),从不一样版本的请求路径标示来操做,例如api/v1,最后获取到的是不一样版本,例如v1.Pod的json文本。这里就经历了几个过程,包括:json
一、http client访问/api/v1/pod/xyz, 想要获取到这个Pod的数据api
二、从etcd获取到api.Pod对象缓存
三、api.Pod对象转换为v1.Pod对象restful
四、v1.Pod对象序列化为json或yaml文本数据结构
五、文本经过http的response体,返回给http clientapp
其中用于处理业务数据的关键数据结构是APIGroupVersion:分布式
1 // APIGroupVersion is a helper for exposing rest.Storage objects as http.Handlers via go-restful 2 // It handles URLs of the form: 3 // /${storage_key}[/${object_name}] 4 // Where 'storage_key' points to a rest.Storage object stored in storage. 5 // This object should contain all parameterization necessary for running a particular API version 6 //重点数据结构 7 type APIGroupVersion struct { 8 //最重要的数据结构,该map的key是用于对,value是rest.Storage结构,用于对接etcd存储, 9 //在初始化注册时,会把这个map化开,化为真正的rest服务到存储的一条龙服务 10 Storage map[string]rest.Storage 11 12 Root string 13 14 // GroupVersion is the external group version 15 // 包含api/v1这样的string,用于标示这个实例 16 GroupVersion unversioned.GroupVersion 17 18 // RequestInfoResolver is used to parse URLs for the legacy proxy handler. Don't use this for anything else 19 // TODO: refactor proxy handler to use sub resources 20 RequestInfoResolver *RequestInfoResolver 21 22 // OptionsExternalVersion controls the Kubernetes APIVersion used for common objects in the apiserver 23 // schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may 24 // define a version "v1beta1" but want to use the Kubernetes "v1" internal objects. If 25 // empty, defaults to GroupVersion. 26 OptionsExternalVersion *unversioned.GroupVersion 27 28 Mapper meta.RESTMapper 29 30 // Serializer is used to determine how to convert responses from API methods into bytes to send over 31 // the wire. 32 //对象序列化和反序列化器 33 Serializer runtime.NegotiatedSerializer 34 ParameterCodec runtime.ParameterCodec 35 36 Typer runtime.ObjectTyper 37 Creater runtime.ObjectCreater 38 //能够转换任意一种对象到另外一种,只要你事先注入了相应的转换函数 39 HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) 40 Convertor runtime.ObjectConvertor 41 Copier runtime.ObjectCopier 42 Linker runtime.SelfLinker 43 44 Admit admission.Interface 45 Context api.RequestContextMapper 46 47 MinRequestTimeout time.Duration 48 49 // SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is 50 // accessible from this API group version. The GroupVersionKind is that of the external version of 51 // the subresource. The key of this map should be the path of the subresource. The keys here should 52 // match the keys in the Storage map above for subresources. 53 SubresourceGroupVersionKind map[string]unversioned.GroupVersionKind 54 }
k8s采用ApiGroup来管理全部的api分组和版本升级,目前的API分组包括:ide
一、核心组,REST路径在/api/v1,但这个路径不是固定的,v1是当前的版本。与之相对应的代码里面的apiVersion字段的值为v1.
二、扩展组,REST路径在/apis/extensions/$version, 相应的代码里面的apiversion:extensions/$VERSION(eg:apiVersion:extensions/v1beta1),这里的API对象可能会被从新分组;
三、"componentconfig" 和 "metrics"这些组
在这个文档里面讲述了实现ApiGroup的几个目标,包括api分组演化,对旧版API的向后兼容(Backwards compatibility),包括用户能够自定义本身的api等。接下来咱们看看他么是怎么初始化注册的,这里都是缩减版代码,去掉了其余部分。
kubernets/pkg/master/master.go func New(c *Config)(*Master, error) { m.InstallAPIs(c) }
2.根据Config往APIGroupsInfo
内增长组信息,而后经过InstallAPIGroups
进行注册
1 func (m *Master) InstallAPIs(c *Config) { 2 if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { 3 glog.Fatalf("Error in registering group versions:%v", err) 4 } 5 }
3.转换为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) } }
4.APIGroupVersion 关键数据结构
kubernetes/pkg/apiserver/apiserver.go type APIGroupVersion struct { Storage map[string]rest.Storage Root string //GroupVersion is the external group version GroupVersion unversioned.GroupVersion }
5.实际注册的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:
k8s使用的一个第三方库,里面提供了一组核心的对象,看例子 GET /api/v1/namespaces/{namespace}/pods/{name}
github.com/emicklei/go-restful
数据结构 | 功能 | 在k8s内的位置 |
---|---|---|
restful.Container | 表明一个http rest服务对象,包括一组restful.WebService | genericapiserver.go - GenericAPIServer.HandlerContainer |
restful.WebService | 由多个restful.Route组成,处理这些路径下全部的特殊的MIME类型等 | api_installer.go - NewWebService() |
restful.Route | 路径——处理函数映射map | api_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关联起来。上面已经基本厘清了从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 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对象,并最终注册到ApiGroup
里面去。