Kubernetes official java client eight: fluent style

Welcome to my GitHub

https://github.com/zq2599/blog_demos
content: classification summary of all original articles and supporting source code, involving Java, Docker, Kubernetes, DevOPS, etc.;

Overview

  1. This article is the eighth in the "Kubernetes official java client" series. The java clients mentioned below refer to client-jar.jar;
  2. The previous article "Kubernetes Official Java Client Seven: Patch Operation" involves too many knowledge points, codes, and operations, which is a great torture to the author and readers . In this article, let’s relax and write a few simple and smooth codes. , Understand the support of java client for fluent style programming, and the verification operation after coding is very simple;

About fluent styel

  1. Also known as fluid coding, fluent programming, it is a style that enhances the readability of the code, making it more natural and smooth when reading the code. The feature is that the function returns the relevant type, so that multiple functions are linked before and after the call.
  2. For fluent style, please refer to Martin Flowler's article published in 2005 at https://martinfowler.com/bliki/FluentInterface.html. The code comparison before and after using fluent style is shown in the figure below:

3.

Source download

  1. If you don't want to code, you can download all the source code on GitHub. The address and link information are shown in the following table (https://github.com/zq2599/blog_demos):
name link Remarks
Project homepage https://github.com/zq2599/blog_demos The project's homepage on GitHub
git warehouse address (https) https://github.com/zq2599/blog_demos.git The warehouse address of the project source code, https protocol
git warehouse address (ssh) [email protected]:zq2599/blog_demos.git The warehouse address of the source code of the project, ssh protocol
  1. There are multiple folders in this git project. The application of this chapter is under the kubernetesclient folder, as shown in the red box below:
    Insert picture description here

Overview of actual combat steps

  1. Create a new subproject named fluent under the parent project kubernetesclient ;
  2. There is only one class FluentStyleApplication in the fluent project, the main method of startup and the code of fluent style are in this class;
  3. FluentStyleApplication.java provides four web interfaces, the functions are: new namespace, new deployment, new service, and delete all resources created by the previous three interfaces;
  4. After the fluent project coding is completed, it does not need to be made into a mirror and deployed inside the kubernetes environment, but as a normal SpringBoot application to find a java environment to start, and deploy and start with the article "Kubernetes Official Java Client Three: External Application" Consistent
  5. Call each interface in turn to verify whether the function meets expectations;

coding

  1. Create a new maven subproject named fluent under the parent project kubernetesclient. The content of pom.xml is as follows. It should be noted that spring-boot-starter-json is excluded . For the reasons, please refer to "Kubernetes Official Java Client Two: Serialization and Anti Serialization issues :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.bolingcavalry</groupId>
        <artifactId>kubernetesclient</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>fluent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fluent</name>
    <description>Demo project for fluent style</description>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-json</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>io.kubernetes</groupId>
            <artifactId>client-java</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.0.RELEASE</version>
            </plugin>
        </plugins>
    </build>

</project>
  1. Create a new FluentStyleApplication.java . First of all, this class is used as a startup class and has a main method:
public static void main(String[] args) {
    
    
  SpringApplication.run(FluentStyleApplication.class, args);
}
  1. Define the constant NAMESPACE as the namespace of this actual combat:
private final static String NAMESPACE = "fluent";
  1. Use the @PostConstruct annotation to modify the setDefaultApiClient method so that it will be executed once during instantiation. Some global initialization settings have been made. Note that the config file path corresponding to the kubeConfigPath variable must be correct:
/**
     * 默认的全局设置
     * @return
     * @throws Exception
     */
    @PostConstruct
    private void setDefaultApiClient() throws Exception {
    
    
        // 存放K8S的config文件的全路径
        String kubeConfigPath = "/Users/zhaoqin/temp/202007/05/config";
        // 以config作为入参创建的client对象,可以访问到K8S的API Server
        ApiClient client = ClientBuilder
                .kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath)))
                .build();

        // 会打印和API Server之间请求响应的详细内容,生产环境慎用
        client.setDebugging(true);

        // 创建操作类
        Configuration.setDefaultApiClient(client);
    }
  1. Next is to create the namespace web service, as shown below, because the apiVersion of the namespace in kubernetes is v1, the V1Namespace instance is created:
 @RequestMapping(value = "/fluent/createnamespace")
    public V1Namespace createnamespace() throws Exception {
    
    

        V1Namespace v1Namespace = new V1NamespaceBuilder()
                .withNewMetadata()
                .withName(NAMESPACE)
                .addToLabels("label1", "aaa")
                .addToLabels("label2", "bbb")
                .endMetadata()
                .build();

        return new CoreV1Api().createNamespace(v1Namespace, null, null, null);
    }
  1. In order to show the fluent style effect more clearly , compare the above code with the content of the yaml file that created the namespace. As shown in the figure below, it can be seen that the code can be written by comparing the yaml file:
    Insert picture description here

  2. Next is the code to create the service. In order to facilitate the correspondence with yaml, the code is specially indented:

 @RequestMapping(value = "/fluent/createservice")
    public V1Service createservice() throws Exception {
    
    
        V1Service v1Service = new V1ServiceBuilder()
                // meta设置
                .withNewMetadata()
                    .withName("nginx")
                .endMetadata()

                // spec设置
                .withNewSpec()
                    .withType("NodePort")
                    .addToPorts(new V1ServicePort().port(80).nodePort(30103))
                    .addToSelector("name", "nginx")
                .endSpec()
                .build();

        return new CoreV1Api().createNamespacedService(NAMESPACE, v1Service, null, null, null);
    }
  1. The code to create the deployment is as follows. Because of the content, it is relatively complicated. Please note that because the apiVersion of deployment in kubernetes is extensions/v1beta1 , the instance of ExtensionsV1beta1Deployment is created:
 @RequestMapping(value = "/fluent/createdeployment")
    public ExtensionsV1beta1Deployment createdeployment() throws Exception {
    
    
        ExtensionsV1beta1Deployment v1Deployment = new ExtensionsV1beta1DeploymentBuilder()
                // meta设置
                .withNewMetadata()
                    .withName("nginx")
                .endMetadata()

                // spec设置
                .withNewSpec()
                    .withReplicas(1)
                    // spec的templat
                    .withNewTemplate()
                        // template的meta
                        .withNewMetadata()
                            .addToLabels("name", "nginx")
                        .endMetadata()

                        // template的spec
                        .withNewSpec()
                            .addNewContainer()
                                .withName("nginx")
                                .withImage("nginx:1.18.0")
                                .addToPorts(new V1ContainerPort().containerPort(80))
                            .endContainer()
                        .endSpec()

                    .endTemplate()
                .endSpec()
                .build();

        return new ExtensionsV1beta1Api().createNamespacedDeployment(NAMESPACE, v1Deployment, null, null, null);
    } 
  1. It can be seen from the above code that withXXX and endXXX appear as a pair. Please be careful not to omit endXXX when programming. It is recommended to write endXXX while writing withXXX;
  2. The last method is to clean up all resources. The deployment, service, and namespace created earlier are all cleaned up here. An embarrassing situation was discovered in actual operation: when the deployment and namespace are deleted, all delete requests sent to the API Server are received. The received operation is a successful response, but the kubernetes client throws an exception when deserializing the response content (details are shown in the log). I have limited ability and have not found a solution yet , so I can only use try catch to avoid the whole method. An exception is thrown. Fortunately, kubernetes has actually been deleted successfully, with little impact:
    @RequestMapping(value = "/fluent/clear")
    public String clear() throws Exception {
    
    

        // 删除deployment
        try {
    
    
            new ExtensionsV1beta1Api().deleteNamespacedDeployment("nginx", NAMESPACE, null, null, null, null, null, null);
        } catch (Exception e)
        {
    
    
            log.error("delete deployment error", e);
        }

        CoreV1Api coreV1Api = new CoreV1Api();

        // 删除service
        coreV1Api.deleteNamespacedService("nginx", NAMESPACE, null, null, null, null, null, null);

        // 删除namespace
        try {
    
    
            coreV1Api.deleteNamespace(NAMESPACE, null, null, null, null, null, null);
        } catch (Exception e)
        {
    
    
            log.error("delete namespace error", e);
        }

        return "clear finish, " + new Date();
    }
  1. The coding has been completed, start the fluent project, and then start to verify whether the function is normal;

verification

  1. Start the fluent project directly in the IEDA environment;

  2. Browser visit: http://localhost:8080/fluent/createnamespace , the page will display the complete namespace information returned by API Server:
    Insert picture description here

  3. Browser visit: http://localhost:8080/fluent/createservice , the page will display the complete service information returned by API Server:
    Insert picture description here

  4. Browser visit: http://localhost:8080/fluent/createdeployment , the page will display the complete deployment information returned by API Server:
    Insert picture description here

  5. Verify that the services created by the previous interfaces are available. The IP address of my kubernetes is 192.168.50.135 , so I visit: http://192.168.50.135:30103 , and the nginx homepage can be displayed normally:
    Insert picture description here

  6. Log in to the kubernetes server through SSH to view the resources created through the kubernetes java client are all normal:
    Insert picture description here

  7. After the verification is completed, the browser visits: http://localhost:8080/fluent/clear to clear the resources created by the first three interfaces;

  • At this point, the actual combat of calling the java client based on fluent style is complete. I hope you can use this style of API call proficiently to make coding easier and smoother. By the way, let’s keep an eye on some simple and easy operations in the next article. The goal is Familiar with common operations of java client;

Guess you like

Origin blog.csdn.net/boling_cavalry/article/details/107886911