jinquan26 发表于 2018-1-4 19:16:56

Kubernetes API源码学习笔记

  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/cmd/kube-apiserver/apiserver.go
  apiserver.go里面的main方法调用server.go里面的run方法来启动指定的API Server
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026162227805-303152342.png
  --》kubernetes/kubernetes/cmd/kube-apiserver/app/server.go
  server.go里面的run方法如下:
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026162705867-1580468394.png
  可以看到先是调用CreateServerChain方法去创建一些server然后去启动这些server
  CreateServerChain方法里面主要创建了两个server,一个是kubeAPIServer,一个是apiExtensionsServer。kubeAPIServer是kubernetes独有的API Server,它负责的是kubernetes最主要的api,官方文档里面不建议在这个里面添加和修改api,如果我们有自己编写的api可以放在apiExtensionsServer里面,这个server是负责一些扩展的api。
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026164324680-134699804.png
  创建kubeAPIServer用到了CreateKubeAPIServer方法,此方法里面的创建server的关键代码如下:
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026164456976-797960915.png
  kubeAPIServerConfig是创建server所用到资源(resource)和配置,complete方法自动填充那些不能为空的字段值,new方法根据传入的config返回一个Server的实例。
  --》kubernetes/kubernetes/pkg/master/master.go
  new方法里面先根据配置创建一个名字为kube-apiserver的server
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026170715648-1804680581.png
  然后生成一个Master结构体,此结构体的API Server为刚刚创建的kube-apiserver
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026170737461-1660667264.png
  然后先注册核心api即LegacyAPI(此方法后面会注册其他的API,例如扩展API和验证所用的API,本文章这里记录注册核心API的过程)
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171026171342648-744572695.png
  InstallLegacyAPI方法里面先调用NewLegacyRESTStorage方法来新建核心api所需用到的Storage,比如nodeStorage,podStorage(rest.Storage结构是用于对接etcd存储的,每个Storage都有操作ETCD的增删改查方法,比如PodStorage,NodeStorage就是操作对应pod和node在ETCD里面数据的结构,利用它们来实现对ETCD里面数据的操作)。
  --》kubernetes/kubernetes/pkg/registry/core/rest/storage_core.go
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027100250101-441470213.png
  这里只截取了node和pod的storage创建代码
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027100313180-341030717.png
  所有核心API所需用到的Storage新建好之后都添加到restStorageMap 里面去,此map相当于一个配置文件,里面列出了所有api路径和storage的对应关系,当然这里的path路径并不是完整的路径,后面还需加上 /api/v1 这样的前缀才能构成完整的api请求路径。
  

restStorageMap := maprest.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
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027101214367-400391319.png
  --》kubernetes/kubernetes/pkg/master/master.go
  InstallLegacyAPI方法得到NewLegacyRESTStorage方法返回的apiGroupInfo后调用InstallLegacyAPIGroup方法
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027101445101-157036682.png
  --》kubernetes/kubernetes/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go
  InstallLegacyAPIGroup方法先调用installAPIResources方法去注册所有前面拿到的storage
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027103637758-683433110.png
  installAPIResources方法里面主要处理逻辑就是下面这段,apiGroupVersion结构里面包含了所有的storage
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027104358305-776975903.png
  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)
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027110528773-1155526243.png
  第一段代码生成url前缀字符串,比如/api/vi/。然后新建一个APIInstaller结构并调用它的install方法
  --》kubernetes/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go
  install方法里面首先新建一个webService结构
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027111557820-1426814488.png
  然后将所有前面集合里面的api路径path放到一个数组里面并将数组排序,接着循环遍历path数组将path路径与对应的storage注册到handler里面,注册好之后放到前面新建的webService里
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027112428351-1133572886.png
  registerResourceHandlers这个方法比较大,首先里面会调用拿到的storage(比如传入的是podStorage)的动作方法,这些方法可以判断此storage是否支持此动词,比如
  

getter, isGetter := storage.(rest.Getter)  

  若此storage支持get方法则得到getter结构,其他例如create,update,delete这些动作若支持也会得到相应结构体。
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027134845695-2121058440.png
  然后新建一个action数组并往此数组里面添加所有的action,这些action即GET,PUT和DELETE这些REST请求对应的actionn
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027135824273-1705679470.png
  然后遍历数组actions,在循环每种动作action(例如get)的逻辑里面先创建一个此action对应的处理器handler,然后通过webService和此handler创建一个route结构,此route结构即为当前path对应到此action的一个路由
https://images2017.cnblogs.com/blog/1141851/201710/1141851-20171027151937305-1278335797.png
  循环遍历actions数组之后将所有route添加到当前路径对应的webService中
  --》kubernetes/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/groupversion.go
  然后回到InstallREST方法中将此webService添加到RestfulContainer中
  --》kubernetes/kubernetes/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go
  前面的逻辑处理好之后回到InstallLegacyAPIGroup方法,之前调用installAPIResources安装了对应url前缀下的所有rest storage(例如 /api 路径下的所有rest storage),后面接着往RestfulContainer添加另一个控制版本的webService,这个webService枚举了所有支持的api版本(例如 /api/v1, /api/v1bete1),至此API的注册过程全部结束,后面apiServer接收到一个rest请求就会根据RestfulContainer里面的handler来进行处理。
页: [1]
查看完整版本: Kubernetes API源码学习笔记