Welcome to my GitHub

Github.com/zq2599/blog…

Content: All original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc.

Links to series of articles

  1. Client-go one of the actual combat: preparation work
  2. Client-go practical two :RESTClient
  3. Client-go combat three: Clientset
  4. Client – Go: dynamicClient
  5. Client-go Combat 5: DiscoveryClient

This paper gives an overview of

  • This article is the fourth part of the “Client-Go Combat” series. In the previous part, we have learned the Clientset client. We find that Clientset is very convenient for deployment, service and other kubernetes built-in resources, each resource has its own method. With official API documents and data structure definitions, it is more efficient to develop than Restclient.
  • But what if you’re dealing with something other than kubernetes’ built-in resources? For example, in CRD, Clientset code does not have any user-defined things, so Clientset is not used. This is where dynamicClient comes in.

Relevant knowledge reserve

  • Before learning dynamicClient, there are two important things to know: object. runtime and Unstructured. They are important to kubernetes as a whole.

Object.runtime

  • Before we talk about object. runtime, we need to clarify two concepts: When you create a Deployment instance in Kubernetes, the new Deployment instance is a resource object.
  • In kubernetes’ code world, resource objects correspond to concrete data structures that implement the same interface called object.Runtime, Source location is staging/SRC/k8s. IO/apimachinery/PKG/runtime/interfaces. Go, defined as follows:
type Object interface {
	GetObjectKind() schema.ObjectKind
	DeepCopyObject() Object
}
Copy the code
  • The DeepCopyObject method, as the name implies, is a deep copy, that is, an object in memory is cloned into a new object;
  • As for the GetObjectKind method, you should have guessed: when handling a variable of type Object.runtime, just call the GetObjectKind method to know its identity (such as Deployment, service, etc.).
  • Finally, resource objects are implementations of object. runtime;

Unstructured

  • Before we talk about Unstructured, let’s look at a simple JSON string:
{
	"id": 101."name": "Tom"
}
Copy the code
  • The above JSON field names and field value types are fixed, so you can write a data structure to handle it:
type Person struct {
	ID int
	Name String
}
Copy the code
  • The JSON strings above are Structured Data, which should make sense;
  • The opposite of structured Data is Unstructured Data. In a real Kubernetes environment, you might see some Data with unpredictable structure. For example, there is a third field in the preceding JSON string, and the content and type of the field value are not known at the encoding time. You don’t know that until you actually run it, so what do you do when you code it? In fact, client-go does the same thing. Take a look at the source code for Unstructured data structures. Path is the staging/SRC/k8s. IO/apimachinery/PKG/apis/meta/v1 / unstructured/unstructured. Go:
type Unstructured struct {
	// Object is a JSON compatible map with string, float, int, bool, []interface{}, or
	// map[string]interface{}
	// children.
	Object map[string]interface{}}Copy the code
  • Obviously, the above data structure definition does not play a role. What is really important is the method of association. As shown in the figure below, client-GO has prepared rich methods for Unstructured data, with which you can flexibly deal with Unstructured data:

Important knowledge: the transformation between Unstructured and resource objects

  • Here’s another very important point: Unstructured instances can be used to generate resource objects, and Unstructured instances can be used to generate Unstructured instances. This magical ability is realized by the FromUnstructured and ToUnstructured methods of unstructuredConverter, respectively. The following code snippet shows how to turn an Unstructured instance into a PodList instance:
// Instantiate a PodList data structure to receive the result of the transformation from unstructObj
podList := &apiv1.PodList{}

// unstructObj
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList)
Copy the code
  • In case you’re wondering how the FromUnstructured method performs the transformation, let’s take a look at the inner implementation of the method, as shown in the figure below. It’s no surprise that the reflection gives you the field information of the podList:

  • Is this the end of the Unstructured analysis? No, I highly recommended you go to the fromUnstructured method in red box 2 above to see the details. It’s very nice. For example, podList is a data structure, but fromUnstructured only works with primitive types. For data structures, the structFromUnstructured method is called, in the structFromUnstructured method

Each field of the data structure is called fromUnstructured. This process iterates through each other, and eventually, no matter how many data structures are nested in the podList, it will be processed. The following is some key code:

  • Summary: The routine of converting an Unstructured resource object into a resource object is not mysterious. It is to use reflection to obtain the field type of the resource object, then use reflection to obtain the original data from the Unstructured map according to the field name, and then use reflection to set the data in the field of the resource object.
  • With that done, it’s time to return to the main topic of this article: the dynamicClient client

About dynamicClient

  • The data structure of deployment and POD resources is clear and fixed, which can accurately correspond to the data structure and method in Clientset. However, for CRD (user defined resource), Clientset client cannot do anything. In this case, a data structure is needed to host the data of resource objects. There has to be a way to process the data;
  • At this point, the previously mentioned Unstructured objects can come into play. Yes, Unstructured objects can be hosted by the Clientset. Let’s look at the relationship between dynamicClient and Unstructured objects:
  • First look at the data structure definition, which is not different from the clientset, only the restClient field:
type dynamicClient struct {
	client *rest.RESTClient
}
Copy the code
  • This data structure has only one associated method, Resource, which takes GVR and returns another data structure, dynamicResourceClient:
func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
	return &dynamicResourceClient{client: c, resource: resource}
}
Copy the code
  • DynamicResourceClient = dynamicResourceClient = dynamicResourceClient = dynamicResourceClient = dynamicResourceClient DynamicClient does all resource related operations by dynamicResourceClient. The serialization and deserialization are given to the Unstructured UnstructuredJSONScheme, and the interaction with Kubernetes is given to Restclient:

  • Summary:
  1. Unlike Clientset, dynamicClient provides a unified API for all types of resources that are wrapped in Unstructured data structures.
  2. Restclient is used internally to interact with Kubernetes;
  • This is the introduction and analysis of dynamicClient, and we can start to practice.

Need to confirm

  • The requirements of this coding practice are very simple: query all pods under the specified namespace, and then print out in the console, requiring dynamicClient implementation;
  • You may ask: Pod is a built-in kubernetes resource, which is more suitable for Clientset operations, whereas dynamicClient is more suitable for CRD operations, isn’t it? — We use POD instead of CRD because CRD is too troublesome. We need to publish it on Kubernetes after we define it, so we use POD instead of CRD. Can deal with all kinds of resources in the future;

Download the source code

  • This actual source code can be downloaded from GitHub, address and link information as shown in the following table (github.com/zq2599/blog…
The name of the link note
Project home page Github.com/zq2599/blog… The project’s home page on GitHub
Git Repository address (HTTPS) Github.com/zq2599/blog… The project source repository address, HTTPS protocol
Git Repository address (SSH) [email protected]:zq2599/blog_demos.git The project source warehouse address, SSH protocol
  • There are multiple folders in the Git project. Client-go-related applications are in the client-go-tutorials folder, as shown in the red box below:

  • There are multiple subfolders under the client-go-tutorials folder. The corresponding source code of this article is under the DynamicClientDemo directory, as shown in the red box below:

coding

  • Create a new folder dynamicClientDemo and run the following command to create a new module:
go mod init dynamicclientdemo
Copy the code
  • Add k8s. IO/API and k8s. IO /client-go dependencies, note that the version matches the Kubernetes environment:
Go get k8s. IO /[email protected] Go get k8s. IO /[email protected]Copy the code
  • Create a new main.go with the following content. We’ll talk about the important things to notice later:
package main

import (
	"context"
	"flag"
	"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"
	"k8s.io/client-go/util/homedir"
	"path/filepath"
)

func main(a) {

	var kubeconfig *string

	// home is the home directory and can be used as the default value if it is available
	ifhome:=homedir.HomeDir(); home ! ="" {
		// If the kubeconfig parameter is entered, the value of this parameter is the absolute path to the Kubeconfig file.
		// If the kubeconfig parameter is not entered, use the default path ~/.kube/config
		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube"."config"), "(optional) absolute path to the kubeconfig file")}else {
		// If the current user's home directory is not available, there is no way to set the default kubeconfig directory
		kubeconfig = flag.String("kubeconfig".""."absolute path to the kubeconfig file")
	}

	flag.Parse()

	// Load the kubeconfig configuration file from the native, so the first argument is an empty string
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)

	// Kubeconfig failed to load
	iferr ! =nil {
		panic(err.Error())
	}

	dynamicClient, err := dynamic.NewForConfig(config)

	iferr ! =nil {
		panic(err.Error())
	}

	// The input parameter required for the unique association method of dynamicClient
	gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}

	// Use the query list method of dynamicClient to query all pods in the namespace specified.
	// Note that the data structure type returned by this method is UnstructuredList
	unstructObj, err := dynamicClient.
		Resource(gvr).
		Namespace("kube-system").
		List(context.TODO(), metav1.ListOptions{Limit: 100})

	iferr ! =nil {
		panic(err.Error())
	}

	// Instantiate a PodList data structure to receive the result of the transformation from unstructObj
	podList := &apiv1.PodList{}

	/ / conversion
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList)

	iferr ! =nil {
		panic(err.Error())
	}

	/ / headers
	fmt.Printf("namespace\t status\t\t name\n")

	// Each POD prints the namespace, status.Phase, and name fields
	for _, d := range podList.Items {
		fmt.Printf("%v\t %v\t %v\n",
			d.Namespace,
			d.Status.Phase,
			d.Name)
	}
}
Copy the code
  • There are three important things to note in this code:
  1. The Resource method specifies the type of Resource for this operation.
  2. The List method makes a request to Kubernetes;
  3. FromUnstructured turns Unstructured data structures into Podlists, the principle of which was analyzed earlier;
  • Go run main.go, as follows, gets data from Kubernetes and converts it to a PodList:
zhaoqin@zhaoqindeMBP-2 dynamicclientdemo % go run main.go
namespace        status          name
kube-system      Running         coredns-7f89b7bc75-5pdwc
kube-system      Running         coredns-7f89b7bc75-nvbvm
kube-system      Running         etcd-hedy
kube-system      Running         kube-apiserver-hedy
kube-system      Running         kube-controller-manager-hedy
kube-system      Running         kube-flannel-ds-v84vc
kube-system      Running         kube-proxy-hlppx
kube-system      Running         kube-scheduler-hedy
Copy the code
  • So far, the learning and practical application of dynamicClient have been completed. DynamicClient is a real dynamicClient tool, and it uses a set of API to handle all resources. In addition to breaking through the built-in resource limits of Clientset, it also makes our business code more flexible. Helps you write code that better matches the scenario;

You are not alone. Xin Chen is with you all the way

  1. Java series
  2. Spring series
  3. The Docker series
  4. Kubernetes series
  5. Database + middleware series
  6. The conversation series

Welcome to follow the public number: programmer Xin Chen

Wechat search “Programmer Chen”, I am Chen, looking forward to enjoying the Java world with you…

Github.com/zq2599/blog…