你好,我是孔令飞。
通过上一节课的分析,我们知道 kube-apiserver 是通过调用 SetObjectDefaults_Deployment 方法来给资源设置默认值,那么 SetObjectDefaults_Deployment 方法又是从哪里来的呢?本节课,我为你详细介绍。
默认值设置函数 func SetDefaults_<Type>(obj *<Type>) 是由 defaulter-gen 工具自动生成的,具体分为以下 3 步:
-
生成
zz_generated.defaults.go文件。 -
添加自定义默认值设置代码。
-
注册资源定义的默认值设置函数。
我们一一来看。
生成 zz_generated.defaults.go 文件
defaulter-gen 工具根据 +k8s:defaulter-gen=TypeMeta 注释来判断,是否要为所在包的资源定义生成设置默认值函数。所以,我们首先要添加 +k8s:defaulter-gen=TypeMeta 标签。+k8s:defaulter-gen=TypeMeta 标签的意思是为所有包含TypeMeta(也可以是 ObjectMeta、ListMeta)的所有资源定义结构体生成设置默认值函数。如果你想为所有的结构体都生成设置默认值函数,可以将 +k8s:defaulter-gen 的值设置为 +k8s:defaulter-gen=true。
在实际的 Kubernetes 开发中,我们通常使用 +k8s:defaulter-gen=TypeMeta 标签,只给需要的资源定义结构体生成设置默认值函数。
这里我使用之前的示例代码来给你演示。首先克隆示例代码:
$ git clone https://github.com/superproj/k8sdemo
$ cd k8sdemo/resourcedefinition
$ go mod tidy
我们可以在 apps/v1beta1/doc.go 文件中添加 +k8s:defaulter-gen=TypeMeta 注释,例如:
$ cat apps/v1beta1/doc.go
// Copyright 2022 Lingfei Kong <colin404@foxmail.com>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/superproj/onex.
//
// +k8s:deepcopy-gen=package
// +k8s:defaulter-gen=TypeMeta
// +k8s:defaulter-gen-input=github.com/superproj/k8sdemo/resourcedefinition/apps/v1beta1
// Package v1beta1 is the v1beta1 version of the API.
package v1beta1
注意,在 doc.go 文件中,我们还添加了 // +k8s:defaulter-gen-input=github.com/superproj/k8sdemo/resourcedefinition/apps/v1beta1 注释,该行注释解释了资源结构体的来源。
在我们添加了必要的 // +_k8s: 注释之后,便可以运行以下命令,来为资源结构体生成设置默认值函数:
$ defaulter-gen -v 1 --go-header-file ./boilerplate.go.txt --output-file zz_generated.defaults.go ./apps/v1beta1/
执行完上述命令后,会生成 apps/v1beta1/zz_generated.defaults.go 文件,文件内容如下:
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Copyright 2022 Lingfei Kong <colin404@foxmail.com>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/superproj/onex.
// Code generated by defaulter-gen. DO NOT EDIT.
package v1beta1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}
zz_generated.defaults.go 中生成了 RegisterDefaults 函数,用来向 scheme 注册资源的默认值设置函数。
添加自定义默认值设置代码
上面操作生成的 RegisterDefaults 函数设置方法为空,是因为我们没有添加自定义的默认值设置逻辑。
这里我们可以根据需要自己添加。例如,新建 apps/v1beta1/defaults.go 文件,内容如下:
package v1beta1
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
// SetDefaults_XXX sets defaults for XXX.
func SetDefaults_XXX(obj *XXX) {
// XXX name prefix is fixed to `hello-`
if obj.ObjectMeta.GenerateName == "" {
obj.ObjectMeta.GenerateName = "hello-"
}
SetDefaults_XXXSpec(&obj.Spec)
}
// SetDefaults_XXXSpec sets defaults for XXX spec.
func SetDefaults_XXXSpec(obj *XXXSpec) {
if obj.DisplayName == "" {
obj.DisplayName = "xxxdefaulter"
}
}
注意,上述默认值设置函数是有固定格式的,设置默认值函数的函数命名、入参、返回值都需要符合规范:
-
设置默认值的函数名需要为
SetDefaults_<Type>,其中<Type>是资源定义结构体名字。 -
入参固定为
<Type>。 -
没有返回值。
在添加完自定义的默认值设置逻辑之后,再次运行 defaulter-gen 命令,来生成设置默认值函数:
$ defaulter-gen -v 1 --go-header-file ./boilerplate.go.txt --output-file zz_generated.defaults.go ./apps/v1beta1/
运行上述命令之后,apps/v1beta1/zz_generated.defaults.go 文件内容会变为:
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Copyright 2022 Lingfei Kong <colin404@foxmail.com>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/superproj/onex.
// Code generated by defaulter-gen. DO NOT EDIT.
package v1beta1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&XXX{}, func(obj interface{}) { SetObjectDefaults_XXX(obj.(*XXX)) })
scheme.AddTypeDefaultingFunc(&XXXList{}, func(obj interface{}) { SetObjectDefaults_XXXList(obj.(*XXXList)) })
return nil
}
func SetObjectDefaults_XXX(in *XXX) {
SetDefaults_XXX(in)
SetDefaults_XXXSpec(&in.Spec)
}
func SetObjectDefaults_XXXList(in *XXXList) {
for i := range in.Items {
a := &in.Items[i]
SetObjectDefaults_XXX(a)
}
}
可以看到,RegisterDefaults 中自动生成了一些函数调用,这些函数调用用来将指定的资源定义方法注册到 Scheme 中。
注册资源定义的默认值设置函数
在添加完自己的设置默认值函数之后,还有非常重要的一步操作,就是要把该默认值设置 Scheme 构造器,添加到 legacyscheme.Scheme Scheme 构造列表中,以便在初始化 Scheme 构造器列表时,能够将指定资源的默认值设置方法添加到 *Scheme 结构体的 defaulterFuncs 中。至于 defaulterFuncs 字段具体是如何使用的,你可以参考《Kubernetes 如何设置默认值?》这节课。
添加默认值设置 Scheme 构造器,要新建 apps/v1beta1/register.go 文件,内容如下:
package v1beta1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/apis/autoscaling"
)
// GroupName is the group name used in this package.
const GroupName = "apps.k8sdemo.io"
// SchemeGroupVersion is group version used to register these objects.
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
// 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, addDefaultingFuncs)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&XXX{},
&XXXList{},
)
// Add the watch version that applies
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
通过 SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs) 变量设置,添加了构造器 addDefaultingFuncs。
课程总结
本节课围绕 Kubernetes 中默认值设置函数的生成过程进行了详细讲解。首先介绍了默认值设置函数 SetDefaults_<Type>(obj *<Type>) 是通过 defaulter-gen 工具自动生成的,具体过程包括 3 个主要步骤:
-
生成 zz_generated.defaults.go 文件:通过在资源定义结构体的
doc.go文件中添加注释// +k8s:defaulter-gen=TypeMeta,指示 defaulter-gen 工具生成默认值设置函数。然后执行生成命令创建zz_generated.defaults.go文件,其中包含RegisterDefaults函数,用于注册默认值函数。 -
添加自定义默认值设置代码:在新的
defaults.go文件中定义自定义的默认值设置逻辑。在设置默认值函数中,必须遵循一定的命名和参数规范,确保函数能正确定义并设置默认值。 -
注册资源定义的默认值设置函数:在
register.go文件中,使用SchemeBuilder将默认值设置函数添加到 Kubernetes 的 Scheme 构造器中,以便在资源初始化时应用这些默认值。
课后练习
-
生成和注册多个默认值设置函数:选择一个已有的 Kubernetes 资源类型(例如 Pod 或 Deployment),根据这节课提供的方法,为这个资源类型创建一个新的自定义默认值设置函数,并确保其能够正确设置多个字段的默认值。执行相关的生成和注册步骤,并验证功能是否正常。
-
扩展默认值设置逻辑:在自定义的默认值设置函数中,尝试实现更加复杂的逻辑。例如,根据特定条件(如其他字段的值)来设置默认值。
欢迎你在留言区与我交流讨论,如果今天的内容让你有所收获,也欢迎转发给有需要的朋友,我们下节课再见!
精选留言
2025-06-24 13:39:39
好像找不到了。
2025-06-20 15:21:52
好像找不到了。