Java操作Istio(kubernetes-client)

istio由于他对服务代码的完全不侵入性,以及kubernetes类云平台的普及 实用性越来越强。但istio至今也没有合适的dashboard,并且不同公司不同的业务场景导致使用istio做的事情也不相同.有偏向灰度发布的场景也有偏向对流量分布的场景。免不得需要使用业务代码操作istio的流量规则等配置。这里提供一个快速可行的操作方案


文章目录

        • 实现方式
        • kubernetes-client扩展
          • 提供对istio资源的操作支持
            • 增加资源对象模型类
            • 增加资源对象Operations类
            • 创建客户端连接类
          • 提供对istio资源对象的链式拼装能力
            • Builder
            • Fluent接口
            • FluentImpl
        • END

实现方式

在使用中我们更多是需要通过代码对istio进行控制,而istio在kubernetes中的规则资源是以CRD的形式存在的。所以 使用原本的kubernetes客户端扩展其资源对象请求拼装逻辑 是可以实现对istio资源进操控的。
java代码的sdk中操作kubernetes集群时较多使用的是fabric的kubernetes-clientkubernetes提供的client-java,这里由于之前对kubernetes资源进操作时使用的客户端是fabric的kubernetes-client所以这里进行扩展时采用的也是kubernetes-client
而关于这个方案的实现方式,在github上也有人已经进行了完整的代码实现(
https://github.com/snowdrop/istio-java-api)
这里我们可以使用相对简单的方案去实现这些功能

kubernetes-client扩展

  1. 创建项目,拉取项目包
        
            io.fabric8
            kubernetes-client
            4.9.1
        

Java操作Istio(kubernetes-client)_第1张图片

可以看到kubernetes-client包含了client包以及model相关包。这里我们可以将对istio的操作需求分为两步

  • 提供对istio的操作支持
  • 提供对istio资源对象的链式拼装能力

其中的步骤1,实现相对简单。完成配置后我们可以通过kubernetes-client原生支持的操作方式对istio的资源进操作增删改查的操作。实现代码后效果如下

Java操作Istio(kubernetes-client)_第2张图片

步骤2完成后可以通过Builder类快速对资源对象完成拼装。实现代码后效果如下

Java操作Istio(kubernetes-client)_第3张图片

接下来分别进行说明

提供对istio资源的操作支持
  • 增加资源对象模型类
  • 增加资源对象Operations类
  • 创建客户端连接类
增加资源对象模型类

创建资源对象模型实际就是根据资源对象的完整结构创建资源类,建议根据官网的对象结构进行创建(原因是istio版本更新真的是 太快了 ,对象结构虽然没有大变化但还是有新的功能字段的)。这里以VirtualService举例,根据官方的结构表格以及字段类型进行对象的创建
https://istio.io/docs/reference/config/networking/virtual-service/

Java操作Istio(kubernetes-client)_第4张图片

模型创建,模型创建时需要注意几个点,首先VirtualServic最外层需要实现HashMetadata接口。
内层需要实现KubernetesResource接口(如VirtualServiceSpec)
这里需要额外注意一下,资源的kind是VirtualService。 apiVersion是networking.istio.io/v1alpha3

Java操作Istio(kubernetes-client)_第5张图片

Java操作Istio(kubernetes-client)_第6张图片

资源对象创建完成后还需要额外创建两个对象
分别是List对象与Doneable对象

Java操作Istio(kubernetes-client)_第7张图片

Java操作Istio(kubernetes-client)_第8张图片

List对象是批量获取时返回的对象类型(如client.apps().deployments().innamespace().list()),注意kind和apiversion的调整,编写时可以参考kubernetes原生对象的类来编写(如DeploymentList)。
Doneable对象中提供的done方法会在触发replace时使用(最开始这里忘记写了,后来需要对vs规则做修改时报错,无法修改导致原因就是这里),编写时同理可以参考原生类对应的类来编写

Java操作Istio(kubernetes-client)_第9张图片

增加资源对象Operations类

完成了基础数据模型编写后,需要开始调整client相关的类让集群客户端能够对我们新资源进行支持。这一支持首先就要提供Operations类,这个类主要用来提供请求调用时地址拼装的相关参数。
为了拼装这些参数首先我们要了解istio生成规则时真实的请求地址是什么。
进入kubernetes master节点

在这里插入图片描述

执行apply命令,补充-v=10|grephttp

Java操作Istio(kubernetes-client)_第10张图片

这样我们就了解了istio规则真实请求的api地址,那么我们将这个真实地址通过Operations来拼装出来

Java操作Istio(kubernetes-client)_第11张图片

apiGoupName、piGroupVersion、pural三个字段的对应关系如下所示,这样我们就可以定义Operations里的参数了。(Operations类如上所示,编写时依然可以参考原生资源)

Java操作Istio(kubernetes-client)_第12张图片

这里字段的对应关系可以看下kubernetes-client中请求拼装的方法 —》OperationSupport.getRootUrl()方法。这里拼装请求地址时使用的方法

Java操作Istio(kubernetes-client)_第13张图片

创建客户端连接类

前置工作到这里就告一段落,开始对接客户端。下来几个类都是与客户端直接关联的适配器或者链接类

  1. 基础客户端接口,接口用于对接上一步我们完成的Operations类,这里注意需要继承Client接口

Java操作Istio(kubernetes-client)_第14张图片

  1. Istio客户端类,实现了基础客户端接口,可以看到这里通过Operations的构造方法反悔了Operations控制器

Java操作Istio(kubernetes-client)_第15张图片

  1. 集群客户端适配器,创建客户端后需要将这个适配器注入到扩展适配器列表中

Java操作Istio(kubernetes-client)_第16张图片

  1. 集群操作客户端接口,这里我们继承kubernetesClient,保持对原生资源的支持

Java操作Istio(kubernetes-client)_第17张图片

  1. 集群操作客户端实现类,这里一定要注意进行Adapters.register操作,将第三部定义的适配器注入到扩展适配列表中,不然客户端反射操作时会抛出异常。让集群客户端初始化时就进行这个注入过程就好。

Java操作Istio(kubernetes-client)_第18张图片

完成这些我们第一步的操作就完成了。

Java操作Istio(kubernetes-client)_第19张图片

提供对istio资源对象的链式拼装能力

这一步进行的内容并不难,只是工作相对繁琐、重复、容易遗漏。需要格外注意,不然链路调用时会出现莫名其妙的问题定位较难。
进行这一步时可以使用原生对象进行参考来编写。
首先我们先明确一下,fabric中对资源对象定义了四种附属对象,分别用于不同的场景

  • Builder
  • Fluent
  • FluentImpl
  • Nested
    如下
    在这里插入图片描述
    但不是每个资源对象只有这四个类,是每一层对象有这些类,以VS举例
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

我们创建对象模型时需要根据规则的层级去包装对象比如Virtualservice中包含Spec对象,Spec对象中包含Hosts对象包含Http对象,每一层我们需要为其定义这些附属对象。这些才是工作量,这里初步算了一下单VS的对象差不多就有40多个(如果打算编写的话,建议从Gateway资源开始做,结构简单)

Java操作Istio(kubernetes-client)_第20张图片

接下来我们对每一种对象进行说明

Builder

Builder类是将链路调用对象与资源对象转化的对象,需要继承其对应的FluentImpl类

Java操作Istio(kubernetes-client)_第21张图片

箭头指向的地方都是通过FluentImpl类中的方法对资源对象或Builder对象进行赋值的过程,Builder实际上最大的作用就是通过FluentImpl属性值向资源对象进行赋予。

Fluent接口

Fluent接口需要为对应资源模块里所有的字段提供对齐操作的方法,根据每一个字段是数组是集合,是基础对象还是自定义对象进行不同的处理,这里做举例说明但不一定说全,可以参考原生对象的Fluent做参考。

  • 关于跳转,我们进行对象的链式拼装时需要向下级跳转,完成下级拼装后再会跳的过程如下,这一过程是需要通过自定义Nested内部类来实现的

Java操作Istio(kubernetes-client)_第22张图片

  • 关于资源类型
  1. 数组: 建议提供以下方法,如果是自定义资源对象需要包含中间部分引入Nested内部类向下级跳转的方法
    List getRoutes();
    SpecHttpRoute buildRoutes(int index);
    List buildRoutes();
    A withRoutes(List items);
    A withRoutes(SpecHttpRoute... items);
    Boolean hasRoutes();
    
    SpecHttpRouteNested addNewRoutes();
    SpecHttpRouteNested setNewRouteLike(SpecHttpRoute item);
    SpecHttpRouteNested setNewRouteLike(int i , SpecHttpRoute item);
    SpecHttpRouteNested editFirstRoutes();
    SpecHttpRouteNested editLastRoutes();
    SpecHttpRouteNested editRoutes(int i);
    
    A addNewRoutes(SpecHttpRoute specHttp);
    A setToRoutes(int index, SpecHttpRoute item);
    A addToRoutes(int index, SpecHttpRoute item);
    A addToRoutes(SpecHttpRoute... items);
    A addAllToRoutes(Collection items);
    A removeFromRoutes(SpecHttpRoute... items);
    A removeAllFromRoutes(Collection items);
  1. 自定义资源类型,自定义资源对象需要包含中间部分引入Nested内部类向下级跳转的方法
    SpecHttpRewrite buildRewrite();
    A withRewrite(SpecHttpRewrite item);
    Boolean hasRewrite();
    SpecHttpFluent.SpecHttpRewriteNested withNewRewrite();
    SpecHttpFluent.SpecHttpRewriteNested withNewRewriteLike(SpecHttpRewrite item);
    SpecHttpFluent.SpecHttpRewriteNested editRewrite();
    SpecHttpFluent.SpecHttpRewriteNested editOrNewRewrite();
    SpecHttpFluent.SpecHttpRewriteNested editOrNewRewriteLike(SpecHttpRewrite item);
  1. 普通资源类型
    String getExact();
    A withExact(String item);

(ps:这个类有点长就分两个图来截了。)

Java操作Istio(kubernetes-client)_第23张图片

Java操作Istio(kubernetes-client)_第24张图片

需要注意的是关于Nested内部接口的定义,继承Nested,下级Fluent对象泛型为当前Nested。

public interface SpecHttpRouteNested extends io.fabric8.kubernetes.api.builder.Nested, SpecHttpRouteFluent> {
        public N and();    public N endRoute();
    }
FluentImpl

实现Fluent接口定义实现类,需要注意红线部分,以及箭头部分,Fluent中包含当前资源对象里的所有属性,但自定义类型的属性在FluentImpl中必须改成对应的Builder,每个方法的实现方式都相对简单,可以自己编写或者参考Deployment的即可

Java操作Istio(kubernetes-client)_第25张图片

  • 关于NestedImpl:在FluentImpl中需要对Fluent中定义的Nested进行实现。需要注意的点已经标注了红线与箭头
    NestedImpl需要继承对应下级的FluentImpl,需要实现同级Fluent的Nested
    包含了and和end方法,实际end方法就是在调用and方法。实现的能力是根据下级中赋予的属性生成对应的Builder,赋予本级对应的Builder属性中。

Java操作Istio(kubernetes-client)_第26张图片

具体每一个类都可以参考原有的资源对象来编写,这里只做简述。这样完成了代码后能够实现如下的资源拼装能力。

Java操作Istio(kubernetes-client)_第27张图片

END

这样可以完成对istio的操作客户端。并且可以完全复用kubernetes-client中的客户端以及其他原生资源对象的操作方法。开发量不大而且也不复杂,只是刚开始看的时候会被多个相似的类弄乱,理清类间的调用逻辑其实并不复杂。
这样的操作并不只针对istio的资源,如果公司自研了一些CRD,也可以使用这种方式进行封装提供操作客户端。

ps:再多说一句,istio赋予规则时需要开启自动注入,这里并不建议对命名空间开启自动注入。毕竟sidecar对资源占用不小是不争的事实。建议通过annotation注解对指定的deployment开启,尽可能节省资源(但这毕竟是业务层相关的逻辑了,按需取舍吧)
注入间的覆盖逻辑如下

Java操作Istio(kubernetes-client)_第28张图片

你可能感兴趣的:(java,istio,微服务)