Kubernetes源码剖析
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.5 代码生成器

顶层Makefile中定义了generated_files命令,该命令用于构建代码生成器,下面看一下generated_files在Makefile.generated_files中的定义:

generated_files中定义了5个代码生成器,执行make all命令后,这些二进制文件被输出至_output/bin/目录,如下面的输出内容所示。如果二进制文件不存在,也可以通过make generated_files命令单独构建代码生成器的二进制工具。下面分别介绍这些代码生成器,如表2-1所示。

表2-1 代码生成器说明

除了以上5个代码生成器,Kubernetes实际上还支持更多的代码生成器,例如client-gen、lister-gen、informer-gen等代码生成器。这些代码生成器会在后面的章节中进行介绍,本节提及的这5个代码生成器是构建Kubernetes源码过程中所需要的。

2.5.1 Tags

代码生成器通过Tags(标签)来识别一个包是否需要生成代码及确定生成代码的方式,Kubernetes提供的Tags可以分为如下两种。

全局Tags:定义在每个包的doc.go文件中,对整个包中的类型自动生成代码。

局部Tags:定义在Go语言的类型声明上方,只对指定的类型自动生成代码。

Tags的定义规则通常为//+tag-name或//+tag-name=value,它们被定义在注释中。

1.全局Tags

全局Tags定义在pkg/apis/<group>/<version>/doc.go中,代码示例如下:

全局Tags告诉deepcopy-gen代码生成器为该包中的每个类型自动生成DeepCopy函数。其中的//+groupName定义了资源组名称,资源组名称一般使用域名形式命名。

2.局部Tags

局部Tags定义在Go语言的类型声明上方,代码示例如下:

代码路径:pkg/apis/core/types.go

局部Tags定义在Pod资源类型的上方,它定义了该类型有两个代码生成器,分别为genclient(即client-gen)和deepcopy-gen。其中genclient代码生成器为这个资源类型自动生成对应的客户端代码,deepcopy-gen代码生成器为这个资源类型自动生成DeepCopy函数。

注意:关于Tags的位置,局部Tags一般定义在类型声明的上方,但如果该类型有注释信息,则局部Tags的定义需要与类型声明的注释信息之间至少有一个空行。例如:

这是因为Kubernetes的API文档生成器会根据类型声明的注释信息(comment-block)生成文档。为了避免Tags信息出现在文档中,故将Tags定义在注释的上方并空一行。

2.5.2 deepcopy-gen代码生成器

deepcopy-gen是一个自动生成DeepCopy函数的代码生成器。给定一个包的目录路径作为输入源,它可以为其生成DeepCopy相关函数,这些函数可以有效地执行每种类型的深复制操作。

为整个包生成DeepCopy相关函数时,其Tags形式如下:

为单个类型生成DeepCopy相关函数时,其Tags形式如下:

为整个包生成DeepCopy相关函数时,可以忽略单个类型,其Tags形式如下:

有时在Kubernetes源码里会看到deepcopy-gen的Tags被定义成runtime.Object,这时deepcopy-gen会为该类型生成返回值为runtime.Obejct类型的DeepCopyObject函数,代码示例如下:

生成如下代码:

下面介绍deepcopy-gen的使用示例和生成规则。

1.deepcopy-gen的使用示例

构建deepcopy-gen二进制文件,并执行deepcopy-gen代码生成器,为k8s.io/kubernetes/pkg/apis/abac/v1beta1包生成zz_generated.deepcopy.go代码文件。

2.deepcopy-gen的生成规则

代码路径:vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go

deepcopy-gen会遍历包中的所有类型,若类型为types.Struct,则会为该类型生成深复制函数。

2.5.3 defaulter-gen代码生成器

defaulter-gen是一个自动生成Defaulter函数的代码生成器。给定一个包的目录路径作为输入源,它可以为其生成Defaulter相关函数,这些函数可以为资源对象生成默认值。

为拥有TypeMeta属性的类型生成Defaulter相关函数时,其Tags形式如下:

为拥有ListMeta属性的类型生成Defaulter相关函数时,其Tags形式如下:

为拥有ObjectMeta属性的类型生成Defaulter相关函数时,其Tags形式如下:

defaulter-gen的Tags都属于全局Tags,没有局部Tags。其值可以为TypeMeta、ListMeta、ObjectMeta,最常用的是TypeMeta。有时在Kubernetes源码里会看到defaulter-gen-input,这说明当前包会依赖于指定的路径包,代码示例如下:

下面介绍defaulter-gen的使用示例和生成规则。

1.defaulter-gen的使用示例

构建defaulter-gen二进制文件,并执行defaulter-gen代码生成器,为k8s.io/kubernetes/pkg/apis/rbac/v1包生成zz_generated.defaults.go代码文件。

2.defaulter-gen的生成规则

代码路径:k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go

defaulter-gen会遍历包中的所有类型,若类型属性拥有特定类型(如TypeMeta、ListMeta、ObjectMeta),则为该类型生成Defaulter函数,并为其生成RegisterDefaults注册函数,代码示例如下:

代码路径:pkg/apis/rbac/v1/defaults.go

生成的Defaults函数如下:

代码路径:pkg/apis/rbac/v1/zz_generated.defaults.go

在defaults.go中定义了rbacv1.ClusterRoleBinding类型,该类型拥有TypeMeta属性,并为该属性生成SetObjectDefaults_ClusterRoleBinding函数。

2.5.4 conversion-gen代码生成器

conversion-gen是一个自动生成Convert函数的代码生成器。给定一个包的目录路径作为输入源,它可以为其生成Convert相关函数,这些函数可以为对象在内部和外部类型之间提供转换函数。

为整个包生成Convert相关函数时,其Tags形式如下:

其中的<peer-pkg>用于定义包的导入路径,例如k8s.io/kubernetes/pkg/apis/abac。

为整个包生成Convert相关函数且依赖其他包时,其Tags形式如下:

其中的<type-pkg>用于定义其他包的路径,例如k8s.io/api/autoscaling/v1。

在排除某个属性后生成Convert相关函数时,其Tags形式如下:

下面介绍conversion-gen的使用示例和生成规则。

1.conversion-gen的使用示例

构建conversion-gen二进制文件,并执行conversion-gen代码生成器,为k8s.io/kubernetes/pkg/apis/abac/v1beta1包生成zz_generated.conversion.go代码文件。

2.conversion-gen的生成规则

代码路径:vendor/k8s.io/code-generator/cmd/conversion-gen/generators/conversion.go

conversion-gen会遍历包中的所有类型,若类型为types.Struct且过滤掉了私有的Struct类型,则为该类型生成Convert函数,并为该类型同时生成RegisterConversions注册函数,代码示例如下:

代码路径:pkg/apis/abac/v1beta1/types.go

生成的Convert函数如下:

代码路径:pkg/apis/abac/v1beta1/zz_generated.conversion.go

在types.go中定义了Policy类型,conversion-gen为该类型生成了Convert函数,例如从v1beta1转换为internal内部版本,从internal内部版本转换为v1版本,代码示例如下:

定义old变量为v1beta1资源版本,通过Convert函数将v1beta1版本转换为内部版本(即internal变量)。

2.5.5 openapi-gen代码生成器

openapi-gen是一个自动生成OpenAPI定义文件(OpenAPI Definition File)的代码生成器,给定一个包的目录路径作为输入源,它可以为其生成OpenAPI定义文件,该文件用于kube-apiserver服务上的OpenAPI规范的生成。更多关于OpenAPI规范的内容,详情请参考7.1.3节“OpenAPI/Swagger核心原理”。

为特定类型或包生成OpenAPI定义文件时,其Tags形式如下:

排除为特定类型或包生成OpenAPI定义文件时,其Tags形式如下:

下面介绍openapi-gen的使用示例和生成规则。

1.openapi-gen的使用示例

构建openapi-gen二进制文件,并执行openapi-gen代码生成器,为k8s.io/kubernetes/vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1包生成zz_generated.openapi.go代码文件,该代码文件存放在k8s.io/kubernetes/pkg/generated/openapi目录下。

2.openapi-gen的生成规则

代码路径:vendor/k8s.io/kube-openapi/pkg/generators/openapi.go

openapi-gen会遍历包中的所有类型,若类型为types.Struct并忽略其他类型,则为types.Struct类型生成OpenAPI定义文件。例如:

代码路径:vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/types.go

生成的OpenAPIDefinition如下:

代码路径:pkg/generated/openapi/zz_generated.openapi.go

在types.go中定义了CustomResourceDefinitionSpec类型,openapi-gen为该类型生成了OpenAPIDefinition。

2.5.6 go-bindata代码生成器

go-bindata是一个第三方工具,它能够将静态资源文件嵌入Go语言中,例如在Web开发中,它可以将静态的HTML、JavaScript等静态资源文件嵌入Go语言代码文件中并提供一些操作方法。给定一个静态资源目录路径作为输入源,go-bindata可以为其生成go文件。go-bindata使用示例如下:

generate-bindata.sh脚本重点执行如下代码:

构建go-bindata二进制文件,并执行go-bindata代码生成器,为translations静态资源目录生成pkg/kubectl/generated/bindata.go.tmp文件。translations目录存放的是与i18n(国际化)语言包相关的文件,在不修改内部代码的情况下支持不同语言及地区。例如,Zh语言包的二进制数据在Go语言中的存储内容如下:

代码路径:pkg/kubectl/generated/bindata.go