A client – go

Recently, there is a need to carry out custom integration of some data of K8S. Client-go can be used to realize the demand quickly and conveniently. In K8S operation and maintenance, we can use Kubectl, client library or REST request to access K8S API. In fact, both Kubectl and the client libraries are tools that encapsulate REST requests. As a client library, client-go can invoke THE K8S API to add, delete, modify, and check resource objects (including Deployment, service, Ingress, replicaSet, POD, Namespace, and node) in the K8S cluster.

The introduction of

Chart 2.1

As can be seen from the figure above, there are four types of clients in client-GO, ClientSet, DynamicClient and DiscoveryClient, which are all concrete implementations of RestClient.

2.2 Directory Structure

# tree client-go/ -L 1
client-go/
  ├ ─ ─ discovery
  ├ ─ ─ dynamic
  ├ ─ ─ informers
  ├ ─ ─ kubernetes
  ├ ─ ─ listers
  ├ ─ ─ plugin
  ├ ─ ─ rest
  ├ ─ ─ scale
  ├ ─ ─ tools
  ├ ─ ─ transport
  └ ─ ─ util
Copy the code
  • discovery: provideDiscoveryClientDiscovering clients
  • dynamic: provideDynamicClientDynamic client
  • informers: Informer implementation of each Kubernetes resource
  • kubernetes: provideClientSetThe client
  • listers: Provides Lister functionality for each Kubernetes resource, which provides read-only cached data for Get and List requests
  • plugin: Provides plug-ins for OpenStack, GCP, and Azure
  • rest: provideRESTClientOn the client, RESTful operations are performed on the Kubernetes API Server
  • scale: provideScaleClientThe client is used to expand or shrink Deployment, ReplicaSet, and RelasController resource objects
  • tools: Provides common tools such as SharedInformer, Reflector, DealtFIFO, and Indexers. Provide Client query and caching mechanism to reduce the number of requests to kube-Apiserver, etc
  • transport: Provides secure TCP connections and supports Http Stream. Some operations require transferring binary streams between the client and the container, such as exec and ATTACH. This functionality is supported by the internal SPDY package
  • util: Provides common methods, such as WorkQueue and Certificate management

Three certification

It is worth mentioning here that there is a small hole when go mod connects to K8S through go Client. That is, we need to specify the K8S version in the Go mod file, otherwise the latest K8S version package will be pulled by default. We also know that the API of different K8S versions will be different

3.1 certified

3.1.1 token

# APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o # jsonpath='{.data.token}' | base64 --decode )
# curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
Copy the code

Four types of client-go

4.1 the RestClient

RestClient is the most basic client. RestClient is encapsulated based on HTTP Request and implements restful API. You can directly pass the restful methods provided by RestClient, such as Get(), Put(), Post(), Delete() interacts with Json and Protobuf, supports all native resources and CRDs, but generally, for more elegant processing, you need to further encapsulate RESTClient through Clientset, and then provide interfaces and services externally.

package main

import (
	"fmt"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var configFile = ".. /config"
var ApiPath = "api"
var nameSpace = "kube-system"
var resouce = "pods"

func main(a) {
	/ / generated config
	config, err := clientcmd.BuildConfigFromFlags("", configFile)
	iferr ! =nil {
		panic(err)
	}
	config.APIPath = ApiPath
	config.GroupVersion = &corev1.SchemeGroupVersion
	config.NegotiatedSerializer = scheme.Codecs

	/ / generated restClient
	restClient, err := rest.RESTClientFor(config)
	iferr ! =nil {
		panic(err)
	}
	// Declare an empty structure
	rest := &corev1.PodList{}
	if err = restClient.Get().Namespace(nameSpace).Resource("pods").VersionedParams(&metav1.ListOptions{Limit: 500}, scheme.ParameterCodec).Do().Into(rest); err ! =nil {
		panic(err)
	}
	for _, v := range rest.Items {
		fmt.Printf("NameSpace: %v Name: %v Status: %v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}
Copy the code

4.2 ClientSet

A Resource can be understood as a client, while a ClientSet is a collection of multiple clients

To operate a Resource object, clientSet needs to specify a Group, specify a Version, and then obtain it based on the Resource. However, ClientSet does not support custom CRDS.

package main

import (
	"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"
)

// ~/.kube/config
func ParseConfig(configPath string) (*kubernetes.Clientset, error) {
	var kubeconfigPath *string
	ifhome := homedir.HomeDir(); home ! ="" {
		kubeconfigPath = flag.String("kubeconfig", filepath.Join(home, ".kube"."config"), "(optional) absolute path to the kubeconfig file")}else {
		kubeconfigPath = flag.String("kubeconfig", configPath, "absolute path to the kubeconfig file")
	}
	flag.Parse()
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfigPath)
	iferr ! =nil {
		return nil, err
	}
	/ / generated clientSet
	clientSet, err := kubernetes.NewForConfig(config)
	iferr ! =nil {
		return clientSet, err
	}
	return clientSet, nil
}

func ListCm(c *kubernetes.Clientset, ns string) error {
	configMaps, err := c.CoreV1().ConfigMaps(ns).List(metav1.ListOptions{})
	iferr ! =nil {
		return err
	}
	for _, cm := range configMaps.Items {
		fmt.Printf("configName: %v, configData: %v \n", cm.Name, cm.Data)
	}
	return nil
}

func ListNodes(c *kubernetes.Clientset) error {
	nodeList, err := c.CoreV1().Nodes().List(metav1.ListOptions{})
	iferr ! =nil {
		return err
	}
	for _, node := range nodeList.Items {
		fmt.Printf("nodeName: %v, status: %v", node.GetName(), node.GetCreationTimestamp())
	}
	return nil
}

func ListPods(c *kubernetes.Clientset, ns string) {
	pods, err := c.CoreV1().Pods(ns).List(metav1.ListOptions{})
	iferr ! =nil {
		panic(err)
	}
	for _, v := range pods.Items {
		fmt.Printf("namespace: %v podname: %v podstatus: %v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}

func ListDeployment(c *kubernetes.Clientset, ns string) error {
	deployments, err := c.AppsV1().Deployments(ns).List(metav1.ListOptions{})
	iferr ! =nil {
		return err
	}
	for _, v := range deployments.Items {
		fmt.Printf("deploymentname: %v, available: %v, ready: %v", v.GetName(), v.Status.AvailableReplicas, v.Status.ReadyReplicas)
	}
	return nil
}

func main(a) {
	var namespace = "kube-system"
	configPath := ".. /config"
	config, err := ParseConfig(configPath)
	iferr ! =nil {
		fmt.Printf("load config error: %v\n", err)
	}
	fmt.Println("list pods")
	ListPods(config, namespace)
	fmt.Println("list cm")
	iferr = ListCm(config, namespace); err ! =nil {
		fmt.Printf("list cm error: %v", err)
	}
	fmt.Println("list nodes")
	iferr = ListNodes(config); err ! =nil {
		fmt.Printf("list nodes error: %v", err)
	}
	fmt.Println("list deployment")
	iferr = ListDeployment(config, namespace); err ! =nil {
		fmt.Printf("list deployment error: %v", err)
	}
}
Copy the code

4.3 DynamicClient

DynamicClient is a dynamic client that can perform restful operations on any resource including CRD custom resources. Unlike clientset, dynamic Client returns a map[string]interface{}. If you need to control all the apis in one controller, you can use the Dynamic Client, which is currently used in the Garbage Collector and namespace Controller. DynamicClient converts a Resource, such as a Podlist, to an unstructured type. All resources in k8s can be converted to this type and then converted to a Podlist. The entire transformation process is similar to the interface transformation through the assertion of interface{}.

Dynamic Client is a Dynamic client, which can handle all kubernetes resources, only support JSON.

package main

import (
	"fmt"
	apiv1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/tools/clientcmd"
)

var namespace = "kube-system"

func main(a) {

	config, err := clientcmd.BuildConfigFromFlags("".".. /config")
	iferr ! =nil {
		panic(err)
	}

	dynamicClient, err := dynamic.NewForConfig(config)
	iferr ! =nil {
		panic(err)
	}
	// Define group version resources
	gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
	unStructObj, err := dynamicClient.Resource(gvr).Namespace(namespace).List(metav1.ListOptions{})
	iferr ! =nil {
		panic(err)
	}
	podList := &apiv1.PodList{}

	iferr = runtime.DefaultUnstructuredConverter.FromUnstructured(unStructObj.UnstructuredContent(), podList); err ! =nil {
		panic(err)
	}

	for _, v := range podList.Items {
		fmt.Printf("namespaces:%v name:%v status:%v \n", v.Namespace, v.Name, v.Status.Phase)
	}
}
Copy the code

4.4 DiscoveryClient

The DiscoveryClient is used to discover resource groups and resource versions supported by the API Server. The K8S API Server supports many resource groups and resource versions. In this case, you can use the DiscoveryClient to view resource information

Kubectl api-version and api-resource are also implemented through the DiscoveryClient, and the information can be cached in the local cache to reduce the API access pressure. The default values are./kube/cache and./kube/http-cache.

package main

import (
	"fmt"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/tools/clientcmd"
)

func main(a) {
	config, err := clientcmd.BuildConfigFromFlags("".".. /config")
	iferr ! =nil {
		panic(err)
	}
	discoverClient, err := discovery.NewDiscoveryClientForConfig(config)
	iferr ! =nil {
		panic(err)
	}
	_, apiResourceList, err := discoverClient.ServerGroupsAndResources()
	for _, v := range apiResourceList {
		gv, err := schema.ParseGroupVersion(v.GroupVersion)
		iferr ! =nil {
			panic(err)
		}
		for _, resource := range v.APIResources {
			fmt.Println("name:", resource.Name, ""."group:", gv.Group, ""."version:", gv.Version)
		}
	}

}

Copy the code

Five other

Learn client-GO, which can be used to operate k8S cluster resources conveniently. Kubeconfig →rest.config→clientset→ specific client(CoreV1Client)→ specific resource object (POD)→RESTClient→ HTTP.Client→HTTP request sending and response

Through the clientset of different clients and different resource objects in the client method to achieve kubernetes resource objects in the addition, deletion, change and query operations, Common clients include CoreV1Client, AppsV1beta1Client, ExtensionsV1beta1Client and so on.

In this paper, simple use of client-Go to achieve simple K8S resource operations, later use such as KubeBuilder and operator-SDK to write operator also needs in-depth understanding and learning of client-go. In the later stage, I will continue to study in depth.

Refer to the link

  • www.voidking.com/dev-k8s-cli…
  • Godoc.org/k8s.io/clie…
  • Github.com/kubernetes/…
  • PKG. Go. Dev/k8s. IO/clie…
  • Zhuanlan.zhihu.com/p/202611841…