【k8s深入学习之 Scheme】全面理解 Scheme 的注册机制、内外部版本、自动转换函数、默认填充函数、Options等机制

参考

  • 【k8s基础篇】k8s scheme3 之序列化_基于schema进行序列化-CSDN博客
  • 【k8s基础篇】k8s scheme4 之资源数据结构与资源注册_kubernetes 的scheam-CSDN博客

Scheme的字段总览

在这里插入图片描述

type Scheme struct {// gvkToType 允许通过给定的版本和名称来推断对象的 Go 类型。// map 键是 GroupVersionKind (GVK),值是 Go 类型(reflect.Type)。gvkToType map[schema.GroupVersionKind]reflect.Type// typeToGVK 允许通过 Go 类型查找对应的 GroupVersionKind(GVK)。// map 键是 Go 类型(reflect.Type),值是一个包含多个 GVK 的切片。// 注意,这里存储的是 Go 类型而非指针。typeToGVK map[reflect.Type][]schema.GroupVersionKind// unversionedTypes 用于转换时不做版本转换的类型。// 这些类型会在调用 ConvertToVersion 时直接使用原始的类型,不进行版本转换。unversionedTypes map[reflect.Type]schema.GroupVersionKind// unversionedKinds 是可以在任何组或版本下创建的 Kind 的名称。// 这些 Kind 没有特定的版本。// TODO: 需要进一步解决无版本类型的状态。unversionedKinds map[string]reflect.Type// fieldLabelConversionFuncs 是一个映射,记录了每个 GroupVersionKind 对应的字段标签转换函数。// 这些函数用于将资源字段标签从某个版本转换为内部版本的标签。fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc// defaulterFuncs 是一个映射,记录了每种 Go 类型对应的默认值设置函数。// 这些函数会在对象创建时为该对象提供默认值,函数接受指向对象的指针。defaulterFuncs map[reflect.Type]func(interface{})// converter 存储所有已注册的转换函数,也包含默认的转换行为。// 它负责处理版本间的转换和数据的默认转换。converter *conversion.Converter// versionPriority 是一个映射,记录了每个组内版本的优先级顺序。// 该顺序决定了在 Scheme 中注册的版本的默认优先级。versionPriority map[string][]string// observedVersions 记录了已注册版本的顺序。// 这个顺序用于帮助追踪各个版本的注册次序。observedVersions []schema.GroupVersion// schemeName 是 Scheme 的名称。如果没有指定名称,默认为调用 NewScheme 的栈信息。// 这个名称用于错误报告,以指示 Scheme 来源。schemeName string
}

gvkToType:根据 GroupVersionKind(GVK)来查找对应的 Go 类型,用于将资源的元数据(如版本和组)转换为 Go 类型。

typeToGVK:将 Go 类型映射到多个 GroupVersionKind(GVK)。这允许从 Go 类型反向查找其所属的版本和组。

unversionedTypes:记录那些没有版本号的资源类型。在转换过程中,这些类型不会进行版本转换,通常用于特殊的资源类型。

unversionedKinds:记录可在任何组或版本中创建的 Kind,这些类型不依赖于版本。

fieldLabelConversionFuncs:为特定版本的资源提供字段标签转换的函数,用于支持版本间的字段转换。

defaulterFuncs:记录类型对应的默认值函数,当资源创建时,这些函数会为资源对象提供默认值。

converter:管理资源版本之间的转换,执行实际的数据转换工作。

versionPriority:按优先级顺序记录每个组内的版本,用于确定默认版本。优先级高的版本会排在前面。

observedVersions:记录已注册版本的顺序,帮助确定资源类型的处理顺序。

schemeName:为 Scheme 指定名称,帮助错误诊断和日志记录。

Q1 | 为什么需要 Scheme

为什么需要 Scheme?

1-序列化与反序列化

  1. 控制器与 API Server 的交互是通过标准的 RESTful API 完成的(如创建 Deployment,或 获取 Deployment),是将信息序列化为 protobuf 或 json 形式,然后包装为 body,通过 https 形式与 apiserver 进行交互(可以理解 apiserver 为普通的 https 服务端)—— 因此如何进行反序列化和序列化转换呢?

    • 同理反序列化,就是客户端对 response body 内容的处理或服务端对 requests body 内容的处理,将 body 的 protobuf 或 json 转换为 go Struct,然后便于进行下一步业务逻辑处理
  2. 以反序列化举例 —— 获取 Deployment —— 通过向 Rest URL 发起请求获得 Deploy —— Rest URL 就是 GVR

    • 在这里插入图片描述
  3. 通过 Rest URL 转换很容易获得 GVK —— 但是 GVK 对应的存储数据结构(也就是 go Struct) 在哪呢?—— 如何进行反序列化

    • 答 —— 通过 Scheme 中记录 gvkToType 便可以查找到 GVK 对应的 go Struct —— 根据 go Struct 后面的 protobuf 或 json tag 便可以反序列化 —— 将 https 响应 body 中的内容转为 Deployment 的 go Struct,便于下一步处理

    • go Struct 后面的 protobuf 或 json tag —— 见下面的 Deployment 代码示例

  4. 所以可以理解 Scheme 的部分参数

    • gvkToType:根据 GroupVersionKind(GVK)来查找对应的 Go 类型,用于将资源的元数据(如版本和组)转换为 Go 类型。
    • typeToGVK:将 Go 类型映射到多个 GroupVersionKind(GVK)。这允许从 Go 类型反向查找其所属的版本和组。
// 路径 /Users/dufengyang/go/pkg/mod/k8s.io/api@v0.29.0/apps/v1/types.go// Deployment enables declarative updates for Pods and ReplicaSets.
type Deployment struct {metav1.TypeMeta `json:",inline"`// Standard object's metadata.// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata// +optionalmetav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`// Specification of the desired behavior of the Deployment.// +optionalSpec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`// Most recently observed status of the Deployment.// +optionalStatus DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}// DeploymentSpec is the specification of the desired behavior of the Deployment.
type DeploymentSpec struct {// Number of desired pods. This is a pointer to distinguish between explicit// zero and not specified. Defaults to 1.// +optionalReplicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"`// Label selector for pods. Existing ReplicaSets whose pods are// selected by this will be the ones affected by this deployment.// It must match the pod template's labels.Selector *metav1.LabelSelector `json:"selector" protobuf:"bytes,2,opt,name=selector"`// Template describes the pods that will be created.// The only allowed template.spec.restartPolicy value is "Always".Template v1.PodTemplateSpec `json:"template" protobuf:"bytes,3,opt,name=template"`// The deployment strategy to use to replace existing pods with new ones.// +optional// +patchStrategy=retainKeysStrategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" protobuf:"bytes,4,opt,name=strategy"`// Minimum number of seconds for which a newly created pod should be ready// without any of its container crashing, for it to be considered available.// Defaults to 0 (pod will be considered available as soon as it is ready)// +optionalMinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,5,opt,name=minReadySeconds"`// The number of old ReplicaSets to retain to allow rollback.// This is a pointer to distinguish between explicit zero and not specified.// Defaults to 10.// +optionalRevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty" protobuf:"varint,6,opt,name=revisionHistoryLimit"`// Indicates that the deployment is paused.// +optionalPaused bool `json:"paused,omitempty" protobuf:"varint,7,opt,name=paused"`// The maximum time in seconds for a deployment to make progress before it// is considered to be failed. The deployment controller will continue to// process failed deployments and a condition with a ProgressDeadlineExceeded// reason will be surfaced in the deployment status. Note that progress will// not be estimated during the time a deployment is paused. Defaults to 600s.ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty" protobuf:"varint,9,opt,name=progressDeadlineSeconds"`
}

2-版本转换

  1. Deployment 也是不断迭代的,目前有 v1、v1betea1、v1beta2,每个版本的 go Struct 都会有变动(如新增字段)

  2. 同时为了便于转换和存储,存在一个 internal 版本,作为一个存储态或中间态(因为 版本两两建立映射关系(如 v1 对 v1beta1、v1对 v1betaN、v1beta1 对 v1betaN等),明显比都与 internal 映射复杂(v1–internal – v1beta1(v1betaN)))

  3. 所以采用 Scheme 中的 converter 参数

    • **converter**管理资源版本之间的转换,执行实际的数据转换工作

3-版本优先级

  • 以 Deployment 为例,目前有三个对外版本,一个内部版本

    • 三个对外版本,k8s.io/api/apps 目录下的 v1、v1beta1、v1beta2 目录的 register.go 记录了各个组版本,types.go 分别记录了每个版本的结构定义
      • var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
      • var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
      • var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta2"}
    • 一个内部版本,k8s.io/kubernetes/pkg/apis/apps/register.go 记录了内部版本 __internal,同目录的 register.go 记录了组版本,也有 types.go 文件记录 __internal 版本资源的数据结构
      • var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
      • k8s.io/kubernetes/pkg/apis/apps 也有 v1、v1beta1、v1beta2 目录,和对应的 register.go 文件,但是没有各个外部版本的 types.go 文件
    • 版本间的优先级 k8s.io/kubernetes/pkg/apis/apps/install/install.go
      • utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion))
      • 表示该 Group 中的 Kind 或 Resource ,优先使用 v1 版本,接下来才是 v1beta2,最后是 v1beta1
  • 以 Deployment 为例,优先级配置代码所在位置

    • // 代码路径 k8s.io/kubernetes/pkg/apis/apps/install/install.gofunc init() {Install(legacyscheme.Scheme)
      }// Install registers the API group and adds types to a scheme
      func Install(scheme *runtime.Scheme) {// internal 内部版本utilruntime.Must(apps.AddToScheme(scheme))// v1beta1 版本utilruntime.Must(v1beta1.AddToScheme(scheme))// v1beta2 版本utilruntime.Must(v1beta2.AddToScheme(scheme))// v1 版本utilruntime.Must(v1.AddToScheme(scheme))// 优先级 v1 v1beta2 v1beta1utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion))
      }
      
  • 所以可以理解 Scheme 中的参数

    • versionPriority:按优先级顺序记录每个组内的版本,用于确定默认版本。优先级高的版本会排在前面。
      • 作用:可以知道先使用哪个版本的资源,如 Scheme 中注册了 Deploy 的 v1、v1beta2、v1beta1 版本,那么会优先使用 v1 版本(指的就是优先使用此版本 Deployment 的 go Struct 数据结构,进行业务逻辑处理和序列化、反序列化等)
    • observedVersions:记录已注册版本的顺序,帮助确定资源类型的处理顺序。
      • 作用:可以通过顺序,了解版本更新的顺序,如 v1beta1、v1beta2、 v1,知道先开发完成的是 v1beta1,最后完成的是 v1

4-Scheme其他参数

  • unversionedTypes:记录那些没有版本号的资源类型。在转换过程中,这些类型不会进行版本转换,通常用于特殊的资源类型。

    • 记录 go Struct 和 gvk 的映射关系,类似 typeToGVK
    • 不同点在于,unversionedTypes 记录无版本资源, typeToGVK 记录有版本资源
    • 无版本资源 —— 可以理解为稳定,没有版本更新,类似 Status,对应的版本为(Group为空,v1,也就是核心组v1版本)
      • 另外注意,Metadata、Object一般称之为“无版本资源”,但其实并不是【独立 API 资源类型】,就是真正的没有版本,其作为【结构体字段】存在各个资源结构体中,因此也称之为【元数据】
      • 【元数据-无版本资源】一般都存储在 k8s.io/apimachinery 项目中,因此可以说此项目是【地基】
      • 【独立资源-无版本资源】一般存储在k8s.io/kubernetes项目中,一般在k8s.io/kubernetes/pkg/apis 目录中,该目录中也包含有版本资源
    • 有版本资源 —— 类似 Deployment,有版本更新,apps 组有 v1beta1、v1beta2、v1 等版本
    • 下面 AddToGroupVersion 有详细介绍
  • unversionedKinds:记录可在任何组或版本中创建的 Kind,这些类型不依赖于版本。

    • 记录 gvk 和 go Struct 的映射关系
    • 下面 AddToGroupVersion 有详细介绍
  • fieldLabelConversionFuncs:为特定版本的资源提供字段标签转换的函数,用于支持版本间的字段转换。

    • 此字段为 map 结构,存储对某些字段的转换函数
    • 如 status.phase 字段存储个对应的函数,便可以通过 fieldLabelConversionFuncs["status.phase "] 调用该字段对应的转换函数,进行下一步处理
  • defaulterFuncs:记录类型对应的默认值函数,当资源创建时,这些函数会为资源对象提供默认值。

    • 就是为一些资源类型填写默认值

    • gvk 和 默认填充函数的对应,可以理解为每个资源版本的 go struct 有对应的默认值填充函数

    • defaulterFuncs map[reflect.Type]func(interface{})
      
    • 下面 AddToGroupVersion 有详细介绍

  • schemeName:为 Scheme 指定名称,帮助错误诊断和日志记录。

无版本资源的典型例子

无版本资源常常用于以下类型的对象:

  1. Status
    • Status 是用于表示 API 请求的执行结果或状态的对象,它通常不会随版本变化而变化。它用于在处理某些操作(如资源创建、删除)时提供反馈和错误信息。
    • Status 通常是无版本的,因为它并不是一种具有长期持久性的资源,而是一个临时的反馈对象。
  2. APIGroupAPIGroupList
    • 这些对象表示 Kubernetes 中的 API 组及其版本信息,通常用于在 API 服务器启动时向客户端报告哪些 API 组和版本是可用的。
    • 这些对象与 Kubernetes 的版本控制无关,因此也可以被视为无版本资源。
  3. APIResourceList
    • APIResourceList 是一种用于描述 API 资源列表的对象,通常用于支持 Kubernetes 资源的发现。
    • 这种类型也没有特定的版本,因为它只是列出当前可用的资源,而与具体版本无关。
无版本资源的应用场景
  • API 资源的发现:当用户或客户端查询 Kubernetes API 服务器时,可能会通过无版本资源(如 APIGroupList)查询集群中的所有支持的 API 组和版本。
  • 状态返回:像 Status 这样的资源用于返回操作的状态,例如在资源创建、删除或更新时返回的成功或错误消息。
  • 兼容性支持:一些资源可能没有版本化机制,因为它们是为了确保系统的兼容性和稳定性,或者它们只是用于基础性操作,不需要随 Kubernetes 的版本变化而变化。

Q2 | 为什么 types.go 文件内部版本和外部版本存在不同路径

2.1-资源数据结构存储路径

通过上面的介绍你也会注意到

  • 资源的外部版本的数据结构,也就是 types.go 文件,放置在 k8s.io/api 项目中
  • 资源的内部版本的数据结构,也就是 types.go 文件,放置在 k8s.io/kubernetes 项目 中
# 没有 vendor 目录,可以随便找个 资源进行跳转
# 若有,可以在 vendor 目录观察到,没有此目录,可以尝试用 go mod vendor 
# 下面以 apps Group 为例,资源数据结构定义所在路径,如下# 外部 v1 版本
mod/k8s.io/api@v0.29.0/apps/v1/types.go
# 外部 v1beta1 版本
mod/k8s.io/api@v0.29.0/apps/v1beta1/types.go
# 外部 v1beta2 版本
mod/k8s.io/api@v0.29.0/apps/v1beta2/types.go# 内部 internal 版本,注意内部版本 没有 json 或 protobuf tag
mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/types.go
# 版本优先级注册
mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/install/install.go# 版本优先级顺序
func init() {Install(legacyscheme.Scheme)
}// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {utilruntime.Must(apps.AddToScheme(scheme))utilruntime.Must(v1beta1.AddToScheme(scheme))utilruntime.Must(v1beta2.AddToScheme(scheme))utilruntime.Must(v1.AddToScheme(scheme))utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion))
}

2.2-资源存储路径不同带来的优势

Kubernetes 的 API 类型和实现是严格分离的,这种设计有以下好处:

  • 简单理解
  • internal 版本主要供 k8s 项目使用,k8s.io/kubernetes 项目主要用于设计和实现 k8s controller 和 apiserver 等主要控制组件,因此采用密切使用的数据结构放在一起,也就是internal版本
  • 外部版本不仅可以 k8s 项目使用,还可以被其他项目引用使用,所以外部版本独立放在k8s.io/api 项目中,且没有将 Internal 版本放在该项目里面
特性Internal 类型外部版本
用途Kubernetes 内部使用,支撑核心逻辑面向用户和客户端,用于操作资源
修改自由度可自由修改,不需要向后兼容必须遵循向后兼容性规则
版本管理无版本概念,保持内部逻辑一致即可需要严格区分版本,遵循语义版本(v1, v1beta1)
依赖结构位于 k8s.io/kubernetes,与核心代码强绑定位于 k8s.io/api,与核心实现解耦

2.3-资源不同版本的转换

  • 上面讲解了,资源的各版本转换(v1beata1、v1beta2、v1)都是通过(internal)进行中转
  • 而相应的转换函数,是通过 conversion-gen 自动生成,然后注册到 Scheme 中
  • 那么考虑,现在 v2 基于 v1 版本进行演化,新增了几个字段,那么 internal 内部版本需要进行变化吗?
    1. 假设 internal 版本字段不变,那么 v2 版本转为别的版本,internal 会自动忽略新增字段;
      • 同样,别的版本通过 internal 转为 v2,v2的新增字段也为空;但这种情况可以通过 Scheme 中的 defaulterFuncs 避免,其可以在转换时为新增字段配置默认值
    2. 若想将 v2 新增字段同步到其他外部版本,那么需要再 internal 版本和其他版本都新增此字段,然后再利用 conversion-gen 生成自动转换函数
    3. 若只在 internal 版本新增字段,其他外部版本都不具有此字段,那么此字段属于内部字段,不对外暴露,不影响其他外部版本

Q3 | k8s 三个重要的库都是什么?

  • 其实前面已经大致讲解了,就是 k8s.io/apimachineryk8s.io/apik8s.io/kubernetes
    • 可以简单理解为
    • k8s.io/apimachinery —— 地基,包含 TypeMeta 和 ObjectMeta 等元数据字段,每个资源和CRD定义都需要引用
    • k8s.io/api —— 资源的 API 定义,主要包含各个 Group、Version、Kind,包含资源各个外部版本的数据结构定义
    • k8s.io/kubernetes —— k8s 的核心,包含 apiserver 和各类控制器;以及资源的 internal 内部版本(用于存储、版本转换等);还定义外部版本的优先级顺序
特性k8s.io/apik8s.io/apimachineryk8s.io/kubernetes
核心功能定义 Kubernetes API 对象类型(就是 GVK 的定义)提供元信息、工具和通用组件(理解为 metada、ObjectMeta、TypeMeta 之类)实现 Kubernetes 的核心功能(理解为控制器、apiserver之类)
模块类型轻量级 API 类型模块底层工具模块核心实现模块
适用场景客户端使用,用于定义和解析资源提供对象元信息和类型转换工具Kubernetes 集群运行和核心功能
依赖关系依赖 k8s.io/apimachinery独立存在依赖 k8s.io/apik8s.io/apimachinery
使用场景客户端工具或控制器开发类型注册、元信息操作、深拷贝工具Kubernetes 核心开发

Q4 | Scheme 如何使用

  • 以 apps Group 为例

4.1- k8s.io/api 中 v1 版本的 register.go 文件

  • 可以理解为,基础的资源数据结构、元数据结构、基础结构转换函数、默认值函数等注册到 Scheme
// 路径 mod/k8s.io/api@v0.29.0/apps/v1/register.go
package v1import (metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/runtime/schema"
)// GroupName is the group name use in this package
const GroupName = "apps"// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()
}var (// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.// 可以把 SchemeBuilder 当做一个 list 队列,元素类型为函数,因此就是一个 存储函数的列表SchemeBuilder      = runtime.NewSchemeBuilder(addKnownTypes)localSchemeBuilder = &SchemeBuilder// 调用此函数,就相当于调用 localSchemeBuilder 中注册的所有函数AddToScheme        = localSchemeBuilder.AddToScheme
)// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {// 相当于,更新传入参数 scheme 中的 gvkToType 和 typeToGVK// 并且记录 GroupVersion 到 scheme 中的 observedVersionsscheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},&StatefulSet{},&StatefulSetList{},&DaemonSet{},&DaemonSetList{},&ReplicaSet{},&ReplicaSetList{},&ControllerRevision{},&ControllerRevisionList{},)// 这个比较复杂// 1. 注册了无版本资源,更新 scheme 的 unversionedTypes 和 unversionedKinds 和 observedVersions// 2. 注册一些基础的转换函数,更新 scheme 的 converter// 3. 注册一些基础的默认值填充函数,更新 scheme 中的 defaulterFuncs// 注意此函数,internal 版本没有,因为 internal 没有版本的概念,下面会详细讲解metav1.AddToGroupVersion(scheme, SchemeGroupVersion)return nil
}

4.2-k8s.io/kubernetes 中 v1 版本的 register.go 文件

  • 可以理解为,将扩展的默认值函数、版本转换函数等注册到 Scheme
  • 没有注册资源的数据结构到 Scheme
// 路径 mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/v1/register.go
package v1import (appsv1 "k8s.io/api/apps/v1""k8s.io/apimachinery/pkg/runtime/schema"
)// GroupName is the group name use in this package
const GroupName = "apps"// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()
}var (localSchemeBuilder = &appsv1.SchemeBuilderAddToScheme        = localSchemeBuilder.AddToScheme
)// 相比于上面,多了默认值填充函数,更新到 scheme 中的 defaulterFuncs
// 但是转换函数在哪里呀?
func init() {// We only register manually written functions here. The registration of the// generated functions takes place in the generated files. The separation// makes the code compile even when the generated files are missing.// 跳转-1localSchemeBuilder.Register(addDefaultingFuncs)
}// 跳转-2
func addDefaultingFuncs(scheme *runtime.Scheme) error {return RegisterDefaults(scheme)
}
// 跳转-3
func RegisterDefaults(scheme *runtime.Scheme) error {scheme.AddTypeDefaultingFunc(&v1.DaemonSet{}, func(obj interface{}) { SetObjectDefaults_DaemonSet(obj.(*v1.DaemonSet)) })scheme.AddTypeDefaultingFunc(&v1.DaemonSetList{}, func(obj interface{}) { SetObjectDefaults_DaemonSetList(obj.(*v1.DaemonSetList)) })scheme.AddTypeDefaultingFunc(&v1.Deployment{}, func(obj interface{}) { SetObjectDefaults_Deployment(obj.(*v1.Deployment)) })scheme.AddTypeDefaultingFunc(&v1.DeploymentList{}, func(obj interface{}) { SetObjectDefaults_DeploymentList(obj.(*v1.DeploymentList)) })scheme.AddTypeDefaultingFunc(&v1.ReplicaSet{}, func(obj interface{}) { SetObjectDefaults_ReplicaSet(obj.(*v1.ReplicaSet)) })scheme.AddTypeDefaultingFunc(&v1.ReplicaSetList{}, func(obj interface{}) { SetObjectDefaults_ReplicaSetList(obj.(*v1.ReplicaSetList)) })scheme.AddTypeDefaultingFunc(&v1.StatefulSet{}, func(obj interface{}) { SetObjectDefaults_StatefulSet(obj.(*v1.StatefulSet)) })scheme.AddTypeDefaultingFunc(&v1.StatefulSetList{}, func(obj interface{}) { SetObjectDefaults_StatefulSetList(obj.(*v1.StatefulSetList)) })return nil
}
  • 转换函数的位置,同层级下,也就是同包中的zz_generated.conversion.go,其通过 init 函数,注册到localSchemeBuilder 变量中
  • 调用 AddToScheme 方法时,会自动调用localSchemeBuilder 变量中的所有函数,完成了转换函数注册到 Scheme 的 converter 变量中
// 路径 mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/v1/zz_generated.conversion.gofunc init() {localSchemeBuilder.Register(RegisterConversions)
}// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
// 此函数,就是 apps Group 的 v1 版本和 internal 版本的所有转换函数
func RegisterConversions(s *runtime.Scheme) error {if err := s.AddGeneratedConversionFunc((*v1.ControllerRevision)(nil), (*apps.ControllerRevision)(nil), func(a, b interface{}, scope conversion.Scope) error {return Convert_v1_ControllerRevision_To_apps_ControllerRevision(a.(*v1.ControllerRevision), b.(*apps.ControllerRevision), scope)}); err != nil {return err}if err := s.AddGeneratedConversionFunc((*apps.ControllerRevision)(nil), (*v1.ControllerRevision)(nil), func(a, b interface{}, scope conversion.Scope) error {return Convert_apps_ControllerRevision_To_v1_ControllerRevision(a.(*apps.ControllerRevision), b.(*v1.ControllerRevision), scope)}); err != nil {return err}// 太多函数了,此处简单截取
}

4.3-k8s.io/kubernetes 中 internal 版本的 register.go 文件

  • 可以看出,和k8s.io/io中的 v1 版本注册逻辑基本一致,但是多了几个资源字段,为什么呢?
    • 因为 internal 是所有版本的中转者,因此包含所有版本必须的信息,所以信息会更为丰富
// 路径 mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/register.go
package appsimport ("k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/runtime/schema""k8s.io/kubernetes/pkg/apis/autoscaling"
)var (// SchemeBuilder stores functions to add things to a scheme.SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)// AddToScheme applies all stored functions t oa scheme.AddToScheme = SchemeBuilder.AddToScheme
)// GroupName is the group name use in this package
const GroupName = "apps"// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {return SchemeGroupVersion.WithKind(kind).GroupKind()
}// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()
}// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {// TODO this will get cleaned up with the scheme types are fixedscheme.AddKnownTypes(SchemeGroupVersion,&DaemonSet{},&DaemonSetList{},&Deployment{},&DeploymentList{},// 相比于 v1 新增&DeploymentRollback{},// 相比于 v1 新增&autoscaling.Scale{},&StatefulSet{},&StatefulSetList{},&ControllerRevision{},&ControllerRevisionList{},&ReplicaSet{},&ReplicaSetList{},)return nil
}

4.4-编写控制器时,该采用哪个 AddToScheme

  • 首先应该清楚为什么 Controller 会使用 Scheme 吧?
    • 因为 Controller 需要对资源进行处理,那如何知道资源GVK和数据结构的关系呢(就是如何监测到 yaml 后形成的 CR 资源对象,并将其解码为正确的数据结构呢?)之后再进行下一步处理
    • 答 —— Scheme,通过 Group 暴露的 AddToScheme 中,Scheme 便记录了 GVK 和 go struct 数据结构的转换关系(以及多版本转换等)
      • 如控制器需要监控 Deployments 资源,那么就需要调用 apps 组的 AddToScheme,将 Deployment 和 go Struct 的映射关系注册到 Scheme 中,之后控制器通过该 Scheme 便能进行后续的所有操作
      • (可以理解为当前 Scheme 就是个 apps 组的字典,想要啥就从中找啥)
      • 当然也可以将别的 Group 注册到 Scheme 中,相当于扩大了 Scheme 的查找范围
项目版本用途使用场景
k8s.io/apiV1v1 版本的基础资源数据结构适用于指定v1版本编写控制器
k8s.io/kubernetesV1默认值填充函数,v1和internal的转换函数不适用于单独编写控制器
k8s.io/kubernetesinternal所有版本的中转者,记录的资源数据结构相比于单一版本更丰富适用于核心组件控制器,可以适配多版本
  • 使用 k8s.io/api(推荐)
// 开发一个管理 Deployment 的控制器,直接与 Kubernetes API Server 交互:
import (appsv1 "k8s.io/api/apps/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/client-go/kubernetes/scheme"
)func main() {// 初始化 SchemelocalScheme := runtime.NewScheme()appsv1.AddToScheme(localScheme)// 与 API Server 交互// 例如:监听 Deployment 资源的变化
}
  • 使用 kubernetes/pkg/apis(仅在核心组件开发中)
// 扩展 Kubernetes 核心控制器管理器,自定义默认值或内部优化:
import (appsinternal "k8s.io/kubernetes/pkg/apis/apps""k8s.io/apimachinery/pkg/runtime"
)func main() {// 注册内部版本资源scheme := runtime.NewScheme()appsinternal.AddToScheme(scheme)// 使用内部版本操作internalDeployment := &appsinternal.Deployment{}// 操作 internalDeployment 逻辑
}

4.5-为什么 internal 版本不需要调用metav1.AddToGroupVersion

在 Kubernetes 中,internalapi/v1 资源的注册逻辑有所不同,其中 internalregister.go 通常不调用 metav1.AddToGroupVersion,而 api/v1 版本中会调用。这种差异主要来源于两者的用途和设计目标。以下是详细解释:


1. metav1.AddToGroupVersion 的作用
  • 定义
    metav1.AddToGroupVersion 是一个辅助函数,用于在 Scheme 中注册与 API 版本相关的元信息(ObjectMetaTypeMeta)。

  • 注册的内容

    • 该函数主要将 ObjectMetaTypeMeta 等元数据类型与指定的 GroupVersion 绑定。
    • 用于标识资源所属的 API 组和版本。
  • 典型调用: 在 api/v1 版本中,通常在 addKnownTypes 函数内调用:

    func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},)metav1.AddToGroupVersion(scheme, SchemeGroupVersion) // 注册元信息return nil
    }
    

2. 为什么 internal 版本不需要调用?
2.1 internal 版本没有特定的 GroupVersion
  • internal 类型是未版本化的资源类型,不绑定具体的 API 版本(GroupVersion)。
  • 因此,metav1.AddToGroupVersion 中的 GroupVersion 绑定逻辑对 internal 类型无意义。
2.2 internal 类型不会直接与 API Server 交互
  • internal 类型是 Kubernetes 内部使用的中间表示,仅在内存中操作。
  • 它们不会直接通过 API Server 进行序列化或反序列化,因此无需注册与 metav1 相关的元信息。
2.3 元信息已经通过其他方式处理
  • internal 类型资源的元信息(如 ObjectMetaTypeMeta)会自动继承其父资源的结构。
  • 在需要时,internal 类型可以通过版本转换逻辑(conversion)与外部版本(如 api/v1)关联。

3. 为什么 api/v1 需要调用?
3.1 明确绑定资源到 GroupVersion
  • api/v1 是版本化的外部资源类型,必须绑定到特定的 GroupVersion(如 apps/v1)。
  • metav1.AddToGroupVersion会将元信息类型(如 ObjectMeta)与 GroupVersion 关联,用于:
    • 标识资源所属的 API 组和版本。
    • 确保序列化和反序列化时能够正确处理这些元信息。
3.2 用于与 API Server 的交互
  • api/v1 类型通过 RESTful API 与 API Server 交互。
  • 在资源序列化为 JSON 或反序列化为 Go 结构体时,TypeMeta 中的 KindAPIVersion 字段依赖于 GroupVersion 的绑定。
3.3 支持客户端和工具
  • 许多 Kubernetes 客户端工具(如 kubectl)依赖于 metav1 中的元信息来识别资源的版本和组。
  • metav1.AddToGroupVersion 的注册为这些工具提供了必要的元数据支持。

4. 示例对比
internal 版本的 register.go
func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},)return nil // 不需要调用 metav1.AddToGroupVersion
}
api/v1 版本的 register.go
func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},)metav1.AddToGroupVersion(scheme, SchemeGroupVersion) // 绑定 metav1 信息return nil
}

5. 总结
特性internal 版本api/v1 版本
是否有具体的 GroupVersion无,需要通过转换逻辑映射到外部版本有,明确绑定到 GroupVersion
是否直接与 API Server 交互否,内部使用是,资源会通过 RESTful API 交互
是否需要元信息注册否,metav1.AddToGroupVersion 无意义是,需要注册以支持元信息处理
用途Kubernetes 内部类型的中间表示(性能优化)对外的版本化资源,支持客户端和 API Server

因此,internal 版本的 register.go 没有调用 metav1.AddToGroupVersion 是合理的,因为 internal 类型不需要绑定 GroupVersion,也不需要元信息的版本化支持。

Q6 | AddToGroupVersion 会更新 Scheme 哪些字段

// 路径 k8s.io/apimachinery/pkg/apis/meta/v1/register.go// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}// Unversioned is group version for unversioned API objects
// TODO: this should be v1 probably
var Unversioned = schema.GroupVersion{Group: "", Version: "v1"}// WatchEventKind is name reserved for serializing watch events.
const WatchEventKind = "WatchEvent"// 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 nowscheme.AddKnownTypes(groupVersion, optionsTypes...)// Register Unversioned types under their own special groupscheme.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))
}// 路径 k8s.io/apimachinery/pkg/runtime/scheme.go
func (s *Scheme) AddUnversionedTypes(version schema.GroupVersion, types ...Object) {s.addObservedVersion(version)s.AddKnownTypes(version, types...)for _, obj := range types {// 获取对应的 go structt := reflect.TypeOf(obj).Elem()// 获取 gvk,t.Name 是go struct 的名称gvk := version.WithKind(t.Name())s.unversionedTypes[t] = gvkif 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}
}func (s *Scheme) addObservedVersion(version schema.GroupVersion) {if len(version.Version) == 0 || version.Version == APIVersionInternal {return}for _, observedVersion := range s.observedVersions {if observedVersion == version {return}}s.observedVersions = append(s.observedVersions, version)
}

AddToGroupVersion 函数中,以下操作会将内容注册到 Scheme 的相应字段中:


1. gvkToTypetypeToGVK

相关代码
scheme.AddKnownTypeWithName(groupVersion.WithKind(WatchEventKind), &WatchEvent{})
scheme.AddKnownTypeWithName(schema.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal}.WithKind(WatchEventKind),&InternalEvent{},
)
scheme.AddKnownTypes(groupVersion, optionsTypes...)
注册内容
  • gvkToType

    • 注册 GroupVersionKind 到对应 Go 类型的映射。

    • 示例:

      GVK: meta.k8s.io/v1, Kind=WatchEvent -> Type: *WatchEvent
      GVK: meta.k8s.io/internal, Kind=WatchEvent -> Type: *InternalEvent
      
  • typeToGVK

    • 注册 Go 类型到对应 GroupVersionKind 的映射。

    • 示例:

      Type: *WatchEvent -> GVK: [meta.k8s.io/v1, Kind=WatchEvent]
      Type: *InternalEvent -> GVK: [meta.k8s.io/internal, Kind=WatchEvent]
      

2. unversionedTypes

相关代码
scheme.AddUnversionedTypes(Unversioned,&Status{},&APIVersions{},&APIGroupList{},&APIGroup{},&APIResourceList{},
)
注册内容
  • 无版本类型

    • 记录不进行版本转换的资源类型。

    • 示例:

      Type: *Status -> GVK: v1, Kind=Status
      Type: *APIVersions -> GVK: v1, Kind=APIVersions
      Type: *APIGroupList -> GVK: v1, Kind=APIGroupList
      

3. unversionedKinds

相关代码
scheme.AddUnversionedTypes(Unversioned,&Status{},&APIVersions{},&APIGroupList{},&APIGroup{},&APIResourceList{},
)
注册内容
  • 无版本 Kind

    • 注册不依赖特定版本的资源 Kind

    • 示例:

      Kind: Status -> Type: *Status
      Kind: APIVersions -> Type: *APIVersions
      Kind: APIGroupList -> Type: *APIGroupList
      

4. converter

相关代码
utilruntime.Must(RegisterConversions(scheme))
注册内容
  • 转换函数

    • GroupVersionKind 的转换函数注册到 converter

    • 用于支持内部版本与外部版本的字段映射和数据转换。

    • 示例:

      Conversion: meta.k8s.io/v1/WatchEvent <-> meta.k8s.io/internal/WatchEvent
      

5. defaulterFuncs

相关代码
utilruntime.Must(RegisterDefaults(scheme))
注册内容
  • 默认值函数

    • 为资源注册默认值设置逻辑。
    • 示例:
      • 如果 WatchEvent 类型未设置某字段,注册的默认值函数会填充该字段。

总结

字段注册内容
gvkToTypeGroupVersionKind 映射到对应的 Go 类型。
typeToGVK将 Go 类型映射到可能的多个 GroupVersionKind
unversionedTypes注册无版本资源类型(如 StatusAPIGroupList 等)。
unversionedKinds注册无版本资源的 Kind(如 Status)。
converter注册转换函数,用于不同版本之间的字段映射。
defaulterFuncs注册默认值设置函数,用于初始化未设置的字段值。

这些注册确保了 API 类型的序列化、反序列化、跨版本转换和默认值填充功能的正常运行。

Q7 | AddToGroupVersion 中注册 optionsTypes 的作用

// 上面AddToGroupVersion函数中存在这一条代码
// 简单来说,就是让 Scheme 知道该资源可以支持的一些操作
scheme.AddKnownTypes(groupVersion, optionsTypes...)

这段代码是 Kubernetes 中的 Scheme 注册过程的一部分,它将多种资源操作相关的 Options 类型注册到 Scheme 中。具体来说,它将与资源操作(如列出、获取、删除、创建、更新、部分更新)相关的选项类型添加到指定的 API 组和版本的 Scheme 中,以便 Kubernetes API 服务器能够在处理请求时识别和序列化这些类型。

代码解释

var optionsTypes = []runtime.Object{&ListOptions{},&GetOptions{},&DeleteOptions{},&CreateOptions{},&UpdateOptions{},&PatchOptions{},
}
  1. optionsTypes 切片
    • 这行代码定义了一个 optionsTypes 切片,包含了多个 Kubernetes 资源操作相关的结构体类型(例如:ListOptionsGetOptions 等)。
    • 每个类型都是 Kubernetes API 请求中的参数类型,用于描述特定的操作选项。
    • 这些结构体通常包含一些控制资源操作的字段,如分页、筛选、排序等。
  2. runtime.Object
    • runtime.Object 是 Kubernetes 中的一个接口,表示所有 API 对象的通用类型。所有在 Kubernetes 中定义的 API 对象(包括这些 Options 类型)都必须实现这个接口。
    • 将这些类型定义为 runtime.Object 是为了让它们能够被 Kubernetes 的 API 系统正确地识别、序列化、反序列化。
scheme.AddKnownTypes(groupVersion, optionsTypes...)
  1. AddKnownTypes 方法:
    • 这个方法将类型注册到 Scheme 中。Scheme 是一个 Kubernetes 中用于管理 API 类型和版本的对象,它帮助 Kubernetes 确定如何处理不同版本的 API 类型。
    • groupVersion 是一个表示 API 组和版本的对象(如 apps/v1core/v1)。
    • optionsTypes... 使用切片展开语法,意味着将 optionsTypes 切片中的所有类型逐一传递给 AddKnownTypes 方法进行注册。
    • 这行代码的作用是将 ListOptionsGetOptionsDeleteOptionsCreateOptionsUpdateOptionsPatchOptions 这些类型注册到 Scheme 中,使它们能够在指定的 groupVersion 下使用。

用途和示例

1. ListOptions

ListOptions 用于列出资源时的选项,通常包括分页、排序、字段选择等。例如,获取所有 Pods 时可以使用 ListOptions 来指定要获取的字段或分页信息。

示例:

listOptions := &ListOptions{Limit:  10,          // 获取前10个 PodContinue: "abc123",  // 分页标识符,获取分页后的 PodFieldSelector: "status.phase=Running",  // 过滤条件,获取所有运行中的 Pod
}
2. GetOptions

GetOptions 用于获取资源时的附加选项。例如,获取某个 Pod 时,GetOptions 可以包含一些条件,如字段选择或某些特定的请求参数。

示例:

getOptions := &GetOptions{ResourceVersion: "12345",  // 指定获取某个特定版本的资源
}
3. DeleteOptions

DeleteOptions 用于删除资源时的选项。例如,删除 Pod 时,DeleteOptions 可以包括是否强制删除、是否删除挂载的 PVC 等选项。

示例:

deleteOptions := &DeleteOptions{GracePeriodSeconds: 30,   // 设置删除时的宽限期为30秒Preconditions: metav1.NewUIDPreconditions("12345678-1234-1234-1234-1234567890ab"), // 设置条件
}
4. CreateOptions

CreateOptions 用于创建资源时的附加选项。它通常包含创建时的策略,例如是否允许自定义字段或使用默认值。

示例:

createOptions := &CreateOptions{DryRun: []string{"All"}, // 创建时进行干运行,即模拟创建但不实际执行
}
5. UpdateOptions

UpdateOptions 用于更新资源时的选项,例如更新时的策略、版本控制等。

示例:

updateOptions := &UpdateOptions{FieldManager: "kubectl",  // 使用的字段管理器
}
6. PatchOptions

PatchOptions 用于部分更新资源时的选项。它通常用于表示通过补丁操作更新资源时所使用的选项。

示例:

patchOptions := &PatchOptions{DryRun: []string{"All"},  // 补丁时进行干运行
}

为什么要将这些类型注册到 Scheme

  • 序列化与反序列化AddKnownTypes 方法将这些类型注册到 Scheme 中,使得 Kubernetes 在处理 API 请求时能够正确地序列化(转换成 JSON 或 Protobuf)和反序列化(从 JSON 或 Protobuf 转回对象)这些类型。
  • 版本管理:这些类型会与特定的 API 版本关联,在 Kubernetes 不同版本之间进行转换时,Scheme 会帮助正确地处理它们。
  • 请求处理:在实际 API 请求处理中(如列出、创建、删除资源),Kubernetes 会根据客户端的请求和参数使用相应的 Options 类型来解析请求并执行相应的操作。

总结

这段代码的作用是将多种与资源操作相关的选项类型(如 ListOptionsGetOptions 等)注册到 Scheme 中,以便 Kubernetes API 服务器在处理这些操作时能够识别和正确序列化/反序列化这些类型。这样可以确保 API 请求中的参数能够在不同版本的 API 之间正确处理,并且在资源操作(如列出、获取、创建、删除)时提供灵活的选项。

Q8 | AddToGroupVersion 中注册 optionsTypes 的作用(补充说明)

重点:

  1. optionsTypes 的注册,如ListOptionsGetOptionsPatchOptions等,是控制 API 操作行为( List 获取,Get 获取、Patch更新),其是类似 Restful API 的方法,表示一种动作
  2. Options 中可以包含一些简单的控制逻辑(如分页、获取的数量相纸 limit、简单的元数据过滤 ResourceVersion 等)
  3. 其实对获取资源行为的控制,而不是对资源内容的控制

AddToGroupVersion 中的 scheme.AddKnownTypes(groupVersion, optionsTypes...) 的作用是将指定的类型注册到 Scheme 中,使其能够被识别并用于序列化和反序列化。这些类型主要是 API 操作选项类型,如 ListOptionsGetOptions 等,它们不是用来直接操作资源(如 Deploymentspec 部分)的,而是用来控制 API 操作行为。以下是详细说明:


1. 是否只能对元数据或无版本资源操作?

不完全是,但这些类型主要与以下内容有关:

  1. 元数据相关操作
    • 例如通过 ListOptions 使用 labelSelectorfieldSelector 筛选资源,与元数据字段相关。
    • 例如 DeleteOptions 定义删除行为的相关参数。
  2. 无版本资源
    • 这些选项类型是 Kubernetes 中的通用资源,适用于所有 API 组和版本。
  3. 不直接操作资源内容
    • 例如 Deploymentspec 部分,它是具体资源的定义和配置,与这些选项类型无直接关联。
    • 它们不会直接改变资源的状态或配置。

2. 为什么这些类型无法直接操作 spec

2.1 类型的职责
  • 这些类型是 操作选项类型,仅用于控制 Kubernetes API 行为,例如筛选、分页、删除策略等。
  • 它们不会参与具体资源的业务逻辑(如 Deployment 的创建、更新、状态变化等)。
2.2 不属于资源本身
  • 例如,

    Deployment
    

    spec
    

    是资源内容的一部分,描述了资源的具体配置:

    spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80
    

    这些内容是

    Deployment
    

    定义的一部分,而不是通过

    ListOptions
    

    GetOptions
    

    等选项类型直接修改的。

2.3 操作资源的 API 路径不同
  • 操作 spec 通常通过特定的 API 路径,例如:
    • GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} 获取 Deployment
    • PATCH /apis/apps/v1/namespaces/{namespace}/deployments/{name} 更新 spec
  • ListOptions 等是通用的 API 行为控制类型,它们的用途是控制列表操作(如过滤或分页),并不直接接触 spec 内容。

3. 这些类型的具体用途

3.1 用于通用 API 操作行为
  • 它们通过选项参数控制操作行为,例如筛选、分页、删除传播策略等。
  • 示例:
    • ListOptions:控制资源列表的行为。
    • DeleteOptions:控制资源删除的行为。
3.2 适用于所有资源类型
  • 这些选项类型是通用的,不限定于某个具体资源(如 DeploymentPod),而是作用于所有支持的资源。

4. 示例:如何对 Deploymentspec 操作

如果要操作 Deploymentspec 部分,需要直接操作 Deployment 资源,而不是通过这些选项类型。以下是示例:

4.1 获取 Deploymentspec
deployment, err := clientset.AppsV1().Deployments("default").Get(context.TODO(), "nginx-deployment", metav1.GetOptions{})
if err != nil {panic(err)
}
fmt.Println("Replicas:", *deployment.Spec.Replicas)
4.2 更新 Deploymentspec
deployment, err := clientset.AppsV1().Deployments("default").Get(context.TODO(), "nginx-deployment", metav1.GetOptions{})
if err != nil {panic(err)
}// 修改 replicas
replicas := int32(5)
deployment.Spec.Replicas = &replicas// 更新 Deployment
updatedDeployment, err := clientset.AppsV1().Deployments("default").Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {panic(err)
}
fmt.Println("Updated Replicas:", *updatedDeployment.Spec.Replicas)

5. 总结

  • AddToGroupVersion 中的类型(如 ListOptions 等)主要用于控制 Kubernetes API 的操作行为,不直接操作资源内容。
  • 如果需要对具体资源(如 Deployment)的 spec 部分进行操作,需要通过对应的客户端 API(如 GetUpdate)处理,而不是通过这些选项类型完成。
  • 选项类型适用于所有资源,而 spec 是资源定义中的特定字段,需要单独操作。

Q9 | Option 的使用(以 listOptions 为例)

要发起请求并利用 ListOptions,你通常是在 Kubernetes API 客户端中执行列出资源的操作(如列出 Pods、Deployments 等)。ListOptions 是一种用于过滤、分页和定制列出操作的选项,它可以传递给 kubectl 或 Kubernetes Go 客户端库中的相关方法。

1. 使用 Kubernetes Go 客户端

在 Kubernetes Go 客户端中,你可以使用 ListOptions 来指定资源列出的行为,例如分页、字段选择、标签选择等。以下是如何通过 Kubernetes Go 客户端发起列出请求并使用 ListOptions 的示例:

示例:列出 Pods 并使用 ListOptions
package mainimport ("context""flag""fmt""log"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd""k8s.io/client-go/util/homedir""path/filepath"
)func main() {// 获取 kubeconfig 文件路径kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")// 创建 Kubernetes 客户端配置config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)if err != nil {log.Fatalf("failed to build kubeconfig: %v", err)}// 创建 Kubernetes 客户端clientset, err := kubernetes.NewForConfig(config)if err != nil {log.Fatalf("failed to create Kubernetes client: %v", err)}// 使用 ListOptions 设置分页和标签选择listOptions := &metav1.ListOptions{LabelSelector: "app=myapp",  // 通过标签选择器过滤Limit:         10,           // 限制返回的结果为10个}// 获取 Pods 列表pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), *listOptions)if err != nil {log.Fatalf("failed to list pods: %v", err)}// 打印结果fmt.Printf("Found %d pods:\n", len(pods.Items))for _, pod := range pods.Items {fmt.Printf("Pod Name: %s\n", pod.Name)}
}

2. 解释关键部分

  • Kubernetes 客户端配置 (clientcmd.BuildConfigFromFlags)
    • 这里的 BuildConfigFromFlags 函数会根据 kubeconfig 文件(通常位于 ~/.kube/config)创建一个客户端配置,连接到 Kubernetes 集群。
  • ListOptions
    • LabelSelector:用于筛选具有特定标签的资源,例如 "app=myapp",这会返回所有具有 app=myapp 标签的 Pods。
    • Limit:限制返回的资源数量,这里设为 10,表示最多返回 10 个 Pod。
    • 你还可以通过 FieldSelector 过滤资源,例如筛选处于某个状态的 Pod,或者指定其他选项,如 Continue(用于分页)和 ResourceVersion(用于版本控制)。
  • 发起请求
    • clientset.CoreV1().Pods("default").List(context.TODO(), *listOptions):该调用会向 Kubernetes 集群的 “default” 命名空间发起一个列出 Pods 的请求,并应用上面设置的 ListOptions
  • 处理响应
    • 返回的 pods.Items 是一个包含 Pod 对象的切片,你可以遍历它们并查看相关信息。

3. 使用 ListOptions 进行高级筛选

除了分页和标签选择外,ListOptions 还可以通过 FieldSelector 实现基于字段的筛选。例如,你可以筛选出所有状态为 Running 的 Pods,或者通过 resourceVersion 来获取某个版本的资源。

listOptions := &metav1.ListOptions{FieldSelector: "status.phase=Running",  // 只返回状态为 Running 的 PodLimit:         10,                      // 限制返回的结果为 10 个
}

4. 其他 ListOptions 示例

  • 分页:如果有很多资源,Kubernetes API 会返回一部分结果并包含一个 continue 字段,允许你继续获取更多结果。例如,你可以通过以下代码获取更多资源:
listOptions := &metav1.ListOptions{Limit:    10,               // 每次返回最多 10 个资源Continue: "abc123",         // 继续获取的分页标识符
}
  • 资源版本:你可以通过 ResourceVersion 来指定列出资源时的版本,从而确保列出的资源与某个特定版本一致。
listOptions := &metav1.ListOptions{ResourceVersion: "12345",    // 只列出版本为 12345 的资源
}

5. 总结

  • ListOptions 是 Kubernetes API 中列出资源时的参数,允许你控制返回的资源内容、过滤方式、分页和排序。
  • 在 Kubernetes Go 客户端中,通过 clientset.CoreV1().Pods("default").List 这样的 API 调用发起请求并传递 ListOptions
  • ListOptions 可以包含多个筛选条件,如 LabelSelectorFieldSelectorLimitContinueResourceVersion,使得列出操作更加灵活。

通过这种方式,你可以根据具体需求定制列出资源的行为,方便开发人员和运维人员高效管理 Kubernetes 中的资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479734.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PySide6 QSS(Qt Style Sheets) Reference: PySide6 QSS参考指南

Qt官网参考资料&#xff1a; QSS介绍&#xff1a; Styling the Widgets Application - Qt for Pythonhttps://doc.qt.io/qtforpython-6/tutorials/basictutorial/widgetstyling.html#tutorial-widgetstyling QSS 参考手册&#xff1a; Qt Style Sheets Reference | Qt Widge…

python控制鼠标,键盘,adb

python控制鼠标&#xff0c;键盘&#xff0c;adb 听说某系因为奖学金互相举报&#xff0c;好像拿不到要命一样。不禁想到几天前老墨偷走丁胖子的狗&#xff0c;被丁胖子逮到。他面对警察的问询面不改色坚持自我&#xff0c;反而是怒气冲冲的丁胖子被警察认为是偷狗贼。我觉得这…

前端Vue项目整合nginx部署到docker容器

一、通过Dockerfile整合nginx方法&#xff1a; 1&#xff0c;使用Vue CLI或npm脚本构建生产环境下的Vue项目。 npm run build or yarn build2&#xff0c;构建完成后&#xff0c;项目目录中会生成一个dist文件夹&#xff0c;里面包含了所有静态资源文件&#xff08;HTML、CSS…

ChatGPT的应用场景:开启无限可能的大门

ChatGPT的应用场景:开启无限可能的大门 随着人工智能技术的快速发展,自然语言处理领域迎来了前所未有的突破。其中,ChatGPT作为一款基于Transformer架构的语言模型,凭借其强大的语言理解和生成能力,在多个行业和场景中展现出了广泛的应用潜力。以下是ChatGPT八个最具代表…

Wireshark抓取HTTPS流量技巧

一、工具准备 首先安装wireshark工具&#xff0c;官方链接&#xff1a;Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成&#xff0c;用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件&#xff08;例如包含密钥的…

【dvwa靶场:File Upload系列】File Upload低-中-高级别,通关啦

目录 一、low级别,直接上传木马文件 1.1、准备一个木马文件 1.2、直接上传木马文件 1.3、访问木马链接 1.4、连接蚁剑 二、medium级别&#xff1a;抓包文件缀名 2.1、准备一个木马文件&#xff0c;修改后缀名为图片的后缀名 2.2、上传文件&#xff0c;打开burpSuite&…

【深度学习|目标跟踪】StrongSort 详解(以及StrongSort++)

StrongSort详解 1、论文及源码2、DeepSort回顾3、StrongSort的EMA4、StrongSort的NSA Kalman5、StrongSort的MC6、StrongSort的BOT特征提取器7、StrongSort的AFLink8、未完待续 1、论文及源码 论文地址&#xff1a;https://arxiv.org/pdf/2202.13514 源码地址&#xff1a;https…

10、PyTorch autograd使用教程

文章目录 1. 相关思考2. 矩阵求导3. 两种方法求jacobian 1. 相关思考 2. 矩阵求导 假设我们有如下向量&#xff1a; y 1 3 x 1 5 [ w T ] 5 3 b 1 3 \begin{equation} y_{1\times3}x_{1\times5}[w^T]_{5\times3}b_{1\times3} \end{equation} y13​x15​[wT]53​b13​​…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…

软件质量保证——软件测试流程

笔记内容及图片整理自XJTUSE “软件质量保证” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 对于软件测试中产品/服务/成果的质量&#xff0c;需要细化到每个质量特性上&#xff0c;因此出现了较为公认的软件质量模型&#xff0c;包括McCall质量模型、ISO/IEC 9126…

代码美学2:MATLAB制作渐变色

效果&#xff1a; %代码美学&#xff1a;MATLAB制作渐变色 % 创建一个10x10的矩阵来表示热力图的数据 data reshape(1:100, [10, 10]);% 创建热力图 figure; imagesc(data);% 设置颜色映射为“cool” colormap(cool);% 在热力图上添加边框 axis on; grid on;% 设置热力图的颜色…

从0开始学PHP面向对象内容之常用设计模式(组合,外观,代理)

二、结构型设计模式 4、组合模式&#xff08;Composite&#xff09; 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它将对象组合成树形结构以表示”部分–整体“的层次结构。通过组合模式&#xff0c;客户端可以以一致的方式处理单个对…

femor 第三方Emby应用全平台支持v1.0.54更新

femor v1.0.54 版本更新 mpv播放器增加切换后台和恢复时隐藏状态栏的功能修复服务器首页因为连接超时异常的问题 获取路径&#xff1a;【femor 历史版本收录】

如何搭建一个小程序:从零开始的详细指南

在当今数字化时代&#xff0c;小程序以其轻便、无需下载安装即可使用的特点&#xff0c;成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业&#xff0c;小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序&#xff0c;本文将为你提供一个从零开始的详细…

nrm镜像管理工具使用方法

nrm&#xff08;NPM Registry Manager&#xff09;是一款专门用于管理 npm 包镜像源的命令行工具。在使用 npm 安装各种包时&#xff0c;默认会从官方的 npm 仓库&#xff08;registry&#xff09;获取资源&#xff0c;但有时候由于网络环境等因素&#xff0c;访问官方源可能速…

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…

易速鲜花聊天客服机器人的开发(下)

目录 “聊天机器人”项目说明 方案 1 &#xff1a;通过 Streamlit 部署聊天机器人 方案2 &#xff1a;通过 Gradio 部署聊天机器人 总结 上一节&#xff0c;咱们的聊天机器人已经基本完成&#xff0c;这节课&#xff0c;我们要看一看如何把它部署到网络上。 “聊天机器人”…

STM32笔记(串口IAP升级)

一、IAP简介 IAP&#xff08;In Application Programming&#xff09;即在应用编程&#xff0c; IAP 是用户自己的程序在运行过程中对 User Flash 的部分区域进行烧写&#xff0c;目的是为了在产品发布后可以方便地通过预留的通信口对产 品中的固件程序进行更新升级。 通常实…

斐波那契堆与二叉堆在Prim算法中的性能比较:稀疏图与稠密图的分析

斐波那契堆与二叉堆在Prim算法中的性能比较:稀疏图与稠密图的分析 引言基本概念回顾Prim算法的时间复杂度分析稀疏图中的性能比较稠密图中的性能比较|E| 和 |V| 的关系伪代码与C代码示例结论引言 在图论中,Prim算法是一种用于求解最小生成树(MST)的贪心算法。其性能高度依…

使用argo workflow 实现springboot 项目的CI、CD

文章目录 基础镜像制作基础镜像设置镜像源并安装工具git下载和安装 Maven设置环境变量设置工作目录默认命令最终dockerfile 制作ci argo workflow 模版volumeClaimTemplatestemplatesvolumes完整workflow文件 制作cd argo workflow 模版Workflow 结构Templates 定义创建 Kubern…