2. Generate codes
2.1. Overview
code-generator is Golang code-generators used to implement Kubernetes-style API types (generate deepcopy, clientset, informer, lister)
- DeepCopy is necessary to implement runtime.Object interface.
- Clientset is to access a (custom) resource in Kubernetes API.
- Lister is to list custom resources in a in-memory
cache.Indexer
with List function. - Informer is used to capture changes of a target custom resource, which is usually used in a custom controller.
2.2. Prepare code-generator
Set
codeGeneratorDir
env var forcode-generator
.codeGeneratorDir=~/repos/kubernetes/code-generator
If you already cloned, you can specify the directory.
Clone code-generator if you haven’t cloned.
git clone https://github.com/kubernetes/code-generator.git $codeGeneratorDir
"${codeGeneratorDir}"/generate-groups.sh Usage: generate-groups.sh <generators> <output-package> <apis-package> <groups-versions> ... <generators> the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all". <output-package> the output package name (e.g. github.com/example/project/pkg/generated). <apis-package> the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis). <groups-versions> the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative to <api-package>. ... arbitrary flags passed to all generator binaries. Examples: generate-groups.sh all github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" generate-groups.sh deepcopy,client github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1"
2.3. Add markers
Mark the package
pkg/api/doc.go
.+// +k8s:deepcopy-gen=package +// +groupName=example.com package v1alpha1
// +k8s:deepcopy-gen=package
: generate DeepCopy for the entire package// +groupName=example.com
: used in the fake client as the full group name (defaults to the package name) (client-gen)
Mark the types (
Foo
andFooList
) inpkg/api/types.go
.+// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Foo is a specification for a Foo resource type Foo struct { ...
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // FooList is a list of Foo resources type FooList struct {
// +genclient
: generate default client verb functions (create, update, delete, get, list, update, patch, watch and depending on the existence of .Status field in the type the client is generated for also updateStatus). (More details: Generation and release cycle of clientset)+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
: generate DeepCopyObject with the given interfaces as return types.
For more about comment tags.
2.4. Generate codes
Generate codes (deepcopy, clientset, listers, and informers).
※ You need to replace
github.com/nakamasato/sample-controller
with your module name.module=github.com/nakamasato/sample-controller; "${codeGeneratorDir}"/generate-groups.sh all ${module}/pkg/generated ${module}/pkg/apis example.com:v1alpha1 --go-header-file "${codeGeneratorDir}"/hack/boilerplate.go.txt --trim-path-prefix $module --output-base ./
--output-base ./
is necessary to generate the codes under the current directory--trim-path-prefix $module
is necessary to generate under the pathpkg/generated/...
The command above consists of the following commands:
Set
gobin
GOBIN="$(go env GOBIN)" gobin="${GOBIN:-$(go env GOPATH)/bin}"
deepcopy-gen:
${gobin}/deepcopy-gen --input-dirs github.com/nakamasato/sample-controller/pkg/apis/example.com/v1alpha1 -O zz_generated.deepcopy --go-header-file /Users/m.naka/repos/kubernetes/code-generator/hack/boilerplate.go.txt --trim-path-prefix github.com/nakamasato/sample-controller
client-gen:
${gobin}/client-gen --clientset-name versioned --input-base '' --input github.com/nakamasato/sample-controller/pkg/apis/example.com/v1alpha1 --output-package github.com/nakamasato/sample-controller/pkg/generated/clientset --go-header-file /Users/m.naka/repos/kubernetes/code-generator/hack/boilerplate.go.txt --trim-path-prefix github.com/nakamasato/sample-controller
lister-gen:
${gobin}/lister-gen --input-dirs github.com/nakamasato/sample-controller/pkg/apis/example.com/v1alpha1 --output-package github.com/nakamasato/sample-controller/pkg/generated/listers --go-header-file /Users/m.naka/repos/kubernetes/code-generator/hack/boilerplate.go.txt --trim-path-prefix github.com/nakamasato/sample-controller
informer-gen:
${gobin}/informer-gen --input-dirs github.com/nakamasato/sample-controller/pkg/apis/example.com/v1alpha1 --versioned-clientset-package github.com/nakamasato/sample-controller/pkg/generated/clientset/versioned --listers-package github.com/nakamasato/sample-controller/pkg/generated/listers --output-package github.com/nakamasato/sample-controller/pkg/generated/informers --go-header-file /Users/m.naka/repos/kubernetes/code-generator/hack/boilerplate.go.txt --trim-path-prefix github.com/nakamasato/sample-controller
The following files are generated:
pkg/apis/example.com/v1alpha1/zz_generated.deepcopy.go
pkg/generated/
clientset
informers
listers
tree . . ├── README.md ├── go.mod ├── go.sum └── pkg ├── apis │ └── example.com │ └── v1alpha1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go └── generated ├── clientset │ └── versioned │ ├── clientset.go │ ├── doc.go │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ └── typed │ └── example.com │ └── v1alpha1 │ ├── doc.go │ ├── example.com_client.go │ ├── fake │ │ ├── doc.go │ │ ├── fake_example.com_client.go │ │ └── fake_foo.go │ ├── foo.go │ └── generated_expansion.go ├── informers │ └── externalversions │ ├── example.com │ │ ├── interface.go │ │ └── v1alpha1 │ │ ├── foo.go │ │ └── interface.go │ ├── factory.go │ ├── generic.go │ └── internalinterfaces │ └── factory_interfaces.go └── listers └── example.com └── v1alpha1 ├── expansion_generated.go └── foo.go 21 directories, 29 files
As is mentioned in the previous section,
AddToScheme
is called inpkg/generated/clientset/versioned/scheme/register.go
to register our new api versionexample.com/v1alpha1
, which includesFoo
kind.var localSchemeBuilder = runtime.SchemeBuilder{ examplev1alpha1.AddToScheme, } ... var AddToScheme = localSchemeBuilder.AddToScheme func init() { v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) utilruntime.Must(AddToScheme(Scheme)) }
Run
go mod tidy
.