client-go提供了四种与Kubernetes APIServer交互的客户端:RESTClient、DiscoveryClient、ClientSet、DynamicClient。 经过学习之后,我感觉这个东西还是蛮不复杂的,以下是这四种客户端获取所有Pods的demo,然后感受一下他们的区别。
运行在下面的四个代码时,需要准备好kubeconfig,就是~/.kube/config这个文件,可以从服务器上拷到本地上。或者直接放在服务器上跑这些代码。
RESTClient
RESTClient是一个最基础的client,他是其他三种client的底层,也就是说,其他三种client都是封装的它。所以操作RESTClient会感觉比较原始。我们
go
import (
"context"
"flag"
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/scheme"
"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.Error())
}
config.APIPath = "api"
// 设置 corev1 groupVersion
config.GroupVersion = &corev1.SchemeGroupVersion
// 设置解析器,用于用于解析 scheme
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
// 初始化 RESTClient
restClient, err := rest.RESTClientFor(config)
if err != nil {
panic(err)
}
list := &corev1.PodList{}
// namespace为空,就返回所有namespace中的资源
err = restClient.Get().Namespace("").Resource("pods").Do(context.TODO()).Into(list)
if err != nil {
panic(err)
}
for _, item := range list.Items {
fmt.Printf("ns:%s , pod:%s\n", item.Namespace, item.Name)
}
}
ClientSet
ClientSet他是用来操作K8s内置资源的,底层给每一种资源封了RESTClient,如果想操作CRD,需要自己定义ClientSet。
go
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()
// 从kubeconfig中获取配置
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// 从配置中获得clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
for _, item := range pods.Items {
fmt.Printf("ns:%s , pod:%s\n", item.Namespace, item.Name)
}
}
其实最后来时落到了这里,所以他是帮我们把一些操作封了一下。
go
func (c *pods) List(ctx context.Context, opts metav1.ListOptions) (result *v1.PodList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.PodList{}
err = c.client.Get().
Namespace(c.ns).
Resource("pods").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
DynamicClient
动态client的就是比较动态,然后他可以操作CRD,但是他返回的内容是map
go
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()
// 从kubeconfig中获取配置
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// 因为是动态调用,不需要操作哪个资源,所以需要自己提供
gvr := schema.GroupVersionResource{
Group: "",
Version: "v1",
Resource: "pods",
}
result, err := dynamicClient.Resource(gvr).Namespace("").List(context.TODO(), meta_v1.ListOptions{})
podList := &corev1.PodList{}
// 将结果解析到 podList scheme 中
err = runtime.DefaultUnstructuredConverter.FromUnstructured(
result.UnstructuredContent(), podList)
for _, item := range podList.Items {
fmt.Printf("ns: %s,pod: %s\n", item.Namespace, item.Name)
}
}
我们这里把的结构化数据转为了结构化数据。
DiscoveryClient
发现客户端是用来用于发现 Kube-apiserver 支持的资源组、资源版本、资源类型等。 通过DiscoveryClient发现所有gvr
go
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()
// 从kubeconfig中获取配置
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// 初始化 DiscoveryClient
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
panic(err.Error())
}
// 获取集群所有资源
_, apiResourceList, err := discoveryClient.ServerGroupsAndResources()
if err != nil {
panic(err.Error())
}
for _, resources := range apiResourceList {
gv, err := schema.ParseGroupVersion(resources.GroupVersion)
if err != nil {
panic(err.Error())
}
for _, resource := range resources.APIResources {
fmt.Printf("group: %s, version: %s, resource: %s\n", gv.Group, gv.Version, resource.Name)
}
}
}