K8s-Client-go:四种客户端

概述

ClientSet、DynamicClient、DiscoveryClient. —> RESTClient —> kubeconfig

其实,前面三种都是依赖于 RESTClient

  • RESTClient:就是对HTTP Client进行了封装,实现了RESTful风格的API。

  • ClientSet:在RESTClient之上封装了ResourceVersion的管理方法,ClientSet只能访问K8s内置的资源,不能访问CRD资源,它是通过client-gen代码生成器生成的

  • DynamicClient:比ClientSet多一个支持CRD资源

  • DiscoveryClient:用于发现kube-apiserver所支持的资源组、资源版本、资源信息(Group、Version、Resource)

kubeconf文件

kubeconf文件存储了集群、用户、命名空间和身份验证等信息。

  • clusters:集群信息
  • users:K8s机器用户的客户端凭证
  • contexts:定义K8s集群,用户信息和命名空间

读取kubeconfig文件配置:

  1. 文件路径,(rules.ExplicitPath)
  2. 环境变量,(KUBECONFIG)

位置:/K8s-sig/tools/clientcmd/load.go

RESTClient

RESTClient基于HTTP Request进行封装,实现了RESTFul风格的API,很灵活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main

import (
"context"
"flag"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"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)
if err != nil {
panic(err)
}

// path: /api/v1/namespaces/{namespace}/pods
config.APIPath = "api"
// pod的Group是空字符串
config.GroupVersion = &corev1.SchemeGroupVersion
// 指定序列化工具
config.NegotiatedSerializer = scheme.Codecs

// 创建RESTClient实例
restClient, err := rest.RESTClientFor(config)
if err != nil {
panic(err)
}
// 存放podList
res := &corev1.PodList{}
namespace := "kube-system"
err = restClient.Get().Namespace(namespace).
// 请求资源
Resource("pods").
// 指定大小限制和序列化工具
VersionedParams(&metav1.ListOptions{Limit: 100}, scheme.ParameterCodec).
Do(context.TODO()).
// 结果存放
Into(res)
if err != nil {
panic(err)
}
for _, item := range res.Items {
fmt.Printf("%v\t %v\t %v\n",
item.Namespace,
item.Status.Phase,
item.Name)
}

}

ClientSet

基于RESTClinet,封装了对ResourceVersion的抽象,通过代码生成器实现对K8s内置资源的管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"context"
"flag"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"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)
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
pod, err := clientset.CoreV1().Pods("default").Get(context.TODO(), "", metav1.GetOptions{})
if err != nil {
panic(err)
}
fmt.Println(pod)
}

DynamicClient

动态客户端,跟ClientSet一样,但是支持了CRD资源。

DynamicClient不是类型安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package main

import (
"context"
"flag"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"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)
if err != nil {
panic(err)
}
// 实例化对象
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err)
}

// 使用scheme的包带入gvr
deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
deploymentName := "ss"
replicas := 1
image := "nginx"
//定义结构化数据
deploymnet := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": deploymentName,
},
"spec": map[string]interface{}{
"replicas": replicas,
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app": "demo",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "demo",
},
},
"spec": map[string]interface{}{
"containers": []map[string]interface{}{
{
"name": "web",
"image": image,
"ports": []map[string]interface{}{
{
"name": "http",
"protocol": "TCP",
"containerPort": 80,
},
},
},
},
},
},
},
},
}
create, err := dynamicClient.Resource(deploymentRes).Namespace("default").Create(context.TODO(), deploymnet, metav1.CreateOptions{})
if err != nil {
panic(err)
}
fmt.Println(create)
}

DiscoveryClient

主要用于发现K8s API Server所支持的资源组、资源版本、资源信息。

DiscoveryClient通过ReESTFulClient请求/api接口,请求数据存放在metav1.APIVersion结构体中,然后通过RESTClient请求/apis接口,请求结果放在metav1.APIGroupList中。

本地缓存默认存放~/.kube/cache~/.kube/http-cache。缓存可以减轻client-go对K8s API Server的访问。默认每10min与K8s API Server进行同步。

DiscoveryClient 获取,如果缓存中没有,才回去从K8s-API Server获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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)
if err != nil {
panic(err)
}

// 新建discoveryClient
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
panic(err)
}
// 获取所有的分组和资源数据
apiGroups, APIResourceListSlice, err := discoveryClient.ServerGroupsAndResources()
if err != nil {
panic(err)
}
fmt.Printf("APIGroup:\n\n %v\n\n", apiGroups)
for _, resourceList := range APIResourceListSlice {
version := resourceList.GroupVersion
fmt.Printf("%s", version)

//把字符串转换为数据结构
groupVersion, err := schema.ParseGroupVersion(version)
if err != nil {
panic(err)
}
fmt.Printf("%v", groupVersion)

}

}