Kubernetes官方java客户端之五(proto基本操作)

学向勤中得,萤窗万卷书。这篇文章主要讲述Kubernetes官方java客户端之五:proto基本操作相关的知识,希望能为你提供帮助。
欢迎访问我的GitHub
https://github.com/zq2599/blog_demos
内容:所有原创文章分类汇总及配套源码,涉及java、Docker、Kubernetes、DevOPS等;
概览

  1. 本文是《Kubernetes官方java客户端》系列的第五篇,以下提到的==java客户端==都是指==client-jar.jar==;
  2. 经过前面四篇文章的准备和尝试,我们对java客户端有了初步了解,也成功运行了hello world,接下来要做的是继续深入学习和实践,掌握这门利器; 两个主要脉络
    • java客户端的基本功能并不复杂,就是以何种手段发起对K8S资源的增删改查请求,把握以下两个主脉络即可:
  3. ==proto主线==:用K8S官方的protobuf定义将各种资源生成java类,用少量API处理这些对象(特点,API极少,每个API都通用,处理所有类型的资源对象);
  4. ==openapi主线==:使用openapi工具,将所有资源都自动生成增删改查的API(特点:API极多,每个资源都有自身的API);
今天的文章咱们来学习和了解==proto主线==;
proto主线的核心类ProtoClient
  1. 前面曾提到proto主线的特点是API极少,咱们来看看这些少量的API的源头:==ProtoClient类==
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  2. 如上图所示,ProtoClient提供了增删改查接口,我们可以用这些接口实现对K8S资源的操作;
  3. 有了接口,接下来要搞清楚参数怎么准备,先看create方法的源码,看它需要什么样的参数:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  4. 如上图所示,create方法的第一个参数就是==K8S资源类==,该类的特性是在泛型中约束的,必须实现==com.google.protobuf.Message==的子接口;
  5. 这些入参Message的子类从哪里来呢?例如我们要创建一个NameSpace的时候,是自己写一个Message子类?还是说哪里有现成的?接下来要做的就是搞清楚K8S资源类来自哪里?毕竟所有K8S资源的操作都要用上这些java类;
  6. 一起去==java客户端==的源码寻找线索,这是父子结构的maven工程,在名为==client-java-proto==的子工程中,它的README文件给出了线索,地址是:https://github.com/kubernetes-client/java/tree/master/proto ,如下图:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  7. 上图红框中的操作向我们揭示了整个过程:先去下载另一个github仓库,然后此仓库里有脚本generate.sh,该脚本根据protobuf配置生成java类,这些java文件被放置在==java/proto/src/main/java==目录下;
  8. 本文是学习K8S官方java客户端的文章,有关K8S的protobuf详情不在这里展开,只给出一段关键脚本供您参考,这是根据proto自动生成代码时执行的脚本,用于下载protobuf文件,地址:https://github.com/kubernetes-client/gen/blob/master/proto/dependencies.sh ,如下图:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  9. 上图红框中的地址是:https://raw.githubusercontent.com/kubernetes//api/master/rbac/v1alpha1/generated.proto ,内容如下,java客户端中的java代码就是根据这些内容生成的:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  10. 结合前面的分析,再回到java客户端源码的子工程==client-java-proto==,可以找到generate.sh脚本生成的V1.java,这个java文件里面有V1版本的所有protobuf对象,如下图:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  11. 上图红框中==Namespace==类是GeneratedMessageV3的子类,来看下GeneratedMessageV3的继承关系,如下图,该类实现了Message接口,满足ProtoClient.create方法对入参的泛型约束:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片
小结
  1. ProtoClient类提供的操作K8S资源的增删改查方法;
  2. java客户端的client-java-proto子工程内,有通过K8S官方protobuf生成的对象类,这些类就是ProtoClient的增删查用到的参数;
  3. 增删改查方法有了,涉及的对象也有了,接下来可以实战了;
实战前的准备
现在还不能马上写代码,还差最后一个准备步骤:==确认API参数==;
  • 假设实战的内容是查询kube-system这个namespace下面的所有pod列表,那么API相关信息在哪获取:
    1. 打开API在线文档,我这里K8S版本是1.15,地址是:https://v1-15.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/
    2. 如下图,红框1是pod列表的接口文档,红框2显示了该URL,有了这个URL我们可以编码了:
      Kubernetes官方java客户端之五(proto基本操作)

      文章图片
  1. 在今后的操作中,所有资源都可以根据该文档找到对应的API信息,辅助我们编码;
  2. 终于,可以开始实战了; 源码下载
  3. 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  1. 这个git项目中有多个文件夹,本章的应用在==kubernetesclient==文件夹下,如下图红框所示:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片
    开始编码
  2. 打开《Kubernetes官方java客户端之一:准备 》中创建的kubernetesclient工程,在里面新建子工程==protobufclient==,其pom.xml内容如下,要注意的是spring-boot-starter-json已经被排除,因此序列化工具会变为Gson(原本默认是jackson):
    < ?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> 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>
2. 新增==ProtobufApplication.java==,这是新工程的引导类,也有通过ProtoClient查询pod列表的代码: ```java 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 = "https://www.songbingjia.com/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 = "https://www.songbingjia.com/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; 验证
  2. 确保K8S环境的config文件在本地可以访问(代码中kubeConfigPath变量的值);
  3. 运行ProtobufApplication;
  4. 先尝试获取==kube-system==这个namespace下的所有pod列表,在浏览器访问:http://localhost:8080/pods/kube-system ,响应如下图,红框中的items_数组就是所有pod信息:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  5. 上图中的==items_==数组,展开一个却name字段是byte数组,没办法看出真实内容:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片
  6. 【Kubernetes官方java客户端之五(proto基本操作)】借助IDEA的断点功能,可以看清上述==name_==字段的内容,如下图:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  7. 再来试试创建namespace的功能,浏览器执行:http://localhost:8080/createnamespace/aaabbbccc ,就会创建名为==aaabbbccc==的namespace,并将==ProtoClient.create==的返回信息展现到浏览器上:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  8. SSH登录上K8S服务器,查看namespace,如下图红框,可以见到新增的namespace:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  9. 验证完成,基于ProtoClient的API和K8S官方的在线API文档,我们可以轻松操作K8S环境; ProtoClient的短板
  10. ProtoClient的短板其实在前面已经提到了,如下图红框4所示,在线API文档中提到查询pod列表的时候可以输入一些参数(例如过滤条件),但是ProtoClient提供的API咱们也看过了,并不支持输入查询参数:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  11. 来看下ProtoClient请求K8S Api service的核心代码,如下图红框所示,==请求参数字段已经写死==,所以外面调用ProtoClient的API时根本没办法把参数传进来:
    Kubernetes官方java客户端之五(proto基本操作)

    文章图片

  12. 咱们可以参考上述代码自己写一段,把红框位置改为API文档中指定的参数,但是,这样似乎略微麻烦,还有更好的办法吗?
    • 当然有,敬请期待下一篇,一起学习和实战openapi主线;

    推荐阅读