Kubernetes官方java客戶端之五:proto基本操作

歡迎訪問我的GitHub

//github.com/zq2599/blog_demos

內容:所有原創文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;

概覽

  1. 本文是《Kubernetes官方java客戶端》系列的第五篇,以下提到的java客戶端都是指client-jar.jar
  2. 經過前面四篇文章的準備和嘗試,我們對java客戶端有了初步了解,也成功運行了hello world,接下來要做的是繼續深入學習和實踐,掌握這門利器;

兩個主要脈絡

  • java客戶端的基本功能並不複雜,就是以何種手段發起對K8S資源的增刪改查請求,把握以下兩個主脈絡即可:
  1. proto主線:用K8S官方的protobuf定義將各種資源生成java類,用少量API處理這些對象(特點,API極少,每個API都通用,處理所有類型的資源對象);
  2. openapi主線:使用openapi工具,將所有資源都自動生成增刪改查的API(特點:API極多,每個資源都有自身的API);

今天的文章咱們來學習和了解proto主線

proto主線的核心類ProtoClient

  1. 前面曾提到proto主線的特點是API極少,咱們來看看這些少量的API的源頭:ProtoClient類
    在這裡插入圖片描述

  2. 如上圖所示,ProtoClient提供了增刪改查介面,我們可以用這些介面實現對K8S資源的操作;

  3. 有了介面,接下來要搞清楚參數怎麼準備,先看create方法的源碼,看它需要什麼樣的參數:
    在這裡插入圖片描述

  4. 如上圖所示,create方法的第一個參數就是K8S資源類,該類的特性是在泛型中約束的,必須實現com.google.protobuf.Message的子介面;

  5. 這些入參Message的子類從哪裡來呢?例如我們要創建一個NameSpace的時候,是自己寫一個Message子類?還是說哪裡有現成的?接下來要做的就是搞清楚K8S資源類來自哪裡?畢竟所有K8S資源的操作都要用上這些java類;

  6. 一起去java客戶端的源碼尋找線索,這是父子結構的maven工程,在名為client-java-proto的子工程中,它的README文件給出了線索,地址是://github.com/kubernetes-client/java/tree/master/proto ,如下圖:
    在這裡插入圖片描述

  7. 上圖紅框中的操作向我們揭示了整個過程:先去下載另一個github倉庫,然後此倉庫里有腳本generate.sh,該腳本根據protobuf配置生成java類,這些java文件被放置在java/proto/src/main/java目錄下;

  8. 本文是學習K8S官方java客戶端的文章,有關K8S的protobuf詳情不在這裡展開,只給出一段關鍵腳本供您參考,這是根據proto自動生成程式碼時執行的腳本,用於下載protobuf文件,地址://github.com/kubernetes-client/gen/blob/master/proto/dependencies.sh ,如下圖:
    在這裡插入圖片描述

  9. 上圖紅框中的地址是://raw.githubusercontent.com/kubernetes//api/master/rbac/v1alpha1/generated.proto ,內容如下,java客戶端中的java程式碼就是根據這些內容生成的:
    在這裡插入圖片描述

  10. 結合前面的分析,再回到java客戶端源碼的子工程client-java-proto,可以找到generate.sh腳本生成的V1.java,這個java文件裡面有V1版本的所有protobuf對象,如下圖:
    在這裡插入圖片描述

  11. 上圖紅框中Namespace類是GeneratedMessageV3的子類,來看下GeneratedMessageV3的繼承關係,如下圖,該類實現了Message介面,滿足ProtoClient.create方法對入參的泛型約束:
    在這裡插入圖片描述

小結

  1. ProtoClient類提供的操作K8S資源的增刪改查方法;
  2. java客戶端的client-java-proto子工程內,有通過K8S官方protobuf生成的對象類,這些類就是ProtoClient的增刪查用到的參數;
  3. 增刪改查方法有了,涉及的對象也有了,接下來可以實戰了;

實戰前的準備

現在還不能馬上寫程式碼,還差最後一個準備步驟:確認API參數

  • 假設實戰的內容是查詢kube-system這個namespace下面的所有pod列表,那麼API相關資訊在哪獲取:
  1. 打開API在線文檔,我這裡K8S版本是1.15,地址是://v1-15.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/

  2. 如下圖,紅框1是pod列表的介面文檔,紅框2顯示了該URL,有了這個URL我們可以編碼了:
    在這裡插入圖片描述

  3. 在今後的操作中,所有資源都可以根據該文檔找到對應的API資訊,輔助我們編碼;

  4. 終於,可以開始實戰了;

源碼下載

  1. 如果您不想編碼,可以在GitHub下載所有源碼,地址和鏈接資訊如下表所示(//github.com/zq2599/blog_demos):
名稱 鏈接 備註
項目主頁 //github.com/zq2599/blog_demos 該項目在GitHub上的主頁
git倉庫地址(https) //github.com/zq2599/blog_demos.git 該項目源碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該項目源碼的倉庫地址,ssh協議
  1. 這個git項目中有多個文件夾,本章的應用在kubernetesclient文件夾下,如下圖紅框所示:
    在這裡插入圖片描述

開始編碼

  1. 打開《Kubernetes官方java客戶端之一:準備 》中創建的kubernetesclient工程,在裡面新建子工程protobufclient,其pom.xml內容如下,要注意的是spring-boot-starter-json已經被排除,因此序列化工具會變為Gson(原本默認是jackson):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //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>protobufclient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>protobufclient</name>
    <description>Demo project for protobuf client</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. 新增ProtobufApplication.java,這是新工程的引導類,也有通過ProtoClient查詢pod列表的程式碼:
package com.bolingcavalry.protobufclient;

import com.google.gson.GsonBuilder;
import io.kubernetes.client.ProtoClient;
import io.kubernetes.client.ProtoClient.ObjectOrStatus;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.proto.Meta;
import io.kubernetes.client.proto.V1.Namespace;
import io.kubernetes.client.proto.V1.PodList;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileReader;

@SpringBootApplication
@RestController
@Slf4j
public class ProtobufApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProtobufApplication.class, args);
    }

    /**
     * 根據配置文件創建ProtoClient實例
     * @return
     * @throws Exception
     */
    private ProtoClient buildProtoClient() 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();

        // 創建操作類
        return new ProtoClient(client);
    }

    @RequestMapping(value = "/createnamespace/{namespace}", method = RequestMethod.GET)
    public ObjectOrStatus<Namespace> createnamespace(@PathVariable("namespace") String namespace) throws Exception {
        // 創建namespace資源對象
        Namespace namespaceObj =
                Namespace.newBuilder().setMetadata(Meta.ObjectMeta.newBuilder().setName(namespace).build()).build();

        // 通過ProtoClient的create介面在K8S創建namespace
        ObjectOrStatus<Namespace> ns = buildProtoClient().create(namespaceObj, "/api/v1/namespaces", "v1", "Namespace");

        // 使用Gson將集合對象序列化成JSON,在日誌中列印出來
        log.info("ns info \n{}", new GsonBuilder().setPrettyPrinting().create().toJson(ns));

        return ns;
    }

    @RequestMapping(value = "/pods/{namespace}", method = RequestMethod.GET)
    public ObjectOrStatus<PodList> pods(@PathVariable("namespace") String namespace) throws Exception {
        // 通過ProtoClient的list介面獲取指定namespace下的pod列表
        ObjectOrStatus<PodList> pods = buildProtoClient().list(PodList.newBuilder(), "/api/v1/namespaces/" + namespace + "/pods");

        // 使用Gson將集合對象序列化成JSON,在日誌中列印出來
        log.info("pod info \n{}", new GsonBuilder().setPrettyPrinting().create().toJson(pods));

        return pods;
    }
}
  1. 上述程式碼展示了ProtoClient的API的用法,一個是獲取pod列表,一個是創建namespace;

驗證

  1. 確保K8S環境的config文件在本地可以訪問(程式碼中kubeConfigPath變數的值);

  2. 運行ProtobufApplication;

  3. 先嘗試獲取kube-system這個namespace下的所有pod列表,在瀏覽器訪問://localhost:8080/pods/kube-system ,響應如下圖,紅框中的items_數組就是所有pod資訊:
    在這裡插入圖片描述

  4. 上圖中的items_數組,展開一個卻name欄位是byte數組,沒辦法看出真實內容:
    在這裡插入圖片描述

  5. 藉助IDEA的斷點功能,可以看清上述name_欄位的內容,如下圖:
    在這裡插入圖片描述

  6. 再來試試創建namespace的功能,瀏覽器執行://localhost:8080/createnamespace/aaabbbccc ,就會創建名為aaabbbccc的namespace,並將ProtoClient.create的返回資訊展現到瀏覽器上:
    在這裡插入圖片描述

  7. SSH登錄上K8S伺服器,查看namespace,如下圖紅框,可以見到新增的namespace:
    在這裡插入圖片描述

  8. 驗證完成,基於ProtoClient的API和K8S官方的在線API文檔,我們可以輕鬆操作K8S環境;

ProtoClient的短板

  1. ProtoClient的短板其實在前面已經提到了,如下圖紅框4所示,在線API文檔中提到查詢pod列表的時候可以輸入一些參數(例如過濾條件),但是ProtoClient提供的API咱們也看過了,並不支援輸入查詢參數:
    在這裡插入圖片描述

  2. 來看下ProtoClient請求K8S Api service的核心程式碼,如下圖紅框所示,請求參數欄位已經寫死,所以外面調用ProtoClient的API時根本沒辦法把參數傳進來:
    在這裡插入圖片描述

  3. 咱們可以參考上述程式碼自己寫一段,把紅框位置改為API文檔中指定的參數,但是,這樣似乎略微麻煩,還有更好的辦法嗎?

  • 當然有,敬請期待下一篇,一起學習和實戰openapi主線;

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 資料庫+中間件系列
  6. DevOps系列

歡迎關注公眾號:程式設計師欣宸

微信搜索「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界…
//github.com/zq2599/blog_demos