Welcome to my GitHub

Github.com/zq2599/blog…

Content: all original article classification summary and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc.;

Links to articles

  1. Client-go: Preparation
  2. Client-go Actual combat 2 :RESTClient
  3. Client go: Clientset
  4. Client-go: dynamicClient
  5. Client-go Combat 5: Discover Client

About Clientset

  • Restclient (Restclient, Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient (Restclient) : Restclient For example, API path, Group, Version, returned data structure, codec tools, etc. :

  • If the business code, need to operate kubernetes resource code are written like the above, I believe you will be difficult to bear, should do some packaging to simplify the code, but client-go has provided a simplified version of the client, save us to do the trouble, which is the topic of this article: Clientset

This paper gives an overview of

  • The purpose of this article is to learn how to use Clientset, so it is not difficult. Let’s speed read the source code to quickly understand what Clientset is, then confirm the requirements, and finally quickly code and verify the work.

Source speed

  • The reason for speed reading rather than accuracy is that Clientset content is simple and easy to understand, and a quick grasp of its principles can be used in practice.
  • The source code for Clientset is the set in its name, which is a collection of many things. Take a look at the source code for the Clientset data structure.
type Clientset struct {
	*discovery.DiscoveryClient
	admissionregistrationV1      *admissionregistrationv1.AdmissionregistrationV1Client
	admissionregistrationV1beta1 *admissionregistrationv1beta1.AdmissionregistrationV1beta1Client
	internalV1alpha1             *internalv1alpha1.InternalV1alpha1Client
	appsV1                       *appsv1.AppsV1Client
	appsV1beta1                  *appsv1beta1.AppsV1beta1Client
	appsV1beta2                  *appsv1beta2.AppsV1beta2Client
	authenticationV1             *authenticationv1.AuthenticationV1Client
    ...
Copy the code
  • Kubernetes Group, Version, Clientset, kubernetes Group, Clientset, kubernetes Group, Version, Kubernetes Clientset Each combination of Kubernetes’ Group and Version corresponds to a field in the Clientset data structure:

  • Clientset is, as it should be, a collection of all Group and Version composite objects, but what exactly are Group and Version composite objects? AppsV1Client has only one field, restClient, so restClient is the base of Clientset. Also notice the Deployments method in red box 2, which returns the DeploymentInterface interface implementation:

  • Take a look at DeploymentInterface and open the deployment.go file to reveal the interface definition and implementation:

  • Take a look at the code for an interface implementation and choose the new Deployment method as follows, similar to the code we used for RESTClient:
func (c *deployments) Create(ctx context.Context, deployment *v1.Deployment, opts metav1.CreateOptions) (result *v1.Deployment, err error) {
	result = &v1.Deployment{}
	err = c.client.Post().
		Namespace(c.ns).
		Resource("deployments").
		VersionedParams(&opts, scheme.ParameterCodec).
		Body(deployment).
		Do(ctx).
		Into(result)
	return
}
Copy the code
  • At this point, you should have a pretty good idea about Clientset: It’s a Group and Version encapsulation of the code we use to manipulate resources with RESTClient. It’s less technical and more manual — so who does the manual work? As shown in the red box below, the source code indicates that this code is automatically generated by the client-gen tool:

  • At this point, the source speed of Clientset is complete. Now that we know the inside story of Clientset, let’s try it.

Need to confirm

  • The requirements of this coding practice are as follows:
  • Write a piece of code that checks the operate parameter entered by the user, which defaults to create or accepts clean.
  • If the operate parameter is equal to create, do the following:
  1. Create a namespace named test-clientset
  2. Create a deployment with test-clientset namespace, tomcat image and 2 copies
  3. Create a service with a namespace of test-clientset type and NodePort type
  • If the operate parameter is equal to clean, delete the service, Deployment, namespace and other resources created in the create operation:
  • The above requirements are realized by Clientset client. After completion, we use the browser to verify whether Tomcat is normal.

Download the source code

  • The source code for this article can be downloaded on GitHub, with the address and link information 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 warehouse address, HTTPS protocol
Git repository address (SSH) [email protected]:zq2599/blog_demos.git The project source warehouse address, SSH protocol
  • The Git project has multiple folders. Client-go related applications are in the client-go-tutorials folder, as shown in the red box below:

  • Client-go-tutorials have multiple sub-folders under the folder. The source code for this section is in the clientsetdemo directory, as shown in the red box below:

coding

  • Create a new folder, RestclientDemo, and run the following command to create a new Module:
go mod init clientsetdemo
Copy the code
  • Add k8s. IO/API and k8s. IO /client-go dependencies to kubernetes:
Go get k8s. IO /[email protected] go get k8s. IO /[email protected]Copy the code
  • Create a new main.go file and it will look like this.
package main

import (
	"context"
	"flag"
	"fmt"
	appsv1 "k8s.io/api/apps/v1"
	apiv1 "k8s.io/api/core/v1"
	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"
	"k8s.io/utils/pointer"
	"path/filepath"
)

const (
	NAMESPACE = "test-clientset"
	DEPLOYMENT_NAME = "client-test-deployment"
	SERVICE_NAME = "client-test-service"
)

func main(a) {

	var kubeconfig *string

	// home is the home directory. If you can get the value of the home directory, you can use it as the default value
	ifhome:=homedir.HomeDir(); home ! ="" {
		// Kubeconfig is the absolute path to the kubeconfig file.
		// If the kubeconfig parameter is not entered, the default path ~/.kube/config is used
		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 kubeconFig default directory, only from the input parameter
		kubeconfig = flag.String("kubeconfig".""."absolute path to the kubeconfig file")}// Gets the operation type entered by the user. The default is create. You can also enter clean to clean all resources
	operate := flag.String("operate"."create"."operate type : create or clean")

	flag.Parse()

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

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

	// instantiate the clientset object
	clientset, err := kubernetes.NewForConfig(config)

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

	fmt.Printf("operation is %v\n", *operate)

	// If you want to perform a cleanup operation
	if "clean"==*operate {
		clean(clientset)
	} else {
		/ / create a namespace
		createNamespace(clientset)

		/ / create the deployment
		createDeployment(clientset)

		/ / create the service
		createService(clientset)
	}
}

// Clean up all resources created in this battle
func clean(clientset *kubernetes.Clientset) {
	emptyDeleteOptions := metav1.DeleteOptions{}

	/ / remove the service
	iferr := clientset.CoreV1().Services(NAMESPACE).Delete(context.TODO(), SERVICE_NAME, emptyDeleteOptions) ; err ! =nil {
		panic(err.Error())
	}

	/ / delete deployment
	iferr := clientset.AppsV1().Deployments(NAMESPACE).Delete(context.TODO(), DEPLOYMENT_NAME, emptyDeleteOptions) ; err ! =nil {
		panic(err.Error())
	}

	/ / remove the namespace
	iferr := clientset.CoreV1().Namespaces().Delete(context.TODO(), NAMESPACE, emptyDeleteOptions) ; err ! =nil {
		panic(err.Error())
	}
}

/ / the new namespace
func createNamespace(clientset *kubernetes.Clientset) {
	namespaceClient := clientset.CoreV1().Namespaces()

	namespace := &apiv1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: NAMESPACE,
		},
	}

	result, err := namespaceClient.Create(context.TODO(), namespace, metav1.CreateOptions{})

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

	fmt.Printf("Create namespace %s \n", result.GetName())
}

/ / new service
func createService(clientset *kubernetes.Clientset) {
	// Get the client of the service
	serviceClient := clientset.CoreV1().Services(NAMESPACE)

	// instantiate a data structure
	service := &apiv1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: SERVICE_NAME,
		},
		Spec: apiv1.ServiceSpec{
			Ports: []apiv1.ServicePort{{
					Name: "http",
					Port: 8080,
					NodePort: 30080,
				},
			},
			Selector: map[string]string{
				"app" : "tomcat",
			},
			Type: apiv1.ServiceTypeNodePort,
		},
	}

	result, err := serviceClient.Create(context.TODO(), service, metav1.CreateOptions{})

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

	fmt.Printf("Create service %s \n", result.GetName())
}

/ / the new deployment
func createDeployment(clientset *kubernetes.Clientset) {
	// Get the client for deployment
	deploymentClient := clientset.
		AppsV1().
		Deployments(NAMESPACE)

	// instantiate a data structure
	deployment := &appsv1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name: DEPLOYMENT_NAME,
		},
		Spec: appsv1.DeploymentSpec{
			Replicas: pointer.Int32Ptr(2),
			Selector: &metav1.LabelSelector{
				MatchLabels: map[string]string{
					"app" : "tomcat",
				},
			},

			Template: apiv1.PodTemplateSpec{
				ObjectMeta:metav1.ObjectMeta{
					Labels: map[string]string{
						"app" : "tomcat",
					},
				},
				Spec: apiv1.PodSpec{
					Containers: []apiv1.Container{
						{
							Name: "tomcat",
							Image: "Tomcat: 8.0.18 - jre8",
							ImagePullPolicy: "IfNotPresent",
							Ports: []apiv1.ContainerPort{
								{
									Name: "http",
									Protocol: apiv1.ProtocolSCTP,
									ContainerPort: 8080,
								},
							},
						},
					},
				},
			},
		},
	}

	result, err := deploymentClient.Create(context.TODO(), deployment, metav1.CreateOptions{})

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

	fmt.Printf("Create deployment %s \n", result.GetName())
}
Copy the code

Data structure initialization annoyance

  • After looking at or reading the code above, you may be annoyed: Create the resources, the data structure of field simply can’t remember too much too complicated, the corresponding code is bad to write, here to share my practice, as the chart, when I was in the development of a total of two Windows, the left is the official yaml example, right to use the function of the GoLand split screen, points to the left side of the screen is me to write the code window, on the right side is a data structure definition, The content is not mistaken, the data structure can also be corresponding, write much more comfortable:

validation

  • After the code is written, run the go run main.go command to create namespace, Deployment, service and other resources.

  • Kubernetes create resource on kubernetes

[root@hedy ~]# kubectl get pods -n test-clientset NAME READY STATUS RESTARTS AGE client-test-deployment-7677cc9669-kd7l7  1/1 Running 0 178m client-test-deployment-7677cc9669-kt5rv 1/1 Running 0 178m [root@hedy ~]# kubectl get service -n Test-set NAME TYPE cluster-ip external-ip PORT(S) AGE client-test-service NodePort 10.109.189.151 <none> 8080:30080/TCP 178mCopy the code
  • If the browser accesses port 30080 of kubernetes server, you can see the familiar tomcat homepage:

  • Run the go run main. go-operate clean command to delete all created resources.

  • This is the end of the study and practice of Clientset, in general, this is a mostly automatic generation of client code, logic is simple and easy to understand, after using a few times, you can control the resources of Kubernetes at will;

Context for containers and images

If you do not want to build their own Kubernetes environment, recommend the use of Tencent cloud container service TKE: no need to build, Tencent cloud can use stable, safe, efficient, flexible expansion of Kubernetes container platform; If you want to upload and download your image through the Internet, we recommend Tencent cloud container image service TCR: data encryption storage, multi-node rapid distribution of large image, cross-region image synchronization

You are not alone, Xinchen original accompany 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 pay attention to the public number: programmer Xin Chen

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

Github.com/zq2599/blog…