自动生成代码controller tool的简单使用

2022-07-15,,,,

介绍

在上一篇中重点介绍了如何使用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-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

以上就是自动生成代码controller tool的简单使用的详细内容,更多关于自动生成代码controller tool的资料请关注其它相关文章!

《自动生成代码controller tool的简单使用.doc》

下载本文的Word格式文档,以方便收藏与打印。