• controllertool的简单使用


    介绍

    在上一篇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
    
  • 相关阅读:
    Arduino通信篇系列之print()和write()输出方式的差异
    通信协议之Modbus协议(一)
    CAD制图系列一之绘图、标注、修改、视图
    Arduino系列之pwm控制LED灯(呼吸灯)
    [转]GDB调试基础
    Linux上编辑然后执行一段脚本的机制
    [转]进程创建-终结流程图
    [ 转]Linux进程关系
    Linux进程管理(四、 进程终结)
    Linux进程管理(三、 线程)
  • 原文地址:https://www.cnblogs.com/huiyichanmian/p/16261635.html
Copyright © 2020-2023  润新知