Kubernetes 源碼分析 -- API Server之編解碼

--------------------- 
做者:weixin_34037977 
來源:CSDN 
原文:https://blog.csdn.net/weixin_34037977/article/details/87058105 node

 

在Kubernetes源碼分析-- API Server之API Install篇中,咱們瞭解到K8S能夠支持多版本的API,可是Rest API的不一樣版本中接口的輸入輸出參數的格式是有差異的,Kubernetes是怎麼處理這個問題的呢?另外Kubernetes支持yaml、json兩個格式的配置,同時又可以支持json、yaml和pb等格式的編解碼進行協議傳輸,那麼Kubernetes又是如何實現各類數據對象的序列化、反序列化的呢?json

 

runtime.Schemeapi

爲了同時解決數據對象的序列化、反序列化與多版本數據對象的兼容和轉換問題,Kubernetes設計了一套複雜的機制,首先,它設計了runtime.Scheme這個結構體(k8s.io/apimachinery/pkg/runtime/schema.go),如下是對它的定義。promise

 

// 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定義瞭如下內容:app

    序列化和反序列化API對象的方法框架

    類型登記處:用於在不一樣版本的Go shemas之間轉換group 、version和kind信息ide

 

  從上述代碼中能夠看到,函數

  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方法,實現資源對象的深度拷貝能力。

 

 

  後面的省略。。。

相關文章
相關標籤/搜索