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

--》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来进行处理。

 

posted @ 2017-10-27 15:59  Zard_李  阅读(2174)  评论(0编辑  收藏  举报