client-go 基本概念
client-go 基本概念
Client 类型
- RESTClient :最基本的客户端,提供组基本的封装
- Clientset:是一个Client 的集群,在Clientset 中包含了所有的k8s内置资源的Client,通过Clientset便可以很方便的操纵如pod、service 资源
- dynamicClient:动态客户端,可以操作任意k8s的资源,包括CRD定义的资源
- DiscoveryClient:用于发现k8s 提供的资源组、资源版本和资源信息,比如:kubectl api-resources。
代码结构:
client-go源码:https://github.com/kubernetes/client-go
client-go源码目录结构
- The
kubernetes
package contains the clientset to access Kubernetes API. - The
discovery
package is used to discover APIs supported by a Kubernetes API server. - The
dynamic
package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects. - The
transport
package is used to set up auth and start a connection. - The
tools/cache
package is useful for writing controllers. - The
rest
packages contains restclient
# tree client-go/ -L 1
client-go/
├── discovery
├── dynamic
├── informers
├── kubernetes
├── listers
├── plugin
├── rest
├── scale
├── tools
├── transport
└── util
-
discovery
:提供DiscoveryClient
发现客户端 -
dynamic
:提供DynamicClient
动态客户端 -
informers
:每种 kubernetes 资源的 Informer 实现 -
kubernetes
:提供ClientSet
客户端 -
listers
:为每一个 Kubernetes 资源提供 Lister 功能,该功能对 Get 和 List 请求提供只读的缓存数据 -
plugin
:提供 OpenStack、GCP 和 Azure 等云服务商授权插件 -
rest
:提供RESTClient
客户端,对 Kubernetes API Server 执行 RESTful 操作 -
scale
:提供ScaleClient
客户端,用于扩容或缩容 Deployment、ReplicaSet、Relication Controller 等资源对象 -
tools
:提供常用工具,例如 SharedInformer、Reflector、DealtFIFO 及 Indexers。提供 Client 查询和缓存机制,以减少向 kube-apiserver 发起的请求数等 -
transport
:提供安全的 TCP 连接,支持 Http Stream,某些操作需要在客户端和容器之间传输二进制流,例如 exec、attach 等操作。该功能由内部的 spdy 包提供支持 -
util
:提供常用方法,例如 WorkQueue 功能队列、Certificate 证书管理等
RESTClient
-
RESTClient是 client-go 最基础的客户端,主要是对HTTP Reqeust进行了封装,对外提供RESTful风格的API,并且提供丰富的API用于各种设置,相比其他几种客户端虽然更复杂,但是也更为灵活;
-
使用RESTClient对kubernetes的资源进行增删改查的基本步骤如下:
- 确定要操作的资源类型(例如查找deployment列表),去官方API文档中找到对于的path、数据结构等信息,后面会用到;
- 加载配置kubernetes配置文件(和kubectl使用的那种kubeconfig完全相同);
- 根据配置文件生成配置对象,并且通过API对配置对象就行设置(例如请求的path、Group、Version、序列化反序列化工具等);
- 创建RESTClient实例,入参是配置对象;
- 调用RESTClient实例的方法向kubernetes的API Server发起请求,编码用fluent风格将各种参数传入(例如指定namespace、资源等),如果是查询类请求,还要传入数据结构实例的指针,改数据结构用于接受kubernetes返回的查询结果;
Clientset
通过sdk里封装好的方法,对k8s里的一类资源进行操作。
ClientSet在RestClient的基础上封装了对Resouorce和Version的管理方法。
一个Resource可以理解为一个客户端,而ClientSet是多个客户端的集合
其操作资源对象时需要指定Group、指定Version,然后根据Resource获取,但是clientset不支持自定义crd(CustomResourceDefinition)。
更新configmap
configMap := v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx",
},
Data: map[string]string{
"xxx.yaml": string(yaml),
},
}
_, err = clientset.CoreV1().ConfigMaps(xxx).Update(ctx, configMap, metav1.UpdateOptions{})
DynamicClient
DynamicClient是一种动态客户端它可以对任何资源进行restful操作包括crd自定义资源,不同于 clientset,dynamic client 返回的对象是一个 map[string]interface{}
利用DynamicClient更新自定义资源
resource := schema.GroupVersionResource{Group: "xxx", Version: "v1", Resource: "xxx"}
// 先查询,有的情况下就更新,没有就创建
xxx, err := k8sProxy.DynamicClient.Resource(resource).Get(ctx, xxx, metav1.GetOptions{})
if err == nil {
if err := unstructured.SetNestedField(xxx.Object, pop.Name, "spec", "pop"); err != nil {
return err
}
_, err = k8sProxy.DynamicClient.Resource(resource).Update(ctx, xxx, metav1.UpdateOptions{})
} else if k8sErrors.IsNotFound(err) {
xxx := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "xxx/v1",
"kind": "xxx",
"metadata": map[string]interface{}{
"name": xxx,
},
"spec": map[string]interface{}{
"pop": pop.Name,
},
},
}
_, err = k8sProxy.DynamicClient.Resource(resource).Create(ctx, xxx, metav1.CreateOptions{})
}
return err
DiscoveryClient
DiscoveryClient是发现客户端,主要用于发现api server支持的资源组 资源版本 资源信息,k8s api server 支持很多资源组 资源版本,资源信息,此时可以通过DiscoveryClient来查看
kubectl的api-version和api-resource也是通过DiscoveryClient来实现的,还可以将信息缓存在本地cache,以减轻api的访问压力,默认在./kube/cache和./kube/http-cache下。
package main
import (
"flag"
"fmt"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"path/filepath"
)
func main() {
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
discoverClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
panic(err)
}
_, apiResourceList, err := discoverClient.ServerGroupsAndResources()
for _, v := range apiResourceList {
gv, err := schema.ParseGroupVersion(v.GroupVersion)
if err != nil {
panic(err)
}
for _, resource := range v.APIResources {
fmt.Println("name:", resource.Name, " ", "group:", gv.Group, " ", "version:", gv.Version)
}
}
}
Reference:
https://www.huweihuang.com/article/source-analysis/client-go-source-analysis/