LoginSignup
1
0

More than 1 year has passed since last update.

kubernetes code-generatorの使い方

Last updated at Posted at 2022-07-14

code-generatorとは

code-generatorは、Kubernetes のAPI typeを実装するために、必要なコードを生成するツール。

このツールで生成できるものの基本は以下の4種類:

1. deepcopy:

KubernetesのObjectはすべてruntime.Object を実装する必要がありそれに必要なDeepCopyObject生成する

type Object interface {
	GetObjectKind() schema.ObjectKind
	DeepCopyObject() Object
}

Object interface must be supported by all API types registered with Scheme. Since objects in a scheme are expected to be serialized to the wire, the interface an Object must provide to the Scheme allows serializers to set the kind, version, and group the object is represented as. An Object may choose to return a no-op ObjectKindAccessor in cases where it is not expected to be serialized.

2. client

Kubernetes APIにアクセスするクライアント。
Kubernetesのbuilt-inリソースの場合は、clientsetを使ってアクセスする。API groupごとに一つのversionを持つ。

// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
	*discovery.DiscoveryClient
	admissionregistrationV1      *admissionregistrationv1.AdmissionregistrationV1Client
	admissionregistrationV1beta1 *admissionregistrationv1beta1.AdmissionregistrationV1beta1Client
	internalV1alpha1             *internalv1alpha1.InternalV1alpha1Client
	appsV1                       *appsv1.AppsV1Client
	appsV1beta1                  *appsv1beta1.AppsV1beta1Client
	appsV1beta2                  *appsv1beta2.AppsV1beta2Client
	...
}

自分でカスタムリソースを作成する場合には、clientsetは自分で作成する必要があるので、その場合にcode-generatorを使って生成する。

// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
	*discovery.DiscoveryClient
	exampleV1alpha1 *examplev1alpha1.ExampleV1alpha1Client
}

3. lister

in-memoryのcache.Indexerからオブジェクトをリストする

// FooLister helps list Foos.
// All objects returned here must be treated as read-only.
type FooLister interface {
	// List lists all Foos in the indexer.
	// Objects returned here must be treated as read-only.
	List(selector labels.Selector) (ret []*v1alpha1.Foo, err error)
	// Foos returns an object that can list and get Foos.
	Foos(namespace string) FooNamespaceLister
	FooListerExpansion
}

// fooLister implements the FooLister interface.
type fooLister struct {
	indexer cache.Indexer
}

4. informer

対象となるKubernetes Objectの変更を検知して、Create, Update, Deleteに対応する処理などをする。Custom Resource作成時にcode-generatorで生成し、Custom Controller内で使われる。

// FooInformer provides access to a shared informer and lister for
// Foos.
type FooInformer interface {
	Informer() cache.SharedIndexInformer
	Lister() v1alpha1.FooLister
}

type fooInformer struct {
	factory          internalinterfaces.SharedInformerFactory
	tweakListOptions internalinterfaces.TweakListOptionsFunc
	namespace        string
}

生成 (Step by Step)

1. FooというAPI typeを定義する

mkdir code-generator-training && cd code-generator-training
git init
go mod init code-generator-training
go get k8s.io/apimachinery@v0.24.2
go get k8s.io/client-go@v0.24.2
go get k8s.io/code-generator@v0.24.2
pkg/api/example.com/v1alpha1/types.go
package v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Foo is a specification for a Foo resource
type Foo struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   FooSpec   `json:"spec"`
	Status FooStatus `json:"status"`
}

// FooSpec is the spec for a Foo resource
type FooSpec struct {
	DeploymentName string `json:"deploymentName"`
	Replicas       *int32 `json:"replicas"`
}

// FooStatus is the status for a Foo resource
type FooStatus struct {
	AvailableReplicas int32 `json:"availableReplicas"`
}

// FooList is a list of Foo resources
type FooList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []Foo `json:"items"`
}

2. code-generatorでdeepcopyを生成する

2.1. DeepCopyとDeepCopyInfoを生成するためのコメントをつける

Packageに対して生成する場合: 以下のコメントを doc.go につける

// +k8s:deepcopy-gen=package

typeごとに生成する場合: 以下のコメントをtypeにつける

// +k8s:deepcopy-gen=true

今回は、packageに対して生成

pkg/api/example.com/v1alpha1/doc.go
// +k8s:deepcopy-gen=package
// +groupName=example.com

package v1alpha1

2.2. DeepCopyInterfaceNameを生成するためのコメントをつける (Optional)

+k8s:deepcopy-gen:interfaces=<interface>をtypeにつけることで、DeepCopyInterfaceNameを生成できる

例.

// +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List

この場合 DeepCopyObjectDeepCopyListが、返り値に指定したinterfaceを返すように生成される。

もう一つは、 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.ObjectをFooとFooListの上に追加する (typeのコメントから1行開けておく)

pkg/api/example.com/v1alpha1/types.go
...
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Foo is a specification for a Foo resource
type Foo struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   FooSpec   `json:"spec"`
	Status FooStatus `json:"status"`
}
...

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// FooList is a list of Foo resources
type FooList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []Foo `json:"items"`
}

2.3. 生成する

https://github.com/kubernetes/code-generatorgenerate-groups.shを使って生成する。

git clone https://github.com/kubernetes/code-generator

generate-groups.shを使って生成する:

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"

生成:

code-generator/generate-groups.sh deepcopy code-generator-training/pkg/client code-generator-training/pkg/api example.com:v1alpha1 --go-header-file code-generator/hack/boilerplate.go.txt --output-base $(pwd)/..

pkg/api/example.com/v1alpha1/zz_generated.deepcopy.goが作成される

3. clientを生成

3.1. // +genclient コメントをつける

pkg/api/example.com/v1alpha1/types.go
package v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
...

3.2. 生成する

code-generator/generate-groups.sh client code-generator-training/pkg/client code-generator-training/pkg/api example.com:v1alpha1 --go-header-file code-generator/hack/boilerplate.go.txt --output-base $(pwd)/..

以下のファイルが生成される

pkg/client/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

6 directories, 14 files

4. listerの生成

code-generator/generate-groups.sh lister code-generator-training/pkg/client code-generator-training/pkg/api example.com:v1alpha1 --go-header-file code-generator/hack/boilerplate.go.txt --output-base $(pwd)/..

以下のファイルが生成される:

tree pkg/client/listers
pkg/client/listers
└── example.com
	└── v1alpha1
		├── expansion_generated.go
		└── foo.go

2 directories, 2 files

5. informerの生成

※informerはlisterに依存しているので、informerを生成するときはlisterを生成しておく必要がある

code-generator/generate-groups.sh informer code-generator-training/pkg/client code-generator-training/pkg/api example.com:v1alpha1 --go-header-file code-generator/hack/boilerplate.go.txt --output-base $(pwd)/..

以下のファイルが生成される

tree pkg/client/informers
pkg/client/informers
└── externalversions
	├── example.com
	│   ├── interface.go
	│   └── v1alpha1
	│       ├── foo.go
	│       └── interface.go
	├── factory.go
	├── generic.go
	└── internalinterfaces
		└── factory_interfaces.go

4 directories, 6 files

生成 (まとめて)

1. types.goを作成

pkg/api/example.com/v1alpha1/types.go
package v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// Foo is a specification for a Foo resource
type Foo struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   FooSpec   `json:"spec"`
	Status FooStatus `json:"status"`
}

// FooSpec is the spec for a Foo resource
type FooSpec struct {
	DeploymentName string `json:"deploymentName"`
	Replicas       *int32 `json:"replicas"`
}

// FooStatus is the status for a Foo resource
type FooStatus struct {
	AvailableReplicas int32 `json:"availableReplicas"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// FooList is a list of Foo resources
type FooList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []Foo `json:"items"`
}

2. doc.goを作成

pkg/api/example.com/v1alpha1/doc.go
// +k8s:deepcopy-gen=package
// +groupName=example.com

package v1alpha1

3. deepcopy,client,lister,informerすべてを生成

code-generator/generate-groups.sh all code-generator-training/pkg/client code-generator-training/pkg/api example.com:v1alpha1 --go-header-file code-generator/hack/boilerplate.go.txt --output-base $(pwd)/..

生成されたコードの使い方

生成されたdeepcopy,client,lister,informerの使い方は https://github.com/nakamasato/code-generator-training で試したので参考にしていただければと。
大体Custom Controller作成するときに出てくるので、https://github.com/kubernetes/sample-controller も参考になる。

参考資料

  1. https://pkg.go.dev/k8s.io/gengo/examples/deepcopy-gen
  2. https://github.com/kubernetes/sample-controller
  3. https://github.com/nakamasato/code-generator-training
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0