controller

介绍

在上一篇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目录下查看。

image

接着我们就可以新建一个项目,来使用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 

商匡云商
Logo
注册新帐户
对比商品
  • 合计 (0)
对比
0
购物车