API Server簡介
在 kubernetes 集群中,API Server 有着非常重要的角色。API Server 負責和 etcd 交互(其他組件不會直接操作 etcd,只有 API Server 這么做),是整個 kubernetes 集群的數據中心,所有的交互都是以 API Server 為核心的。簡單來說,API Server 提供了以下的功能:
- 整個集群管理的 API 接口:所有對集群進行的查詢和管理都要通過 API 來進行
- 集群內部各個模塊之間通信的樞紐:所有模塊之前並不會之間互相調用,而是通過和 API Server 打交道來完成自己那部分的工作
- 集群安全控制:API Server 提供的驗證和授權保證了整個集群的安全
API Server源碼分析
github地址:https://github.com/kubernetes/kubernetes(當前master對應版本1.8)
sourcegraph網站地址:https://sourcegraph.com/github.com/kubernetes/kubernetes@master
入口:kubernetes
--》kubernetes
可以看到先是調用CreateServerChain方法去創建一些server然后去啟動這些server
CreateServerChain方法里面主要創建了兩個server,一個是kubeAPIServer,一個是apiExtensionsServer。kubeAPIServer是kubernetes獨有的API Server,它負責的是kubernetes最主要的api,官方文檔里面不建議在這個里面添加和修改api,如果我們有自己編寫的api可以放在apiExtensionsServer里面,這個server是負責一些擴展的api。
創建kubeAPIServer用到了CreateKubeAPIServer方法,此方法里面的創建server的關鍵代碼如下:
kubeAPIServerConfig是創建server所用到資源(resource)和配置,complete方法自動填充那些不能為空的字段值,new方法根據傳入的config返回一個Server的實例。
--》kubernetes
new方法里面先根據配置創建一個名字為kube-apiserver的server
然后生成一個Master結構體,此結構體的API Server為剛剛創建的kube-apiserver
然后先注冊核心api即LegacyAPI(此方法后面會注冊其他的API,例如擴展API和驗證所用的API,本文章這里記錄注冊核心API的過程)
InstallLegacyAPI方法里面先調用NewLegacyRESTStorage方法來新建核心api所需用到的Storage,比如nodeStorage,podStorage(rest.Storage結構是用於對接etcd存儲的,每個Storage都有操作ETCD的增刪改查方法,比如PodStorage,NodeStorage就是操作對應pod和node在ETCD里面數據的結構,利用它們來實現對ETCD里面數據的操作)。
--》kubernetes
這里只截取了node和pod的storage創建代碼
所有核心API所需用到的Storage新建好之后都添加到restStorageMap 里面去,此map相當於一個配置文件,里面列出了所有api路徑和storage的對應關系,當然這里的path路徑並不是完整的路徑,后面還需加上 /api/v1 這樣的前綴才能構成完整的api請求路徑。
restStorageMap := 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, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage.Controller, "replicationControllers/status": controllerStorage.Status, "services": serviceRest.Service, "services/proxy": serviceRest.Proxy, "services/status": serviceStatusStorage, "endpoints": endpointsStorage, "nodes": nodeStorage.Node, "nodes/status": nodeStorage.Status, "nodes/proxy": nodeStorage.Proxy, "events": eventStorage, "limitRanges": limitRangeStorage, "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "configMaps": configMapStorage, "componentStatuses": componentstatus.NewStorage(componentStatusStorage{c.StorageFactory}.serversToValidate),
}
后面將此map放入到apiGroupInfo結構里面去並返回apiGroupInfo
--》kubernetes
InstallLegacyAPI方法得到NewLegacyRESTStorage方法返回的apiGroupInfo后調用InstallLegacyAPIGroup方法
--》kubernetes
InstallLegacyAPIGroup方法先調用installAPIResources方法去注冊所有前面拿到的storage
installAPIResources方法里面主要處理邏輯就是下面這段,apiGroupVersion結構里面包含了所有的storage
InstallREST方法注冊所有的REST處理器handler(包括storage, watch, proxy和redirect)到restful Container
restful.Container代表一個http rest服務對象(restful.Container來自於一個第三方庫github.com/emicklei/go-restful),包括一組restful.WebService(每個webserver處理一個對應路徑下的所有請求。比如/api/v1/),restful.WebService由多個restful.Route組成,處理這些路徑下所有的特殊的MIME類型等,restful.Route為路徑(處理函數映射map)
第一段代碼生成url前綴字符串,比如/api/vi/。然后新建一個APIInstaller結構並調用它的install方法
--》kubernetes
install方法里面首先新建一個webService結構
然后將所有前面集合里面的api路徑path放到一個數組里面並將數組排序,接着循環遍歷path數組將path路徑與對應的storage注冊到handler里面,注冊好之后放到前面新建的webService里
registerResourceHandlers這個方法比較大,首先里面會調用拿到的storage(比如傳入的是podStorage)的動作方法,這些方法可以判斷此storage是否支持此動詞,比如
getter, isGetter := storage.(rest.Getter)
若此storage支持get方法則得到getter結構,其他例如create,update,delete這些動作若支持也會得到相應結構體。
然后新建一個action數組並往此數組里面添加所有的action,這些action即GET,PUT和DELETE這些REST請求對應的actionn
然后遍歷數組actions,在循環每種動作action(例如get)的邏輯里面先創建一個此action對應的處理器handler,然后通過webService和此handler創建一個route結構,此route結構即為當前path對應到此action的一個路由
循環遍歷actions數組之后將所有route添加到當前路徑對應的webService中
--》kubernetes
然后回到InstallREST方法中將此webService添加到RestfulContainer中
--》kubernetes
前面的邏輯處理好之后回到InstallLegacyAPIGroup方法,之前調用installAPIResources安裝了對應url前綴下的所有rest storage(例如 /api 路徑下的所有rest storage),后面接着往RestfulContainer添加另一個控制版本的webService,這個webService枚舉了所有支持的api版本(例如 /api/v1, /api/v1bete1),至此API的注冊過程全部結束,后面apiServer接收到一個rest請求就會根據RestfulContainer里面的handler來進行處理。