Schema 注册表
Kubernetes 系统拥有众多资源,每一种资源就是一个资源类型,这些资源类型需要有统一的注册、存储、查询、管理等机制--Scheme资源注册表,其是一个内存型的资源注册表,拥有如下特点。
支持注册多种资源类型,包括内部版本和外部版本;
支持多种版本转换机制;
支持不同资源的序列化/反序列化机制。
1、资源类型
Scheme 资源注册表支持两种资源类型的注册,分别是 UnversionedType 和 KnownType 资源类型。
GVK(资源组、资源版本、资源种类)在 Scheme 资源注册表中以 <group>/<version>,Kind=<kind> 的形式存在,其中对于 Kind 字段,在注册时如果不指定该字段的名称,那么默认通过反射获取类型的名称。
1.1 UnversionedType
无版本资源类型,它主要应用于某些没有版本的资源类型,该类型的资源对象并不需要进行转换。在目前的 Kubernetes 发行版本中,几乎所有的资源对象都拥有版本,但在 metav1 元数据中还有部分类型,它们既属于 meta.k8s.io/v1 又属于 UnversionedType 无版本资源类型,例如 Status、APIVersions、APIGroupList 等。
该类型资源对象通过 scheme.AddUnversionedTypes 方法进行注册。
1.2 KnownType
是目前 Kubernetes 最常用的资源类型,也可称其为“拥有版本的资源类型”。
该类型资源对象通过 scheme.AddKnownTypes 方法进行注册。
2、注册表数据结构
type Scheme struct {
gvkToType map[schema.GroupVersionKind]reflect.Type
typeToGVK map[reflect.Type][]schema.GroupVersionKind
unversionedTypes map[reflect.Type]schema.GroupVersionKind
unversionedKinds map[string]reflect.Type
fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc
defaulterFuncs map[reflect.Type]func(interface{})
converter *conversion.Converter
versionPriority map[string][]string
observedVersions []schema.GroupVersion
schemeName string
}如上代码所示,Scheme 资源注册表数据结构有4个 map 结构:
gvkToType:存储 GVK 与 Type 的映射关系;
typeToGVK:存储 Type 与 GVK 的映射关系,一个 Type 会对应一个或多个 GVK;
unversionedTypes:存储 UnversionedType 与 GVK 的映射关系;
unversionedKinds:存储 Kind 名称与 UnversionedType 的映射关系。
2.1 注册方法
在 Scheme 资源注册表中,不同的资源类型使用的注册方法不同:
scheme.AddUnversionedTypes:注册 UnversionedType 资源类型;
func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Object) { s.addObservedVersion(version) s.AddKnownTypes(version, types...) for _, obj := range types { t := reflect.TypeOf(obj).Elem() gvk := version.WithKind(t.Name()) s.unversionedTypes[t] = gvk if old, ok := s.unversionedKinds[gvk.Kind]; ok && t != old { panic(fmt.Sprintf("%v.%v has already been registered as unversioned kind %q - kind name must be unique in scheme %q", old.PkgPath(), old.Name(), gvk, s.schemeName)) } s.unversionedKinds[gvk.Kind] = t } }scheme.AddKnownTypes:注册 KnownType 资源类型;
func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) { s.addObservedVersion(gv) for _, obj := range types { t := reflect.TypeOf(obj) if t.Kind() != reflect.Pointer { panic("All types must be pointers to structs.") } t = t.Elem() s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj) } }scheme.AddKnownTypeWithName:注册 KnownType 资源类型,须指定资源的 Kind 资源种类名称。
func (s *Scheme) AddKnownTypeWithName(gvk schema.GroupVersionKind, obj Object) { s.addObservedVersion(gvk.GroupVersion()) t := reflect.TypeOf(obj) if len(gvk.Version) == 0 { panic(fmt.Sprintf("version is required on all types: %s %v", gvk, t)) } if t.Kind() != reflect.Pointer { panic("All types must be pointers to structs.") } t = t.Elem() if t.Kind() != reflect.Struct { panic("All types must be pointers to structs.") } if oldT, found := s.gvkToType[gvk]; found && oldT != t { panic(fmt.Sprintf("Double registration of different types for %v: old=%v.%v, new=%v.%v in scheme %q", gvk, oldT.PkgPath(), oldT.Name(), t.PkgPath(), t.Name(), s.schemeName)) } s.gvkToType[gvk] = t for _, existingGvk := range s.typeToGVK[t] { if existingGvk == gvk { return } } s.typeToGVK[t] = append(s.typeToGVK[t], gvk) // if the type implements DeepCopyInto(<obj>), register a self-conversion if m := reflect.ValueOf(obj).MethodByName("DeepCopyInto"); m.IsValid() && m.Type().NumIn() == 1 && m.Type().NumOut() == 0 && m.Type().In(0) == reflect.TypeOf(obj) { if err := s.AddGeneratedConversionFunc(obj, obj, func(a, b interface{}, scope conversion.Scope) error { // copy a to b reflect.ValueOf(a).MethodByName("DeepCopyInto").Call([]reflect.Value{reflect.ValueOf(b)}) // clear TypeMeta to match legacy reflective conversion b.(Object).GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{}) return nil }); err != nil { panic(err) } } }
2.2 查询方法
在运行过程中,kube-apiserver 组件常对 Scheme 资源注册表进行查询:
scheme.KnownTypes:查询注册表中指定GV下的资源类型
func (s *Scheme) KnownTypes(gv schema.GroupVersion) map[string]reflect.Type { types := make(map[string]reflect.Type) for gvk, t := range s.gvkToType { if gv != gvk.GroupVersion() { continue } types[gvk.Kind] = t } return types }scheme.AllKnownTypes:查询注册表中所有 GVK 下的资源类型
func (s *Scheme) AllKnownTypes() map[schema.GroupVersionKind]reflect.Type { return s.gvkToType }scheme.ObjectKinds:查询资源对象所对应的 GVK,一个资源对象可能存在多个 GVK
func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error) { // Unstructured objects are always considered to have their declared GVK if _, ok := obj.(Unstructured); ok { // we require that the GVK be populated in order to recognize the object gvk := obj.GetObjectKind().GroupVersionKind() if len(gvk.Kind) == 0 { return nil, false, NewMissingKindErr("unstructured object has no kind") } if len(gvk.Version) == 0 { return nil, false, NewMissingVersionErr("unstructured object has no version") } return []schema.GroupVersionKind{gvk}, false, nil } v, err := conversion.EnforcePtr(obj) if err != nil { return nil, false, err } t := v.Type() gvks, ok := s.typeToGVK[t] if !ok { return nil, false, NewNotRegisteredErrForType(s.schemeName, t) } _, unversionedType := s.unversionedTypes[t] return gvks, unversionedType, nil }scheme.New:查询 GVK 所对应的资源对象
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.IsGroupRegistered:判断指定的资源组是否已经注册
func (s *Scheme) IsGroupRegistered(group string) bool { for _, observedVersion := range s.observedVersions { if observedVersion.Group == group { return true } } return false }scheme.IsVersionRegistered:判断指定的 GV 是否已经注册
func (s *Scheme) IsVersionRegistered(version schema.GroupVersion) bool { for _, observedVersion := range s.observedVersions { if observedVersion == version { return true } } return false }scheme.Recognizes:判断指定的 GVK 是否已经注册
func (s *Scheme) Recognizes(gvk schema.GroupVersionKind) bool { _, exists := s.gvkToType[gvk] return exists }scheme.IsUnversioned:判断指定的资源对象是否属于 UnversionedType 类型
func (s *Scheme) IsUnversioned(obj Object) (bool, bool) { v, err := conversion.EnforcePtr(obj) if err != nil { return false, false } t := v.Type() if _, ok := s.typeToGVK[t]; !ok { return false, false } _, ok := s.unversionedTypes[t] return ok, true }
- 感谢你赐予我前进的力量