设为首页 收藏本站
查看: 1275|回复: 0

[经验分享] kubernetes之kube-ApiServer代码分析

[复制链接]

尚未签到

发表于 2018-1-4 12:34:42 | 显示全部楼层 |阅读模式
一、概述:
  kube-ApiServer相当于是k8集群的一个入口,不论通过kubectl还是使用remote api 直接控制,都要经过apiserver。apiserver说白了就是一个server负责监听指定的端口(http/https协议),之后处理不同的请求,只不过加上的很多控制;apiserver是k8s系统中所有对象的增删查改盯的http/restful式服务端,其中盯是指watch操作【watch是apiserver中的重要操作之一】。数据最终存储在分布式一致的etcd存储内,apiserver本身是无状态的,提供了这些数据访问的认证鉴权、缓存、api版本适配转换等一系列的功能。

二、restful基础
  对于http服务和使用go语言实现方式,可以看go-restful的文档和例子

  k8s存放在etcd内的存储对象是api.Pod对象(无版本),从不同版本的请求路径标示来操作,例如api/v1,最后获取到的是不同版本,例如v1.Pod的json文本。这里就经历了几个过程,包括:
  1、http client访问/api/v1/pod/xyz, 想要获取到这个Pod的数据
  2、从etcd获取到api.Pod对象
  3、api.Pod对象转换为v1.Pod对象
  4、v1.Pod对象序列化为json或yaml文本
  5、文本通过http的response体,返回给http client
  其中用于处理业务数据的关键数据结构是APIGroupVersion:
  

// APIGroupVersion is a helper for exposing rest.Storage objects as http.Handlers via go-restful  

// It handles URLs of the form:  

// /${storage_key}[/${object_name}]  

// Where 'storage_key' points to a rest.Storage object stored in storage.  

// This object should contain all parameterization necessary for running a particular API version  

//重点数据结构  

type APIGroupVersion struct {  

//最重要的数据结构,该map的key是用于对,value是rest.Storage结构,用于对接etcd存储,  

//在初始化注册时,会把这个map化开,化为真正的rest服务到存储的一条龙服务  

Storage map[string]rest.Storage  

  
     Root string
  

  
     // GroupVersion is the external group version
  
     // 包含api/v1这样的string,用于标示这个实例
  
     GroupVersion unversioned.GroupVersion
  

  
     // RequestInfoResolver is used to parse URLs for the legacy proxy handler.  Don't use this for anything else
  
     // TODO: refactor proxy handler to use sub resources
  
     RequestInfoResolver *RequestInfoResolver
  

  
     // OptionsExternalVersion controls the Kubernetes APIVersion used for common objects in the apiserver
  
     // schema like api.Status, api.DeleteOptions, and api.ListOptions. Other implementors may
  
     // define a version "v1beta1" but want to use the Kubernetes "v1" internal objects. If
  
     // empty, defaults to GroupVersion.
  
     OptionsExternalVersion *unversioned.GroupVersion
  

  
     Mapper meta.RESTMapper
  

  
     // Serializer is used to determine how to convert responses from API methods into bytes to send over
  
     // the wire.
  
     //对象序列化和反序列化器
  
     Serializer     runtime.NegotiatedSerializer
  
     ParameterCodec runtime.ParameterCodec
  

  
     Typer   runtime.ObjectTyper
  
     Creater runtime.ObjectCreater
  
     //可以转换任意一种对象到另一种,只要你事先注入了相应的转换函数
  
     HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
  
     Convertor runtime.ObjectConvertor
  
     Copier    runtime.ObjectCopier
  
     Linker    runtime.SelfLinker
  

  
     Admit   admission.Interface
  
     Context api.RequestContextMapper
  

  
     MinRequestTimeout time.Duration
  

  
     // SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is
  
     // accessible from this API group version. The GroupVersionKind is that of the external version of
  
     // the subresource. The key of this map should be the path of the subresource. The keys here should
  
     // match the keys in the Storage map above for subresources.
  
     SubresourceGroupVersionKind map[string]unversioned.GroupVersionKind
  
}
  


三、API分组、多版本的初始化注册(Rest)

  k8s采用ApiGroup来管理所有的api分组和版本升级,目前的API分组包括:
  1、核心组,REST路径在/api/v1,但这个路径不是固定的,v1是当前的版本。与之相对应的代码里面的apiVersion字段的值为v1.
  2、扩展组,REST路径在/apis/extensions/$version, 相应的代码里面的apiversion:extensions/$VERSION(eg:apiVersion:extensions/v1beta1),这里的API对象可能会被重新分组;
  3、"componentconfig" 和 "metrics"这些组
  在这个文档里面讲述了实现ApiGroup的几个目标,包括api分组演化,对旧版API的向后兼容(Backwards compatibility),包括用户可以自定义自己的api等。接下来我们看看他么是怎么初始化注册的,这里都是缩减版代码,去掉了其他部分。


  • api注册入口:  

    kubernets/pkg/master/master.go  
    func New(c
    *Config)(*Master, error) {  m.InstallAPIs(c)
      
    }
      


  2.根据Config往APIGroupsInfo内增加组信息,然后通过InstallAPIGroups进行注册
  

func (m *Master) InstallAPIs(c *Config) {  

if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {  

glog.Fatalf("Error in registering group versions:%v", err)  

}  

}  

  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:
  

    GET /api/v1/namespaces/{namespace}/pods/{name}k8s使用的一个第三方库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关联起来。

4.etcd存储的操作(ORM)
  上面已经基本厘清了从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里面去。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-431489-1-1.html 上篇帖子: CentOS7安装Kubernetes 下篇帖子: kubernetes service分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表