controller-tool的简单使用


介绍

在上一篇code-generator简单介绍中重点介绍了如何使用code-generator来自动生成代码,通过自动生成的代码可以帮助我们像访问k8s内置资源那样来操作我们的CRD,其实就是帮助我们生成ClientSet、Informer、Lister等工具包。

但是我们需要自己定义types.go文件以及需要自己去编写crd文件。工作量其实也是很大的,那么有没有工具像code-generator那样帮助我们生成代码呢?答案是肯定的,那就是接下来要介绍的controller-tools

controller-tools

controller-tools主要可以帮我们自动生成types.go所需要的内容以及自动帮我们生成crd。

同样首先将其clone到本地:

$ git clone https://github.com/kubernetes-sigs/controller-tools.git 

在项目的cmd目录下,我们可以看到有controller-genhelpgentype-scaffold三个工具。

其中type-scaffold可以用来生成我们需要的types.go文件,controller-gen可以生成zz_xxx.deepcopy.go文件以及crd文件。

我们使用go install进行安装:

$ cd controller-gen $ go install ./cmd/{controller-gen,type-scaffold} 

安装完成后我们可以去GOPATH下的bin目录下查看。

controller-tool的简单使用

接着我们就可以新建一个项目,来使用controller-tools提供的工具为我们自动生成代码了。

$ mkdir controller-test && cd controller-test $ go mod init controller-test $ mkdir -p pkg/apis/example.com/v1 $ tree . ├── go.mod └── pkg     └── apis         └── example.com             └── v1  4 directories, 1 file 

接下来我们就可以使用工具来生成我们所需要的代码了,首先我们生成types.go所需要的内容,由于type-scaffold不支持导入文本,所以生成后我们需要复制到types.go文件中:

$ type-scaffold --kind Foo // FooSpec defines the desired state of Foo type FooSpec struct {         // INSERT ADDITIONAL SPEC FIELDS -- desired state of cluster }  // FooStatus defines the observed state of Foo. // It should always be reconstructable from the state of the cluster and/or outside world. type FooStatus struct {         // INSERT ADDITIONAL STATUS FIELDS -- observed state of cluster }  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object  // Foo is the Schema for the foos API // +k8s:openapi-gen=true type Foo struct {         metav1.TypeMeta   `json:",inline"`         metav1.ObjectMeta `json:"metadata,omitempty"`          Spec   FooSpec   `json:"spec,omitempty"`         Status FooStatus `json:"status,omitempty"` }  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object  // FooList contains a list of Foo type FooList struct {         metav1.TypeMeta `json:",inline"`         metav1.ListMeta `json:"metadata,omitempty"`         Items           []Foo `json:"items"` }  

然后在types.go文件中将import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"添加上就行。

当然自动生成只是一个模版,里面的具体细节还是需要我们自己去填写,比如我们填充FooSpec

资源类型定义好了,那么如何能让client-go识别我们的资源呢,这里就需要其注册进去。我们可以在register.go中定义GV(Group Version),以及通过标签指定groupName。

// register.go  // +groupName=example.com  package v1  import ( 	"k8s.io/apimachinery/pkg/runtime" 	"k8s.io/apimachinery/pkg/runtime/schema" 	"k8s.io/apimachinery/pkg/runtime/serializer" )  var ( 	Scheme       = runtime.NewScheme() 	GroupVersion = schema.GroupVersion{ 		Group:   "example.com", 		Version: "v1", 	} 	Codec = serializer.NewCodecFactory(Scheme) ) 

types.go中调用Scheme.AddKnownTypes方法即可:

// types.go  package v1  import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"  // FooSpec defines the desired state of Foo type FooSpec struct { 	// INSERT ADDITIONAL SPEC FIELDS -- desired state of cluster 	Name     string `json:"name"` 	Replicas int32  `json:"replicas"` }  // FooStatus defines the observed state of Foo. // It should always be reconstructable from the state of the cluster and/or outside world. type FooStatus struct { 	// INSERT ADDITIONAL STATUS FIELDS -- observed state of cluster }  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object  // Foo is the Schema for the foos API // +k8s:openapi-gen=true type Foo struct { 	metav1.TypeMeta   `json:",inline"` 	metav1.ObjectMeta `json:"metadata,omitempty"`  	Spec   FooSpec   `json:"spec,omitempty"` 	Status FooStatus `json:"status,omitempty"` }  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object  // FooList contains a list of Foo type FooList struct { 	metav1.TypeMeta `json:",inline"` 	metav1.ListMeta `json:"metadata,omitempty"` 	Items           []Foo `json:"items"` }  func init() { 	Scheme.AddKnownTypes(GroupVersion, &Foo{}, &FooList{}) } 

接下来就需要生成deepcopy.go文件了:

$ controller-gen object paths=./pkg/apis/example.com/v1/types.go 

同样,我们使用controller-gen生成crd:

$ mkdir config $ go mod tidy $ controller-gen crd paths=./... output:crd:dir=config/crd 

这时候我们查看项目结构:

. ├── config │   └── crd │       └── example.com_foos.yaml ├── go.mod ├── go.sum └── pkg     └── apis         └── example.com             └── v1                 ├── register.go                 ├── types.go                 └── zz_generated.deepcopy.go  6 directories, 6 files 

最后我们来进行验证,首先创建一个cr:

apiVersion: example.com/v1 kind: Foo metadata:   name: crd-test spec:   name: test   replicas: 2 

将crd和cr添加到集群后,我们来编写main.go文件来进行验证:

package main  import ( 	"context" 	v1 "controller-test/pkg/apis/example.com/v1" 	"fmt" 	"k8s.io/client-go/rest" 	"k8s.io/client-go/tools/clientcmd" 	"log" )  func main() { 	config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile) 	if err != nil { 		log.Fatalln(err) 	} 	// 这边需要使用原始的 RESTClient  	config.APIPath = "/apis/" 	config.NegotiatedSerializer = v1.Codec 	config.GroupVersion = &v1.GroupVersion  	client, err := rest.RESTClientFor(config) 	if err != nil { 		log.Fatalln(err) 	}  	foo := &v1.Foo{} 	err = client.Get().Namespace("default").Resource("foos").Name("crd-test").Do(context.TODO()).Into(foo) 	if err != nil { 		log.Fatalln(err) 	}  	newObj := foo.DeepCopy() 	newObj.Spec.Name = "test2" 	fmt.Println(foo.Spec.Name) 	fmt.Println(newObj.Spec.Name) }  //======= // 输出结果 test test2 
发表评论

相关文章

当前内容话题