当前位置: 首页 > article >正文

【k8s深入理解之 Scheme 补充-1】理解 Scheme 中资源的注册以及 GVK 和 go 结构体的映射

代码阅读引出的问题 —— 附录是详解

  • addKnownTypes、AddKnownTypeWithName、AddToGroupVersion 都是什么?

  • 了解资源注册流程

    • 下面代码是以 apps/v1 为例
    • addKnownTypes 注册多个资源,实际上是调用 AddKnownTypeWithName 进行单个资源注册
    • AddKnownTypeWithName 会利用反射,获取 go 结构体名称作为 Kind,建立 GVK 和 go 结构体的映射
    • addKnownTypes 一般还会包含 AddToGroupVersion,注册一些无版本资源(可以理解为辅助资源,如Status 等)以及相关的转换、默认值填充函数等
    • 下面的附录是详细介绍
// 路径-1 mod/k8s.io/api@v0.29.0/apps/v1/register.go

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}

// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
  // 注册多个资源类型,跳转 路径-2
	scheme.AddKnownTypes(SchemeGroupVersion,
		&Deployment{},
		&DeploymentList{},
		&StatefulSet{},
		&StatefulSetList{},
		&DaemonSet{},
		&DaemonSetList{},
		&ReplicaSet{},
		&ReplicaSetList{},
		&ControllerRevision{},
		&ControllerRevisionList{},
	)
  // 注册 GroupVersion,跳转 路径-3
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
	return nil
}

// 路径-2  mod/k8s.io/apimachinery@v0.29.0/pkg/runtime/scheme.go
// AddKnownTypes registers all types passed in 'types' as being members of version 'version'.
// All objects passed to types should be pointers to structs. The name that go reports for
// the struct becomes the "kind" field when encoding. Version may not be empty - use the
// APIVersionInternal constant if you have a type that does not have a formal version.
func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) {
	s.addObservedVersion(gv)
	for _, obj := range types {
    // 获取 obj 的类型,此处可能是指针类型 如 *Deployment
		t := reflect.TypeOf(obj)
		if t.Kind() != reflect.Pointer {
			panic("All types must be pointers to structs.")
		}
    // 获取指针指向的类型,如 Deployment 结构体
		t = t.Elem()
    // .Name 返回的是,结构体名称,也就是 Deployment —— 所以一般来说结构体名称就是 GVK 中的 Kind
		s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj)
	}
}


// 路径-3 mod/k8s.io/apimachinery@v0.29.0/pkg/apis/meta/v1/register.go
// 注册一些 无版本资源(可以理解为 稳定不易变化的版本,公共资源,其他 Group 都可以使用,主要用于辅助记录和查询作用 如 Status)
// 并注册一些,这些无版本资源或一些基础资源 的转换函数和默认值填充函数
// AddToGroupVersion registers common meta types into schemas.
func AddToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion) {
	scheme.AddKnownTypeWithName(groupVersion.WithKind(WatchEventKind), &WatchEvent{})
	scheme.AddKnownTypeWithName(
		schema.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal}.WithKind(WatchEventKind),
		&InternalEvent{},
	)
	// Supports legacy code paths, most callers should use metav1.ParameterCodec for now
	scheme.AddKnownTypes(groupVersion, optionsTypes...)
	// Register Unversioned types under their own special group
	scheme.AddUnversionedTypes(Unversioned,
		&Status{},
		&APIVersions{},
		&APIGroupList{},
		&APIGroup{},
		&APIResourceList{},
	)

	// register manually. This usually goes through the SchemeBuilder, which we cannot use here.
	utilruntime.Must(RegisterConversions(scheme))
	utilruntime.Must(RegisterDefaults(scheme))
}

附录1 | AddKnownTypes 和 AddKnownTypeWithName 和 AddToGroupVersion 有什么关系

在 Kubernetes 的代码中,AddKnownTypesAddKnownTypeWithNameAddToGroupVersion 是与 runtime.Scheme 相关的函数,主要用于注册自定义资源或类型,但它们关注的粒度和作用不同。


1. AddKnownTypes

  • 功能:批量注册某个 GroupVersion 下的资源类型到 runtime.Scheme
  • 内部实现:会将所有提供的类型注册到 GroupVersionKind (GVK) 中,其中 Kind 默认是类型的结构体名。
  • 调用场景:一般用于 API 类型的注册,比如注册 CRD 的 Go 类型。
  • 特点
    • 简化了多个类型的注册。
    • 默认使用结构体名作为类型的 Kind
  • 底层关联AddKnownTypes 内部会调用 AddKnownTypeWithName 来完成注册。

2. AddKnownTypeWithName

  • 功能:注册单个 runtime.Object 类型到特定的 GroupVersionKind
  • 特点
    • 允许为类型指定自定义的 Kind 名称。
    • 是更底层的实现,提供更精细的控制。
  • 调用场景:需要为单个类型注册自定义的 Kind 时。
  • 内部关联AddKnownTypes 只是对多个 AddKnownTypeWithName 调用的封装。

3. AddToGroupVersion

  • 功能:为一个 GroupVersion 添加元信息(GroupVersion 本身的注册),并且是类型注册的入口点。

  • 典型实现

    func AddToGroupVersion(scheme *runtime.Scheme, gv schema.GroupVersion) error {
        return scheme.AddGeneratedDeepCopyFuncs(
            deepCopyFuncs...
        )
    }
    
  • 作用

    • 用于声明某个 GroupVersion
    • 通常用于为 API 组注册基础信息(比如默认版本和元数据支持)。
  • 调用场景

    • 用于 API 组的初始配置,确保该 GroupVersion 被声明并可以被进一步扩展(如通过 AddKnownTypes 注册资源类型)。

三者之间的关系

函数名粒度主要功能调用链关系
AddToGroupVersionGroupVersion 级别注册 GroupVersion 的元信息,为资源类型的注册提供入口点。一般最先调用(但也不是必须在第一位),用于初始化 GroupVersion
AddKnownTypes批量类型级别注册某个 GroupVersion 下的多个类型资源到 runtime.Scheme,简化注册流程。内部调用 AddKnownTypeWithName
AddKnownTypeWithName单个类型级别注册单个类型资源到 runtime.Scheme,允许为资源指定自定义的 Kind 名称。最底层的注册实现

示例:三者配合

假设你有一个自定义 API 组 example.com/v1,其中包含一种资源 MyCustomResource

  1. 使用 AddToGroupVersion

    • 声明

      example.com/v1
      

      的元信息:

      func AddToScheme(scheme *runtime.Scheme) error {
          gv := schema.GroupVersion{Group: "example.com", Version: "v1"}
          return AddToGroupVersion(scheme, gv)
      }
      
  2. 使用 AddKnownTypes

    • 注册所有相关资源类型:

      func AddToScheme(scheme *runtime.Scheme) error {
          gv := schema.GroupVersion{Group: "example.com", Version: "v1"}
          scheme.AddKnownTypes(gv, &MyCustomResource{}, &MyCustomResourceList{})
          return nil
      }
      
  3. 使用 AddKnownTypeWithName

    • 在需要时为资源指定自定义 Kind名称:

      func AddToScheme(scheme *runtime.Scheme) error {
          gv := schema.GroupVersion{Group: "example.com", Version: "v1"}
          scheme.AddKnownTypeWithName(gv.WithKind("SpecialResource"), &MyCustomResource{})
          return nil
      }
      

总结

  • AddToGroupVersion 是对 API GroupVersion 的初始化,通常是注册流程的起点。
  • AddKnownTypes 是高层次的封装,用于批量注册资源类型。
  • AddKnownTypeWithName 是低层次的实现,用于更精细地注册单个资源类型,特别是需要自定义 Kind 的场景。

附录2 | reflect.TypeOf(obj).Elem()获取指针指向的go类型

  • reflect.TypeOf(obj).Elem().Name() 获取的是 obj 指向的实际类型的名称。具体来说,它返回的是 指针所指向的类型的名称

    解释:

    • reflect.TypeOf(obj) 获取的是 obj 的反射类型,如果 obj 是指针类型,reflect.TypeOf(obj) 返回的是指针类型。
    • .Elem() 用来获取指针所指向的元素类型,即返回指针所指向的实际类型。
    • .Name() 返回该类型的名称。

    举个例子:

    假设你有以下代码:

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type MyStruct struct {
    	Name string
    }
    
    func main() {
    	obj := &MyStruct{Name: "K8s"}
    
    	// 获取 obj 的反射类型,即 *MyStruct 类型
    	ptrType := reflect.TypeOf(obj)
    	
    	// 获取 obj 指针所指向的元素类型,即 MyStruct 类型
    	elemType := ptrType.Elem()
    	
    	// 获取元素类型的名称
    	fmt.Println("elemType.Name():", elemType.Name()) // 输出 MyStruct
    }
    

    输出:

    elemType.Name(): MyStruct
    

    解释:

    • reflect.TypeOf(obj) 获取的是 *MyStruct 类型。
    • Elem() 获取的是 MyStruct 类型(即 *MyStruct 指向的类型)。
    • Name() 获取的是 MyStruct 的类型名称,因此输出 MyStruct

    总结:

    reflect.TypeOf(obj).Elem().Name() 获取的是指针类型所指向的元素类型的名称,通常用于获取结构体类型的名称。


http://www.kler.cn/a/414405.html

相关文章:

  • 讨论JAVA、JVM与Spring
  • 1、Three.js开端准备环境
  • idea2024加载flowable6.8.1.36遇到的问题-idea启动flowable问题flowable源码启动问题
  • 新版布谷直播软件源码开发搭建功能更新明细
  • coqui-ai TTS 初步使用
  • UE5 实现组合键触发事件的方法
  • 同时在github和gitee配置密钥
  • 力扣第 71 题 简化路径
  • 电脑模拟器端口号及相关的操作命令
  • 云计算基础-期末复习
  • 【Linux】文件管理
  • 华为Mate 70系列,行走在AI山脊
  • P1390 公约数的和
  • (73)脉冲幅度调制PAM调制解调通信系统的MATLAB仿真
  • 力扣hot100-->前缀和/前缀书/LRU缓存
  • 文本的预处理(pytorch)
  • Ubuntu环境中RocketMQ安装教程
  • ROS VSCode调试方法
  • Linux 命令详解之 tail 命令
  • 【计算机视觉】图像基本操作
  • C++和C中的volatile 关键字
  • Apache Doris 现行版本 Docker-Compose 运行教程
  • 实现uniapp开发安卓应用使用AIDL与原生安卓通信
  • 《C++ 与神经网络:自动微分在反向传播中的高效实现之道》
  • jenkins 2.346.1最后一个支持java8的版本搭建
  • git的简单使用与gdb