写点什么

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

作者:程序员欣宸
  • 2022 年 4 月 02 日
  • 本文字数:4884 字

    阅读完需:约 16 分钟

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

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


概览

  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 类


  1. 如上图所示,ProtoClient 提供了增删改查接口,我们可以用这些接口实现对 K8S 资源的操作;

  2. 有了接口,接下来要搞清楚参数怎么准备,先看 create 方法的源码,看它需要什么样的参数:

  1. 如上图所示,create 方法的第一个参数就是 K8S 资源类,该类的特性是在泛型中约束的,必须实现 com.google.protobuf.Message 的子接口;

  2. 这些入参 Message 的子类从哪里来呢?例如我们要创建一个 NameSpace 的时候,是自己写一个 Message 子类?还是说哪里有现成的?接下来要做的就是搞清楚 K8S 资源类来自哪里?毕竟所有 K8S 资源的操作都要用上这些 java 类;

  3. 一起去 java 客户端的源码寻找线索,这是父子结构的 maven 工程,在名为 client-java-proto 的子工程中,它的 README 文件给出了线索,地址是:https://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 文件,地址:https://github.com/kubernetes-client/gen/blob/master/proto/dependencies.sh ,如下图:

  1. 上图红框中的地址是:https://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,地址是:https://v1-15.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.15/

2. 如下图,红框 1 是 pod 列表的接口文档,红框 2 显示了该 URL,有了这个 URL 我们可以编码了:


3. 在今后的操作中,所有资源都可以根据该文档找到对应的 API 信息,辅助我们编码;

4. 终于,可以开始实战了;


源码下载

  1. 如果您不想编码,可以在 GitHub 下载所有源码,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):



  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="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>
复制代码


  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@Slf4jpublic 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 列表,在浏览器访问:http://localhost:8080/pods/kube-system ,响应如下图,红框中的 items_数组就是所有 pod 信息:


4. 上图中的 items_数组,展开一个却 name 字段是 byte 数组,没办法看出真实内容:


5. 借助 IDEA 的断点功能,可以看清上述 name_字段的内容,如下图:


6. 再来试试创建 namespace 的功能,浏览器执行:http://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 主线;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 04 月 02 日阅读数: 46
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
Kubernetes官方java客户端之五:proto基本操作_4月月更_程序员欣宸_InfoQ写作社区