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
裏面去。