在以前的文章中分析过kubernetes是如何进行多版本管理中提到了一个关键的设计解码器, 负责将请求对象反序列化成一个具体的数据模型,今天一块儿来了解下其内部是如何实现多版本管理、转换的设计要点
在一般的web开发中更多的时候,你们都是断代向前兼容更新,大多数状况下当版本更新以后会独立演进,若是要在多版本之间转换一般则会出现以下的状况
若是咱们要为每一个版本都去适配其余全部的版本,则复杂度会指数级上升,而在kubernetes中则经过一个内部版本的设计来进行解决,内部版本是一个稳定的版本,全部的版本都只针对目标版原本进行转换的实现,而不关注其余版本
那若是谋个版本须要独立的演进,或者增设一些新的字段,修改字段名称等破坏性更新的时候,则就须要一种转换机制,负责在当前版本和内部版本之间来进行字段或者数据的转换
转换其实核心目标是完成从目标对象的字段中获取数据,而后通过一系列操做最终为目标对象的对应的字段进行赋值操做,要完成该操做,则就须要借助反射来实现,经过枚举字段,来获取对应的转换函数,执行转换函数,完成目标赋值
为了实现上面的方案,kubernetes中设计了以下组件:Scheme(负责各个版本的注册和管理)、Convert(转换实现)、Serializer(实现对应版本的反序列化),让咱们依次看下其关键设计
Convert实现从一个目标对象到另一个目标对象的转换, 为了实现这种转换,kubernetes里面主要是借助反射和不一样版本的转换函数来共同完成
1.首先咱们经过目标函数来获取对应的属性字段,而后针对该字段进行计算赋值操做2.若是发现对应的字段须要来转换,则会调用对应的转换函数来进行赋值操做,若是不须要转换则会直接经过反射来进行赋值
在构建rest接口的时候,每一个rest接口都会持有一个生成当前版本对象的构造函数,当请求进入以后,会首先经过目标版本获取对应的decoderdecoder会利用当前的GroupVersionKind来进行第一步解析,首先将字节数组解析成当前版本,而后在解析成目标对象以后,又会根据目标版本进行转换
Scheme负责各个资源版本的统一注册和管理,为其余组件提供根据GVK来获取对应的资源对象,也提供经过资源对象获取版本等操做,内部还持有convert对象,包装了源对象到目标对象的转换操做
Scheme对象是一个复合的数据结构,其实现了多种结果,诸如typer、defaulter、creater等,不少地方都是经过直接传递scheme来进行对应的参数的填充, 其内部关键数据结构以下
GVK与资源类型的映射,以及当前资源类型支持哪些GVK
gvkToType map[schema.GroupVersionKind]reflect.Type
typeToGVK map[reflect.Type][]schema.GroupVersionKind
则建立对象的时候能够直接经过New来实例化对应的对象
func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) { if t, exists := s.gvkToType[kind]; exists { return reflect.New(t).Interface().(Object), nil } }
defaulterFuncs map[reflect.Type]func(interface{})
func (s *Scheme) Default(src Object) { if fn, ok := s.defaulterFuncs[reflect.TypeOf(src)]; ok { fn(src) }}
func (s *Scheme) AddConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error { return s.converter.RegisterUntypedConversionFunc(a, b, fn)}
实现上无疑是复杂的做为一个工业设计有不少须要care的边缘状况,剖丝抽茧每一个人看到的都不同,这可能就是源码阅读的乐趣,从上面能够看到核心其实就三个点:
-
-
-
最后经过convert来处理不一样版本之间的差别,最后统一操做内部版本
好了今天就到这了,但愿对你们有所帮助css
kubernetes学习笔记地址: https://www.yuque.com/baxiaoshi/tyado3web
文章来源:图解源码 / 原文连接swift
本文分享自微信公众号 - K8S中文社区(k8schina)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。微信