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
--》kubernetes/kubernetes/cmd/kube-apiserver/app/server.go
server.go里面的run方法如下:
可以看到先是调用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/kubernetes/pkg/master/master.go
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/kubernetes/pkg/registry/core/rest/storage_core.go
这里只截取了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/kubernetes/pkg/master/master.go
InstallLegacyAPI方法得到NewLegacyRESTStorage方法返回的apiGroupInfo后调用InstallLegacyAPIGroup方法
--》kubernetes/kubernetes/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go
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/kubernetes/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go
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/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来进行处理。