• Kubernetes 源码分析 -- API Server之编解码


    --------------------- 
    作者:weixin_34037977 
    来源:CSDN 
    原文:https://blog.csdn.net/weixin_34037977/article/details/87058105 

    在Kubernetes源码分析-- API Server之API Install篇中,我们了解到K8S可以支持多版本的API,但是Rest API的不同版本中接口的输入输出参数的格式是有差别的,Kubernetes是怎么处理这个问题的呢?另外Kubernetes支持yaml、json两个格式的配置,同时又能够支持json、yaml和pb等格式的编解码进行协议传输,那么Kubernetes又是如何实现各种数据对象的序列化、反序列化的呢?

    runtime.Scheme

    为了同时解决数据对象的序列化、反序列化与多版本数据对象的兼容和转换问题,Kubernetes设计了一套复杂的机制,首先,它设计了runtime.Scheme这个结构体(k8s.io/apimachinery/pkg/runtime/schema.go),以下是对它的定义。

    // Scheme defines methods for serializing and deserializing API objects, a type
    // registry for converting group, version, and kind information to and from Go
    // schemas, and mappings between Go schemas of different versions. A scheme is the
    // foundation for a versioned API and versioned configuration over time.
    //
    // In a Scheme, a Type is a particular Go struct, a Version is a point-in-time
    // identifier for a particular representation of that Type (typically backwards
    // compatible), a Kind is the unique name for that Type within the Version, and a
    // Group identifies a set of Versions, Kinds, and Types that evolve over time. An
    // Unversioned Type is one that is not yet formally bound to a type and is promised
    // to be backwards compatible (effectively a "v1" of a Type that does not expect
    // to break in the future).
    //
    // Schemes are not expected to change at runtime and are only threadsafe after
    // registration is complete.
    type Scheme struct {
    	// versionMap allows one to figure out the go type of an object with
    	// the given version and name.
    	gvkToType map[schema.GroupVersionKind]reflect.Type
    
    	// typeToGroupVersion allows one to find metadata for a given go object.
    	// The reflect.Type we index by should *not* be a pointer.
    	typeToGVK map[reflect.Type][]schema.GroupVersionKind
    
    	// unversionedTypes are transformed without conversion in ConvertToVersion.
    	unversionedTypes map[reflect.Type]schema.GroupVersionKind
    
    	// unversionedKinds are the names of kinds that can be created in the context of any group
    	// or version
    	// TODO: resolve the status of unversioned types.
    	unversionedKinds map[string]reflect.Type
    
    	// Map from version and resource to the corresponding func to convert
    	// resource field labels in that version to internal version.
    	fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc
    
    	// defaulterFuncs is an array of interfaces to be called with an object to provide defaulting
    	// the provided object must be a pointer.
    	defaulterFuncs map[reflect.Type]func(interface{})
    
    	// converter stores all registered conversion functions. It also has
    	// default converting behavior.
    	converter *conversion.Converter
    
    	// versionPriority is a map of groups to ordered lists of versions for those groups indicating the
    	// default priorities of these versions as registered in the scheme
    	versionPriority map[string][]string
    
    	// observedVersions keeps track of the order we've seen versions during type registration
    	observedVersions []schema.GroupVersion
    
    	// schemeName is the name of this scheme.  If you don't specify a name, the stack of the NewScheme caller will be used.
    	// This is useful for error reporting to indicate the origin of the scheme.
    	schemeName string
    }
    

      

      runtime.Scheme是带版本的API与带版本的配置文件的基础。
      runtime.Scheme定义了以下内容:

        序列化和反序列化API对象的方法

        类型登记处:用于在不同版本的Go shemas之间转换group 、version和kind信息

      从上述代码中可以看到,

      typeToGVK与gkvToType 属性就是为了解决数据对象的序列化与反序列化问题,

      converter 属性则负责不同版本的数据对象转换问题;

      unversionedKind 用于映射哪些能够在任意group和version情况下的类型,key是一个string,也就是kind;

      fieldLabelConversionFuncs:用于解决数据对象的属性名称的兼容性转换和检验,比如讲需要兼容Pod的spec.Host属性改为spec.nodeName的情况。

      Kubernetes这个设计思路简单方便地建解决多版本的序列化和数据转换问题,下面是runtime.Scheme里序列化、反序列化的核心方法New()的代码:通过查找gkvToType里匹配的诸多类型,以反射方法生成一个空的数据对象:

    // New returns a new API object of the given version and name, or an error if it hasn't
    // been registered. The version and kind fields must be specified.
    func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error) {
    	if t, exists := s.gvkToType[kind]; exists {
    		return reflect.New(t).Interface().(Object), nil
    	}
    
    	if t, exists := s.unversionedKinds[kind.Kind]; exists {
    		return reflect.New(t).Interface().(Object), nil
    	}
    	return nil, NewNotRegisteredErrForKind(s.schemeName, kind)
    }
    

      

    由于这个方法的实现,也让Scheme实现了ObjectCreater接口。

    注意到runtime.Scheme只是实现了一个序列化与类型转换的框架API,提供了注册资源数据类型与转换函数的功能,那么具体的资源数据对象、转换函数又是在哪个包里实现的呢?答案是k8s.io/api/{resource}/{version}/register.go,而核心资源在k8s.io/api/core/v1/register.go中完成注册,以核心资源为例说明一下目录下的关键的代码

      types.go:k8s.io/api/core/v1/types.go
      定义了Rest API接口中设计的所有核心的数据类型
      register.go 负责将types.go里定义的数据类型注册到runtime.Scheme里。

      在register.go中,我们看到这里可以看到两个定义:

    var (
    	// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
    	// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
    	SchemeBuilder      = runtime.NewSchemeBuilder(addKnownTypes)
    	localSchemeBuilder = &SchemeBuilder
    	AddToScheme        = localSchemeBuilder.AddToScheme
    )

      但是只提供了注册的方法,其实还没有执行注册的过程。什么时候执行这个过程呢?


      在k8s.io/client-go/kubernetes/scheme/register.go中,有一个 init方法,在引用的时候就会被调用。

    func init() {
    	v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
    	utilruntime.Must(AddToScheme(Scheme))
    }
    

      

    该方法中的AddToScheme方法,会调用各个资源、版本的AddToScheme方法,从而把所有的核心数据资源都注册进了runtime.Scheme实例中了。

      generated.proto 基于genclient自动创建的clientsets Go Client,在types.go中,我们可以看到有些对象加了一行注释:“+genclient=true”,那么这些对象,就会被自动genclient工具自动创建出相应的client。

      zz_generated.deepcopy.go    自动创建的资源数据对象的DeepCopy方法,实现资源对象的深度拷贝能力。

      后面的省略。。。

    没有什么是写一万遍还不会的,如果有那就再写一万遍。
  • 相关阅读:
    HRBUST 1377 金明的预算方案
    51Nod 2649 完全背包
    计蒜客 T2129 采药
    计蒜客 T1408 矩形嵌套
    OpenJudge 2711 合唱队形
    51Nod 2080 最长上升子序列
    2021NUAA暑假集训 Day5 部分题解
    2021NUAA暑假集训 Day4 部分题解
    C++ 11 move constructor 何时调用?
    老外这样说英文
  • 原文地址:https://www.cnblogs.com/waken-captain/p/10560862.html
Copyright © 2020-2023  润新知