欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

概览

  • 本文是《K8S官方java客户端》系列的第九篇,以下提到的java客户端都是指client-jar.jar
  • 《K8S官方java客户端之七:patch操作 》涉及的知识点、代码、操作都太多了,对作者和读者都是莫大的折磨,于是从上一篇《K8S官方java客户端之八:fluent style 》,再到本篇都以放松为主题吧,写得尽量简单一些,但是该学该练的不会缩水;
  • 平时用命令行操作kubernetes时,经常用到yaml文件,实际上java客户端也支持yaml格式的操作:通过yaml生成资源对象、将资源对象转成yaml格式的内容,也就是今天咱们的实战内容;
  • 今天的实战对应的java应用无需部署在K8S环境内部,只需当做一个普通的SpringBoot运行起来即可,详情请参考《K8S官方java客户端之三:外部应用 》

实战步骤

今天的实战由以下步骤组成:

  1. 编码:编写namespace和service的yaml文件;
  2. 编码:用java客户端的API,基于yaml文件创建namespace和service;
  3. 编码:用java客户端的API,将namespace和service对象转成yaml格式的字符串;
  4. 验证:运行应用,验证上述代码的功能:通过http请求创建namespace、service,通过http请求下载已有namespace和service的yaml文件、通过http请求清理本次实战的所有资源;

源码下载

如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示(
https://github.com/zq2599/blog_demos):
064ff44e93adf4d351b91012d479c8fa.png
  • 这个git项目中有多个文件夹,《K8S官方java客户端》系列的源码在kubernetesclient文件夹下,如下图红框所示:
3d0db7b4bd5aa035107836ace09981dd.png

编码

  • 在父工程kubernetesclient下面新建名为yaml的maven子工程,pom.xml内容如下,需要注意的是排除掉spring-boot-starter-json,原因请参考《K8S官方java客户端之二:序列化和反序列化问题 》:
<?xml version="1.0" encoding="UTF-8"?>4.0.0com.bolingcavalry        kubernetesclient        1.0-SNAPSHOT../pom.xmlcom.bolingcavalry    yaml    0.0.1-SNAPSHOTyamlDemo project for yamljarorg.springframework.boot            spring-boot-starter-web            org.springframework.boot                    spring-boot-starter-json                org.projectlombok            lombok            trueio.kubernetes            client-java        org.springframework.boot                spring-boot-maven-plugin                2.3.0.RELEASE
  • resources目录下新建namespace.yaml,这是创建namespace用的yaml文件,内容如下:
apiVersion: v1kind: Namespacemetadata:  name: yaml
  • resources目录下新建service.yaml,这是创建service用的yaml文件,内容如下:
apiVersion: v1kind: Servicemetadata:  namespace: yaml  name: test-servicespec:  type: ClusterIP  selector:    app: test-service  ports:    - name: port-of-container      port: 8080
  • 接下来是java代码,都集中在同一个文件YamlApplication.java中,咱们分成几部分逐个看,首先是类注解:
@SpringBootApplication@RestController@Slf4jpublic class YamlApplication {
  • 其次是main方法:
    public static void main(String[] args) {        SpringApplication.run(YamlApplication.class, args);    }
  • 定义两个常量,分别是实战用到的namespace和service的name,稍后用到:
    /**     * 本次实战用到的namespace,和namespace.yaml、service.yaml文件中的一致     */    private final static String NAMESPACE = "yaml";    /**     * 本次实战用到的service的名称,和service.yaml文件中的一致     */    private final static String SERVICE_NAME = "test-service";
  • 接下来是初始化方法,kubeConfigPath变量的值,请指向您的kubernetes环境的config文件,还要注意的是Yaml.addModelMap方法,这是为了在war包或者junit测试的时候规避load方法失效的问题:
@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);        // 规避已知问题:https://github.com/kubernetes-client/java/issues/474        // 如果应用是war包,或者运行在junit等涉及到反射类型的class-loader场景下,Yaml.load方法有可能不生效,        // 此时要执行Yaml.addModelMap来规避此问题        Yaml.addModelMap("v1", "Namespace", V1Namespace.class);        Yaml.addModelMap("v1", "Service", V1Service.class);    }
  • 开发一个web接口,用来基于yaml文件创建namespace和service,可见核心方法是Yaml.load这个API,入参是yaml文件,返回的是创建好的API实例,CoreV1Api可以直接用这个实例创建资源:
    @RequestMapping(value = "/yaml/load")    public String load() throws Exception {        CoreV1Api api = new CoreV1Api();        // 通过yaml文件创建namespace实例        V1Namespace namespace = (V1Namespace) Yaml.load(new ClassPathResource("namespace.yaml").getFile());        // 创建namespace资源        api.createNamespace(namespace, null, null, null);        // 通过yaml文件创建service实例        V1Service service = (V1Service) Yaml.load(new ClassPathResource("service.yaml").getFile());        // 创建service资源        api.createNamespacedService(NAMESPACE, service, null, null, null);        return "load operation success " + new Date();    }
  • 将API实例转成yaml格式的字符串,依靠的是Yaml.dump方法,这里为了方便查看,我封装了一个私有方法,该方法接收API实例,然后用Yaml.dump方法转成yaml格式的字符串,接着在日志中打印,并在浏览器产生一个yaml格式的下载文件:
    private void writeResponse(HttpServletResponse httpServletResponse, Object dumpObject, String fileName) throws Exception {        String yaml = Yaml.dump(dumpObject);        log.info(yaml);        byte[] bytes = yaml.getBytes("UTF-8");        httpServletResponse.setHeader("content-type", "application/yaml");        httpServletResponse.setContentType("application/yaml");        httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + fileName);        httpServletResponse.setHeader("Content-Length", "" + bytes.length);        httpServletResponse.getOutputStream().write(bytes);    }
  • 有了上面的writeResponse方法,就可以轻松开发两个web接口了,分别用来下载service和namespace的yaml格式内容:
    @RequestMapping(value = "/yaml/getnamespace")    @ResponseBody    public String getNamespace(HttpServletResponse httpServletResponse) throws Exception {        // 查找名为yaml的namespace        V1Namespace namespace = new CoreV1Api().readNamespace(NAMESPACE, null, null, null);        // 通过Yaml.dump方法将资源对象转成Yaml格式的字符串,在日志中打印,然后在浏览器以yaml文件的格式下载        writeResponse(httpServletResponse, namespace, "namespace.yaml");        return "getnamespace operation success " + new Date();    }    @RequestMapping(value = "/yaml/getservice")    @ResponseBody    public String getService(HttpServletResponse httpServletResponse) throws Exception {        // 在yaml这个namespace下,查找名为test-service的service        V1Service service = new CoreV1Api().readNamespacedService(SERVICE_NAME, NAMESPACE, null, null, null);        // 通过Yaml.dump方法将资源对象转成Yaml格式的字符串,在日志中打印,然后在浏览器以yaml文件的格式下载        writeResponse(httpServletResponse, service, "service.yaml");        return "getservice operation success " + new Date();    }
  • 最后是清理资源的方法,实战最后调用一下,干干净净不留残余:
    @RequestMapping(value = "/yaml/clear")    public String clear() throws Exception {        CoreV1Api coreV1Api = new CoreV1Api();        // 删除service        coreV1Api.deleteNamespacedService(SERVICE_NAME, 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();    }
  • 编码已经完成,下图红框中是新增的三个文件:
3ca1130303da1ebac79cc60493f7c488.png
  • 启动这个Spring Boot应用,开始验证;

验证

  • 浏览器访问:http://localhost:8080/yaml/load ,即可根据yaml创建namespace和service,命令行查看kubernetes环境,可见创建成功:
d7607a5311eb348e194f6b98d607c393.png
  • 浏览器访问:http://localhost:8080/yaml/getnamespace ,浏览器会提示下载,如下图,选择保存:
aaf2ccf2f90c7d0bb396151ccf5d3f69.png
  • 打开下载好的namespace.yaml,内容如下:
e3916e879b207e5c9d4f4d015fa3d902.png
  • 浏览器访问:http://localhost:8080/yaml/getservice ,会下载service的yaml,如下图:
a7ddd37552761e63da67ee0f7d2de7ea.png
  • 验证结束,浏览器访问:http://localhost:8080/yaml/clear ,相关的service和namespace都被清理掉了:
599b1ada1830c0133dafa3f8f81deec3.png
  • 至此,java客户端的yaml支持实战已经完成,轻松愉快的氛围中咱们又掌握一项基本功能;

新的起点

截止目前,《K8S官方java客户端》系列已经推出九篇文章,这些都是紧密结合kubernetes基本概念和操作的实战,有了这些扎实的基本功,接下来可以进入进阶篇了,前方有更多精彩的内容等着咱们!

欢迎关注我的公众号:程序员欣宸

54a5c66fd76b4c268b89a02efccd4631.png
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐