代码生成过程#
本节以 deepcopy-gen 为例,介绍代码生成器生成代码的全流程。其他代码生成器的生成过程与 deepcopy-gen 基本一致。
Kubernetes 代码生成器包括 deepcopy-gen、defaulter-gen、conversion-gen、openapi-gen、prerelease-lifecycle-gen、client-gen、lister-gen、informer-gen、applyconfiguration-gen 等。其中最常用的 5 种生成代码的过程如图 13-3 所示。
deepcopy-gen、defaulter-gen、conversion-gen、openapi-gen、prerelease-lifecycle-gen、client-gen、lister-gen、informer-gen、applyconfiguration-gen 代码生成器生成代码的流程基本类似,以 deepcopy-gen 代码生成器为例,生成代码的过程可分为以下 3 步:
- 构建 deepcopy-gen 二进制文件。
- 生成 .todo 文件。
- 生成 DeepCopy 相关函数。

下面分别进行介绍。
构建 deepcopy-gen 二进制文件#
为方便读者理解 Makefile.generated_files 的生成代码的过程,下面将 Makefile.generated_files 中的代码和重要的调试信息一并展示。以 deepcopy-gen 代码生成器为例,代码示例如下。
$(DEEPCOPY_GEN):
$(GODEPS k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/deepcopy-gen)
KUBE_BUILD_PLATFORMS="" \
hack/make-rules/build.sh k8s.io/code-generator/cmd/deepcopy-gen
touch $@
重要的调试信息如下:
KUBE_BUILD_PLATFORMS="" hack/make-rules/build.sh k8s.io/code-generator/cmd/deepcopy-gen
touch _output/bin/deepcopy-genhack/make-rules/build.sh 构建脚本根据传入的代码生成器的 main 入口文件路径,构建二进制文件。touch $@ 则更新 deepcopy-gen 代码生成器二进制文件的 atime/mtime/ctime 时间戳。
生成 .todo 文件#
.todo 文件相当于临时文件,用来存放被 Tags 标记过的包。通过 shell 的 grep 命令将所有代码包中 Tags 标记过的包目录记录在 .todo 文件中,方便记录哪些包需要使用代码生成功能,代码示例如下。
ALL_K8S_TAG_FILES := $(shell find $(ALL_GO_DIRS) -maxdepth 1 -type f -name \*.go | xargs grep --color=never -l '^// *+k8s:')
DEEPCOPY_DIRS := $(shell grep --color=never -l '+k8s:deepcopy-gen=' $(ALL_K8S_TAG_FILES) | xargs -n1 dirname | LC_ALL=C sort -u)
$(DEEPCOPY_FILES): $(DEEPCOPY_GEN)
if [ "$(DBG_CODEGEN)" == 1 ]; then \
echo "DBG: deepcopy needed in $(@D):"; \
ls -lft --full-time $@ || true; \
ls -lft --full-time $? || true; \
fi
echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEEPCOPY_GEN).todo
重要的调试信息如下:
echo k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config>>.make/_output/bin/deepcopy-gen.todoMakefile.generated_files 中定义了 ALL_K8S_TAG_FILES 变量,用于获取代码中使用“// +k8s:”Tags 标记过的包,DEEPCOPY_DIRS 变量用于从 ALL_K8S_TAG_FILES 变量中筛选出使用“+k8s:deepcopy-gen”Tag 标记过的包。最终将筛选出的包路径输出到 .todo 文件中。deepcopy-gen.todo 文件中的部分内容如下。
$ head .make/_output/bin/deepcopy-gen.todo
k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config
k8s.io/kubernetes/cmd/cloud-controller-manager/app/apis/config/v1alpha1
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm
k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1
k8s.io/kubernetes/pkg/apis/abac
k8s.io/kubernetes/pkg/apis/abac/v0
k8s.io/kubernetes/pkg/apis/abac/v1beta1
k8s.io/kubernetes/pkg/apis/admission
k8s.io/kubernetes/pkg/apis/admissionregistration
k8s.io/kubernetes/pkg/apis/apps生成 DeepCopy 相关函数#
.PHONY: gen_deepcopy
gen_deepcopy: $(DEEPCOPY_GEN) $(META_DIR)/$(DEEPCOPY_GEN).todo
if [ -s $(META_DIR)/$(DEEPCOPY_GEN).todo ]; then \
pkgs=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | paste -sd, -); \
if [ "$(DBG_CODEGEN)" == 1 ]; then \
echo "DBG: running $(DEEPCOPY_GEN) for $$pkgs"; \
fi; \
N=$$(cat $(META_DIR)/$(DEEPCOPY_GEN).todo | wc -l); \
kube::log::status "Generating deepcopy code for $$N targets"; \
./hack/run-in-gopath.sh $(DEEPCOPY_GEN) \
--v $(KUBE_VERBOSE) \
--logtostderr \
-i "$$pkgs" \
--bounding-dirs $(PRJ_SRC_PATH),"k8s.io/api" \
-O $(DEEPCOPY_BASENAME) \
"$$@"; \
fi
重要的调试信息如下:
./hack/run-in-gopath.sh _output/bin/deepcopy-gen \
--v 1 \
--logtostderr \
-i "$pkgs" \
--bounding-dirs k8s.io/kubernetes,"k8s.io/api" \
-O zz_generated.deepcopy./hack/run-in-gopath.sh 脚本用于设置临时 Kubernetes GOPATH 环境并在其中运行命令。
deepcopy-gen 代码生成器参数说明如表所示。
| 参数 | 参数说明 |
|---|---|
--v | 指定日志级别 |
--logtostderr | 将日志输出到标准错误输出 |
-i, --input-dirs | 输入源,即 .todo 文件中的目录列表,以逗号分隔 |
--bounding-dirs | 依赖的包及为其生成 DeepCopy 的类型 |
-O, --output-filebase | 输出文件的命名 |
deepcopy-gen 代码生成器将 .todo 文件的内容作为输入源,生成 DeepCopy 相关函数,并输出到 zz_generated.deepcopy.go 文件中。以 k8s.io/kubernetes/pkg/apis/abac/v1beta1 作为输入源手动进行测试,执行以下命令。
./hack/run-in-gopath.sh _output/bin/deepcopy-gen \
--v 1 \
--logtostderr \
-i "k8s.io/kubernetes/pkg/apis/abac/v1beta1" \
--bounding-dirs k8s.io/kubernetes,"k8s.io/api" \
-O zz_generated.deepcopy最终,我们在 pkg/apis/abac/v1beta1/ 目录下得到新生成的 zz_generated.deepcopy.go 代码文件。

