github上client-go官方项目工程
以前创建和管理CRD的client库位于:https://github.com/kubernetes/apiextensions-apiserver,但是现在client-go已经支持CRD
比如定义一个目录api/types/v1alpha1,里面是关于types的一些定义文件;
metav1.ObjectMeta 类型会包含典型的任意的Kubernetes资源的metadata属性,如name, namespace, labels, annotations。
被Kubernetes API定义的所有资源对象、类型都需要实现k8s.io/apimachinery/pkg/runtime.Object这个接口定义,这个接口包含两个方法GetObjectKind() 和 DeepCopyObject():
Scheme定义了序列化和反序列化API对象的方法,用于将group、版本和类型信息转换为Go模式和从Go模式转换为Go模式的类型注册表,以及不同版本的Go模式之间的映射。
当和API Server通信的时候能够处理新的types类型的话就需要先让client能够知道有这个新的types类型存在。
AddToScheme 会利用到反射,因此新定义的types类型的结构体的命名必须要和自定义的Kind的命名(如VirtualService
)保持一致,否则会找不到对应的kind,
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
当我们定义好一个新的types类型并且添加了一个register注册方法到全局的scheme编译器后,我们就可以创建一个http client去加载我们的自定义资源了。现在就要用到client-go/rest
这个RESTClient去实现了。一般而言,为了更为安全的方式使用API,优雅的姿势是打包这些操作到clientset中,通过rest包中的RESTClientFor
方法进行相关的封装,然后再实现一些普适的interface接口,包含Get、Create、 Delete, Update 、List、Watch等通用接口方法,这个可以参考Pod client set的实现
一般优雅的姿势去操作Kubernetes的资源并实时做出响应的方案是采用client-go的informer,它的工作模式是:初始时使用List()去加载资源的所有相关实例,然后使用Watch()进行订阅更新;使用初始对象List列表和从watch订阅更新到的数据会构建一个本地缓存,该缓存可以快速访问任何自定义资源而无需每次都访问API Server。像Pod、Deployment等资源对象都是采用这种方式。
在k8s.io/client-go/tools/cache
包中提供了一个Informer方法cache.NewInformer
,这个cache.NewInformer
返回两个参数Store 和Controller:
代码生成相比于前面的手动生成的优势在于不用手动去写一些基础的deepcopy,client,informer,lister
这些方法
code-generation 也是基于client-go,因为client-go 需要实现runtime.Object interface的CustomResources类型 ,这样就要实现诸如DeepCopy深拷贝的一系列方法,code-generation 就是实现了比如深拷贝的代码生成器,关于k8s.io/code-generator,如下:
func (t* T) DeepCopy() *T
informer和lister相当于是controllers,抽象一层controllers去进行操作资源.
实际项目中,需要引入k8s.io/code-generator这个工程,然后通过一些脚本生成。一个简单的示例是github上的crd-code-generation项目,这个同时也是这篇博文 code-generation-customresources中的示例
官方的sample-controller项目也是代码生成的,并且有关于自定义资源CRD的一些操作。
pkg/apis/{Groupame}/{Version}
,如pkg/apis/networking.istio.io/v1
vendor/k8s.io/code-generator/generate-groups.sh
生成注意点:types不能有interface{} ,否则自动生成的时候会生成出错,因此其实也不建议通过代码自动生成,还是手动去编写会更好。
type VirtualServiceSpec struct {
Hosts []string `json:"hosts"`
Gateways []string `json:"gateways"`
Http interface{} `json:"http"`
}
报错如下:
/v1/zz_generated.deepcopy.go" (107:37: expected ';', found '{' (and 5 more errors)).
然后通过如下命令
generate-groups.sh <generators> <output-package> <apis-package> <groups-versions> ...
vendor/k8s.io/code-generator/generate-groups.sh all github.com/openshift-evangelists/crd-code-generation/pkg/client github.com/openshift-evangelists/crd-code-generation/pkg/apis example.com:v1 ...
可以同时指定多个输出目录
vendor/k8s.io/code-generator/generate-groups.sh all \
base-code-example/istio/crd-code-generation-service/pkg/client base-code-example/istio/crd-code-generation-service/pkg/apis \
"example.com:v1 networking.istio.io:v1" \
--go-header-file ${SCRIPT_ROOT}/hack/custom-boilerplate.go.txt
可以生成client的所有方法
优势:
deepcopy,client,informer,lister
这些方法,这个相对来说是通用的,各个CRD都要实现一套劣势:
试想一下,istio中的资源、对象都是Kubernetes的CRDs,那么必然,istio中肯定有处理好Kubernetes CRD的方式,我们知道目前都是采用client-go,那么istio中必然会有大量的client-go的引用和使用,通过源码可以发现确实如此并且都是采用RESTClient,clientset是包含RESTClient的。
在源码路径/Users/meitu/Documents/work_Meitu/goDev/Applications/src/istio.io/istio/pilot/pkg/config/kube/crd
中就是相关CRD的处理,然后/Users/meitu/Documents/work_Meitu/goDev/Applications/src/istio.io/istio/pilot/pkg/config/kube/crd/types.go
是istio中所有一些常用资源的定义如DestinationRule、Gateway、VirtualService等。这样的话,我们自己要通过client-go去实现后端服务,去开发的话,就可以参考istio源码中的一些定义和基本方法,然后结合client-go的一般性处理去实现后端服务程序。
Accessing Kubernetes CRDs from the client-go package
Kubernetes Deep Dive: Code Generation for CustomResources
k8s.io/code-generator
官方的sample-controller项目
github上的crd-code-generation项目