【k8s深入理解之 Scheme 补充-2】理解 register.go 暴露的 AddToScheme 函数

AddToScheme 函数

  • AddToScheme 就是为了对外暴露,方便别人调用,将当前Group组的信息注册到其 Scheme 中,以便了解该 Group 组的数据结构,用于后续处理
项目版本用途使用场景
k8s.io/apiV1注册资源某一外部版本数据结构
(只包含v1 版本的基础资源数据结构,不包含版本转换函数)
适用于指定v1版本编写控制器
k8s.io/kubernetesV1注册默认值填充函数和内外版本转换函数
(默认值填充函数,v1和internal的转换函数 zz_generated.conversion.go)
不适用于单独编写控制器
k8s.io/kubernetesinternal注册资源内部版本数据结构
(所有版本的中转者,记录的资源数据结构相比于单一版本更丰富,不包含版本转换函数)
适用于核心组件控制器,可以适配多版本

api 项目中 v1 版本的 AddToScheme 函数

  • register.go 中的 AddToScheme 是专门设计为供外部调用的接口,用于将当前 API 组的所有资源类型和相关逻辑(如默认值和转换函数)注册到全局 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      = runtime.NewSchemeBuilder(addKnownTypes)localSchemeBuilder = &SchemeBuilder// 就是此函数,之后编写别的控制器需要此资源时,可以用过调用该 package-name.AddToScheme 就能了解到该 apps/v1 组的所有资源和对应的数据结构,用于逻辑处理AddToScheme        = localSchemeBuilder.AddToScheme
)// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},&StatefulSet{},&StatefulSetList{},&DaemonSet{},&DaemonSetList{},&ReplicaSet{},&ReplicaSetList{},&ControllerRevision{},&ControllerRevisionList{},)metav1.AddToGroupVersion(scheme, SchemeGroupVersion)return nil
}

Kubernetes 项目中的 v1 版本的 AddToScheme 函数

// 路径 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
)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.localSchemeBuilder.Register(addDefaultingFuncs)
}
  • 相比于 api 项目,同级目录还存在个 zz_generated.conversion.go 函数
// 路径 mod/k8s.io/kubernetes@v1.29.0/pkg/apis/apps/v1/zz_generated.conversion.go
func init() {localSchemeBuilder.Register(RegisterConversions)
}// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
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}// ... 省略若干 v1版本和内部版本的转换函数
}

内部版本的 AddToScheme 函数

// 路径 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{},&DeploymentRollback{},&autoscaling.Scale{},&StatefulSet{},&StatefulSetList{},&ControllerRevision{},&ControllerRevisionList{},&ReplicaSet{},&ReplicaSetList{},)return nil
}

附录1 | 理解 AddToScheme

是的,register.go 中的 AddToScheme 是专门供外部调用的接口。它的主要作用是将当前 API 组的所有资源类型、元数据、版本等注册到全局的 runtime.Scheme,从而支持这些类型的序列化、反序列化、默认值设置和版本转换等操作。


AddToScheme 的特点

  1. 封装性
    • 它封装了资源类型注册的细节,调用者只需要知道 AddToScheme 能将特定 API 组的资源类型注册到 Scheme 中,而无需了解具体的注册过程。
  2. 便于外部调用
    • 通过导出 AddToScheme,外部模块可以轻松将该 API 组集成到自己的项目中。
  3. 统一注册点
    • 将所有相关类型(如 DeploymentStatefulSet)集中在一个函数中注册,方便维护和使用。

调用场景

在 Kubernetes 源码中

AddToScheme 通常会被 Kubernetes 的核心组件或工具(如 kubectl、API server)调用,用于支持资源的处理:

import ("example.com/project/pkg/apis/apps/v1""k8s.io/apimachinery/pkg/runtime"
)func main() {scheme := runtime.NewScheme()v1.AddToScheme(scheme) // 注册 apps/v1 的资源类型
}
在 Controller 开发中

在开发 Kubernetes Controller 时,必须将自定义资源类型注册到控制器的 Scheme 中:

import (appsv1 "example.com/project/pkg/apis/apps/v1"ctrl "sigs.k8s.io/controller-runtime"
)func main() {scheme := ctrl.GetScheme()appsv1.AddToScheme(scheme) // 注册 apps/v1 类型到 controller-runtime 的 Scheme
}
在测试代码中

测试代码中需要模拟某些资源的序列化或反序列化操作时,也需要调用 AddToScheme

import ("example.com/project/pkg/apis/apps/v1""k8s.io/apimachinery/pkg/runtime"
)func TestSomething(t *testing.T) {scheme := runtime.NewScheme()_ = v1.AddToScheme(scheme) // 注册类型,确保测试环境中可以处理这些资源
}

设计目的

  1. 抽象和复用
    • 将复杂的注册过程(如 AddKnownTypesAddToGroupVersion 的调用)封装为一个简单的函数供外部使用。
  2. 统一接口
    • Kubernetes 中不同 API 组都会导出类似的 AddToScheme 函数,外部调用者只需要知道这个约定即可注册所需的类型。
  3. 灵活性
    • 通过 SchemeBuilder 的机制,支持动态添加注册逻辑,便于扩展。

总结

register.go 中的 AddToScheme 是专门设计为供外部调用的接口,用于将当前 API 组的所有资源类型和相关逻辑(如默认值和转换函数)注册到全局 Scheme 中。它通过封装复杂的注册逻辑,提供了一个统一、简单且易于使用的接口,大大降低了集成的复杂性。

附录2 | api 和 kubernetes 项目同版本的 register.go 文件有什么不同

Kubernetes 的 api 项目和 kubernetes 项目中的 register.go 文件不一致,主要是因为两者承担的职责不同,它们分属不同的模块和依赖层级。以下是原因和区别的详细分析:


1. 两者的职责和用途

k8s.io/api
  • 功能:
    • 是一个独立的 API 定义项目,主要用于定义 Kubernetes 的资源结构和常量。
    • 提供资源类型的核心定义,如 DeploymentStatefulSet
    • 这些定义是“纯粹的”,不包含与 Kubernetes 内部运行时相关的逻辑。
  • 特点:
    • 仅包含资源的结构定义和自动生成的代码(如 deepcopyopenapi)。
    • 用于支持外部项目,如客户端工具(client-go)或自定义控制器。
kubernetes
  • 功能:
    • 是 Kubernetes 主项目,包含所有 Kubernetes 的核心逻辑,包括控制器、调度器等。
    • 除了使用 k8s.io/api 提供的资源定义外,还需要注册这些资源到 runtime.Scheme 中。
  • 特点:
    • 包含具体的 Scheme 注册逻辑和运行时依赖。
    • 需要将资源绑定到 Kubernetes 的控制器和调度器逻辑。

2. 两者 register.go 的区别

k8s.io/api 中的 register.go
  • 内容:
    • 提供 GroupNameSchemeGroupVersion 等常量,用于定义 API 组和版本。
    • 仅导出 SchemeBuilderAddToScheme,用于资源类型注册。
    • 不包含 runtime.Scheme 的直接引用,也不执行实际的资源注册。
  • 目的:
    • 定义一个通用的接口,允许其他模块或项目将这些资源类型注册到自己的 runtime.Scheme 中。
    • 不直接注册到运行时,保持模块的轻量级和独立性。
var (SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)AddToScheme   = SchemeBuilder.AddToScheme
)
kubernetes 中的 register.go
  • 内容:
    • k8s.io/api 导入资源类型和 SchemeBuilder
    • 在主项目中,结合 Kubernetes 内部逻辑,扩展资源注册的功能。
    • 增加了 localSchemeBuilder 和其他运行时相关逻辑。
  • 目的:
    • 扩展 API 定义,并将其绑定到 Kubernetes 主项目的运行时环境。
    • 实现默认值填充(addDefaultingFuncs)、字段标签转换等额外功能。
localSchemeBuilder.Register(addDefaultingFuncs)

3. 为什么有分工?

  • 模块化设计:
    • Kubernetes 将 k8s.io/apikubernetes 主项目分开,是为了实现模块化和解耦。
    • 资源定义是基础层,而运行时逻辑是上层依赖。
  • 减少依赖复杂度:
    • k8s.io/api 是许多外部项目(如 client-go)的直接依赖,如果包含运行时逻辑会导致循环依赖。
    • 通过分离,k8s.io/api 只关注定义,避免了复杂的依赖链。
  • 适配不同场景:
    • k8s.io/api 可以被外部项目独立使用,而不需要整个 Kubernetes 主项目。
    • kubernetes 主项目需要额外的运行时逻辑,处理更复杂的功能。

4. 实际工作流

k8s.io/api
  • 提供了 SchemeBuilderAddToScheme,供外部调用。
  • 示例:
import (appsv1 "k8s.io/api/apps/v1""k8s.io/apimachinery/pkg/runtime"
)var scheme = runtime.NewScheme()func main() {appsv1.AddToScheme(scheme) // 注册 API 定义到 Scheme
}
kubernetes
  • 除了注册类型,还会添加其他自定义逻辑,如默认值和字段标签转换。
  • 示例:
import ("k8s.io/kubernetes/pkg/apis/apps/v1"
)func main() {v1.AddToScheme(scheme) // 注册到 Kubernetes 主项目的 Scheme
}

5. 总结

特性k8s.io/apikubernetes
主要职责定义 API 类型和常量运行时绑定和扩展逻辑
是否包含运行时逻辑
导出内容SchemeBuilderAddToSchemeAddToSchemelocalSchemeBuilder、扩展功能
是否直接注册 Scheme
使用场景提供轻量级定义供外部依赖Kubernetes 主项目内部使用

两者的设计目标不同,k8s.io/api 是独立的资源定义库,而 kubernetes 则是完整的实现与运行时逻辑结合。

附录3 | 以 apps 组说明同版本两个 register.go 的 AddToScheme 调用关系

apps 组为例,Kubernetes 的 Scheme 是通过逐层调用 AddToScheme 函数来注册 API 类型的。这两个 AddToScheme 函数分别来自:

  1. k8s.io/api/apps/v1:定义 API 类型(如 Deployment, StatefulSet 等)并提供注册方法。
  2. kubernetes/pkg/apis/apps/v1:扩展 API 定义,并添加运行时相关功能(如默认值填充、字段标签转换等)。

以下是详细的调用流程和逻辑分析:


1. 两个 AddToScheme 的来源

k8s.io/api/apps/v1
  • 定义 SchemeBuilderAddToScheme,注册资源的基本定义到 Scheme 中。
  • 核心功能是调用 runtime.Scheme.AddKnownTypes 注册类型。
kubernetes/pkg/apis/apps/v1
  • 主要在 Kubernetes 主项目中使用,扩展了 AddToScheme,增加了:

    • 默认值函数(defaulter)。
    • 字段标签转换(field label conversion functions)。
    • 其他与运行时相关的功能。

2. 调用的层次和流程

在 Kubernetes 主项目中,Scheme 的初始化流程会递归调用所有注册函数,包括两个 AddToScheme 函数。以下是以 apps 组为例的调用流程:

第一步:调用 k8s.io/api/apps/v1AddToScheme

Kubernetes 主项目会先调用 k8s.io/api/apps/v1 提供的 AddToScheme

import (appsv1 "k8s.io/api/apps/v1"
)var scheme = runtime.NewScheme()func main() {// 注册 apps 组的资源类型appsv1.AddToScheme(scheme)
}

此时的逻辑在 k8s.io/api/apps/v1/register.go 中:

var SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
var AddToScheme = SchemeBuilder.AddToSchemefunc addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Deployment{},&DeploymentList{},&StatefulSet{},&StatefulSetList{},&DaemonSet{},&DaemonSetList{},&ReplicaSet{},&ReplicaSetList{},&ControllerRevision{},&ControllerRevisionList{},)metav1.AddToGroupVersion(scheme, SchemeGroupVersion) // 注册元数据return nil
}

注册的内容主要是:

  • 资源类型:如 Deployment, StatefulSet
  • 元数据:通过 metav1.AddToGroupVersion 注册通用的元信息类型。

第二步:调用 kubernetes/pkg/apis/apps/v1AddToScheme

在 Kubernetes 主项目中,还需要进一步扩展 apps 的资源定义。这时会调用 kubernetes/pkg/apis/apps/v1 中的 AddToScheme

import (appsinternalv1 "k8s.io/kubernetes/pkg/apis/apps/v1"
)func main() {// 扩展 apps 组的功能appsinternalv1.AddToScheme(scheme)
}

此时的逻辑在 kubernetes/pkg/apis/apps/v1/register.go 中:

var localSchemeBuilder = &appsv1.SchemeBuilder // 直接复用 k8s.io/api/apps/v1 的 SchemeBuilder
var AddToScheme = localSchemeBuilder.AddToSchemefunc init() {// 注册运行时相关的函数localSchemeBuilder.Register(addDefaultingFuncs)
}

这里做了以下扩展:

  • 注册默认值函数(addDefaultingFuncs)。
  • apps 资源添加额外的运行时功能。

3. 总结:两者如何组合

在 Kubernetes 主项目中,Scheme 会分别调用 k8s.io/api/apps/v1kubernetes/pkg/apis/apps/v1AddToScheme,实现如下目标:

  1. 基础类型注册

    • k8s.io/api/apps/v1 提供的 AddToScheme 确保 apps 组的资源类型被正确注册到 Scheme 中。
    • 这是所有调用的基础。
  2. 运行时扩展

    • kubernetes/pkg/apis/apps/v1提供的 AddToScheme在基础类型的注册之上,添加运行时功能,如:
      • 默认值填充(Defaulting)。
      • 字段标签转换(Field Label Conversion)。

调用顺序如下:

  • 首先调用 k8s.io/api/apps/v1AddToScheme
  • 其次调用 kubernetes/pkg/apis/apps/v1AddToScheme 扩展功能。

4. 实际调用示例

完整流程可能如下:

import (appsv1 "k8s.io/api/apps/v1"appsinternalv1 "k8s.io/kubernetes/pkg/apis/apps/v1""k8s.io/apimachinery/pkg/runtime"
)func main() {scheme := runtime.NewScheme()// 注册基础类型if err := appsv1.AddToScheme(scheme); err != nil {panic(err)}// 扩展运行时功能if err := appsinternalv1.AddToScheme(scheme); err != nil {panic(err)}// 验证是否注册成功gvk := schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}obj, err := scheme.New(gvk)if err != nil {panic(err)}fmt.Printf("Registered object: %T\n", obj)
}

5. 注册的依赖关系

步骤来源功能
appsv1.AddToSchemek8s.io/api/apps/v1注册基础资源类型和元信息
appsinternalv1.AddToSchemekubernetes/pkg/apis/apps/v1扩展运行时功能,添加默认值、字段转换等

通过这种分层调用,Kubernetes 可以灵活地管理 API 类型的定义和运行时行为。

附录4 | 编写控制器时采用 api 项目的 AddToScheme 还是 kubernetes 项目 internal 版本的 AddToScheme

在编写 Kubernetes 控制器时,通常需要根据具体的需求选择调用 api 项目中的 AddToSchemekubernetes 项目中的 internal 版本的 AddToScheme。以下是两者的区别和使用场景分析:


1. 两种 AddToScheme 的区别

api 项目中的 AddToScheme
  • 来源k8s.io/api(例如 k8s.io/api/apps/v1)。

  • 内容

    • 提供公开的 API 类型定义。
    • 注册外部(版本化)资源类型(如 apps/v1.Deployment)。
  • 特点

    • 独立于 Kubernetes 核心实现,可被任何第三方控制器、客户端使用。
    • 稳定性高,版本化清晰。
  • 使用场景

    • 第三方控制器开发时优先使用。
    • 通过 Kubernetes API 与集群交互的场景。
kubernetes 项目中的 AddToScheme
  • 来源k8s.io/kubernetes/pkg/apis(例如 k8s.io/kubernetes/pkg/apis/apps/v1)。

  • 内容

    • 包含内部资源类型(internal type)。
    • 提供额外的运行时功能,如默认值设置(defaulting)、版本转换(conversion)等。
  • 特点

    • 依赖 Kubernetes 核心实现,不能单独使用。
    • 包含内部类型(internal),需要版本转换才能与外部 API 交互。
  • 使用场景

    • Kubernetes 核心组件(如控制器管理器、调度器)中使用。
    • 需要直接操作内部类型的场景。

2. 控制器开发中如何选择

一般情况:使用 k8s.io/api
  • 推荐做法:在控制器开发中,优先使用 k8s.io/api 中的 AddToScheme,因为:

    1. 提供的是外部版本的资源类型,直接与 Kubernetes API 交互。
    2. 更加通用,易于维护,适用于所有 Kubernetes 集群。
  • 示例

    import ("k8s.io/api/apps/v1""k8s.io/apimachinery/pkg/runtime"
    )var scheme = runtime.NewScheme()func init() {// 注册外部版本的 apps 组资源if err := v1.AddToScheme(scheme); err != nil {panic(err)}
    }
    
特殊情况:使用 kubernetes 项目中的 internal 版本
  • 适用场景

    1. 需要内部类型的性能优化:如果控制器需要直接操作 Kubernetes 内部类型(internal types),例如在同一个进程内执行大量的内部操作,可以使用 internal 版本。
    2. 与 Kubernetes 核心组件的深度集成:如自定义 ControllerManager,在直接调用内部组件时可能需要使用 internal 版本的 AddToScheme
  • 注意事项

    • 使用 internal 类型时,需要手动处理版本转换,将其转换为外部类型与 API Server 交互。
    • kubernetes/pkg/apis 依赖于 Kubernetes 主项目,控制器无法独立运行。
  • 示例

    import ("k8s.io/kubernetes/pkg/apis/apps""k8s.io/apimachinery/pkg/runtime"
    )var scheme = runtime.NewScheme()func init() {// 注册内部版本的 apps 组资源if err := apps.AddToScheme(scheme); err != nil {panic(err)}
    }
    

3. 推荐做法

优先使用 k8s.io/api
  • 理由

    • 更加通用,独立性高,不依赖 Kubernetes 源码。
    • 版本稳定,减少与 Kubernetes 主项目版本变化的耦合。
    • 适用于第三方控制器开发和部署。
仅在必要时使用 kubernetes/pkg/apis
  • 理由

    • 使用 internal 版本需要处理更多的兼容性问题(版本转换等)。
    • 仅在需要直接操作 Kubernetes 内部类型,或开发 Kubernetes 核心组件时才考虑使用。

4. 典型场景举例

使用 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 逻辑
}

5. 总结

场景使用的 AddToScheme 来源理由
第三方控制器开发k8s.io/api独立性高,直接操作外部版本资源,易于与 API Server 交互。
Kubernetes 核心组件扩展kubernetes/pkg/apis内部类型性能更高,适合深度定制和运行时扩展功能。
操作需要运行时默认值或内部结构的资源kubernetes/pkg/apis(需转换外部类型)提供默认值填充、版本转换等运行时功能,但需要处理额外的兼容性问题。

在实际开发中,优先使用外部版本(k8s.io/api,仅在必要时才使用 internal 类型(kubernetes/pkg/apis)。

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

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

相关文章

CQ 社区版 2024.11 | 新增“审批人组”概念、可通过SQL模式自定义审计图表……

CloudQuery 社区 11 月新版本来啦!本月版本依旧是 CUG(CloudQuery 用户组)尝鲜版的更新。 针对审计模块增加了 SQL 模式自定义审计图表;在流程模块引入了“审批人组”概念。此外,在 SQL 编辑器、连接管理等模块都涉及…

做异端中的异端 -- Emacs裸奔之路4: 你不需要IDE

确切地说,你不需要在IDE里面编写或者阅读代码。 IDE用于Render资源文件比较合适,但处理文本,并不划算。 这的文本文件,包括源代码,配置文件,文档等非二进制文件。 先说说IDE带的便利: 函数或者变量的自动…

RDIFramework.NET CS敏捷开发框架 SOA服务三种访问(直连、WCF、WebAPI)方式

1、介绍 在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。…

GitLab CVE-2024-8114 漏洞解决方案

漏洞 ID 标题严重等级CVE ID通过 LFS 令牌提升权限高CVE-2024-8114 GitLab 升级指南GitLab 升级路径查看版本漏洞查询 漏洞解读 此漏洞允许攻击者使用受害者的个人访问令牌(PAT)进行权限提升。影响从 8.12 开始到 17.4.5 之前的所有版本、从 17.5 开…

基于Pyside6开发一个通用的在线升级工具

UI main.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>MainWindow</class><widget class"QMainWindow" name"MainWindow"><property name"geometry"&…

Redis(配置文件属性解析)

一、tcp-backlog深度解析 tcp-backlog是一个TCP连接的队列&#xff0c;主要用于解决高并发场景下客户端慢连接问题。配置文件中的“511”就是队列的长度&#xff0c;对联与TCP的三次握手有关&#xff0c;不同的linux内核&#xff0c;backlog队列中存放的元素&#xff08;客户端…

24.12.02 Element

import { createApp } from vue // 引入elementPlus js库 css库 import ElementPlus from element-plus import element-plus/dist/index.css //中文语言包 import zhCn from element-plus/es/locale/lang/zh-cn //图标库 import * as ElementPlusIconsVue from element-plus/i…

mybatis-plus 对于属性为null字段不更新

MyBatis-Plus 默认情况下会根据字段的值是否为 null 来决定是否生成对应的 UPDATE 语句。这是由 更新策略 决定的&#xff0c;默认的行为是 忽略 null 值&#xff0c;即如果字段值为 null&#xff0c;该字段将不会出现在 UPDATE 语句中。 默认行为分析 MyBatis-Plus 默认的 Fi…

C++小问题

怎么分辨const修饰的是谁 是限定谁不能被改变的&#xff1f; 在C中&#xff0c;const关键字的用途和位置非常关键&#xff0c;它决定了谁不能被修改。const可以修饰变量、指针、引用等不同的对象&#xff0c;并且具体的作用取决于const的修饰位置。理解const的规则能够帮助我们…

在线家具商城基于 SpringBoot:设计模式与实现方法探究

第3章 系统分析 用户的需求以及与本系统相似的在市场上存在的其它系统可以作为系统分析中参考的资料&#xff0c;分析人员可以根据这些信息确定出本系统具备的功能&#xff0c;分析出本系统具备的性能等内容。 3.1可行性分析 尽管系统是根据用户的要求进行制作&#xff0c;但是…

TS问题之class

类 派生类包含了一个构造函数&#xff0c;它 必须调用 super()&#xff0c;它会执行基类的构造函数。 而且&#xff0c;在构造函数里访问 this的属性之前&#xff0c;我们 一定要调用 super()。 这个是TypeScript强制执行的一条重要规则。public 在TypeScript里&#xff0c;成…

TongRDS分布式内存数据缓存中间件

命令 优势 支持高达10亿级的数据缓冲&#xff0c;内存优化管理&#xff0c;避免GC性能劣化。 高并发系统设计&#xff0c;可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储&#xff0c;字段类型和长度可配置。 支持多台服务并行运行&#xff0c;服务之间可互…

项目整合logback日志打印线程id

项目打印日志能帮助我们解决很多的问题&#xff0c;提示我们出现的问题&#xff0c;通过日志我们可以准确的定位问题快速找到问题点解决问题。 <?xml version"1.0" encoding"UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO &l…

Flutter-Web打包后上线白屏

问题描述 Flutter上线后进行测试发现界面白屏&#xff0c;打开开发者模式查看网络发现加载main.js文件404 问题原因 我上线的地址是https://xxx:8091/homedots,但是我打包后的index文件中的baseUrl是"/",将地址改成”/homedots/"&#xff0c;注意homedots后面…

算法训练营day22(二叉树08:二叉搜索树的最近公共祖先,插入,删除)

第六章 二叉树part08 今日内容&#xff1a; ● 235. 二叉搜索树的最近公共祖先 ● 701.二叉搜索树中的插入操作 ● 450.删除二叉搜索树中的节点 详细布置 235. 二叉搜索树的最近公共祖先 相对于 二叉树的最近公共祖先 本题就简单一些了&#xff0c;因为 可以利用二叉搜索树的…

Rust循环引用与多线程并发

循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中&#xff0c;由于所有权和生命周期的严格约束&#xff0c;直接创建循环引用通常会导致编译失败。例如&#xff1a; // 错误的循环引用示例 struct Node {next: Option<B…

ambari metrics单机模式改成集群模式

最近碰到了ambari平台ambari metrics相关的lib较大&#xff0c;导致系统盘使用率较高。今天对这个组件进行转移到其他磁盘使用率低的服务器上&#xff0c;在安装好metrice collector组件后&#xff0c;发现启动时一直报如下错误。 通过报错可以定位到&#xff0c;该组件的模式是…

前端 递归优化

在前端开发中&#xff0c;递归是一种常见的编程技巧&#xff0c;但它也可能带来性能问题&#xff0c;特别是当递归深度很深或递归调用非常频繁时。以下是一些优化递归的方法&#xff1a; 1. 尾递归优化 尾递归是指递归调用是函数中的最后一个操作&#xff0c;没有额外的计算。…

Python 面向对象编程详解

Python 面向对象编程详解 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来设计软件。在 Python 中&#xff0c;面向对象编程非常强大&#xff0c;允许开发者通过类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;来模…

langchain实现基于sql的问答

1. 数据准备 import requestsurl "https://storage.googleapis.com/benchmarks-artifacts/chinook/Chinook.db"response requests.get(url)if response.status_code 200:# Open a local file in binary write modewith open("Chinook.db", "wb&qu…