快捷搜索:  汽车  科技

k8s中yaml文件如何编写(K8S官方java客户端之九)

k8s中yaml文件如何编写(K8S官方java客户端之九)

欢迎访问我的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):
  • k8s中yaml文件如何编写(K8S官方java客户端之九)(1)

    • 这个git项目中有多个文件夹,《K8S官方java客户端》系列的源码在kubernetesclient文件夹下,如下图红框所示:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(2)

    编码
    • 在父工程kubernetesclient下面新建名为yaml的maven子工程,pom.xml内容如下,需要注意的是排除掉spring-boot-starter-json,原因请参考《K8S官方java客户端之二:序列化和反序列化问题 》:

    <?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>yaml</artifactId> <version>0.0.1-SNAPSHOT</version> <name>yaml</name> <description>Demo project for yaml</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>

    • resources目录下新建namespace.yaml,这是创建namespace用的yaml文件,内容如下:

    apiVersion: v1 kind: Namespace metadata: name: yaml

    • resources目录下新建service.yaml,这是创建service用的yaml文件,内容如下:

    apiVersion: v1 kind: Service metadata: namespace: yaml name: test-service spec: type: ClusterIP selector: app: test-service ports: - name: port-of-container port: 8080

    • 接下来是java代码,都集中在同一个文件YamlApplication.java中,咱们分成几部分逐个看,首先是类注解:

    @SpringBootApplication @RestController @Slf4j public 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(); }

    • 编码已经完成,下图红框中是新增的三个文件:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(3)

    • 启动这个Spring Boot应用,开始验证;
    验证
    • 浏览器访问:http://localhost:8080/yaml/load ,即可根据yaml创建namespace和service,命令行查看kubernetes环境,可见创建成功:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(4)

    • 浏览器访问:http://localhost:8080/yaml/getnamespace ,浏览器会提示下载,如下图,选择保存:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(5)

    • 打开下载好的namespace.yaml,内容如下:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(6)

    • 浏览器访问:http://localhost:8080/yaml/getservice ,会下载service的yaml,如下图:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(7)

    • 验证结束,浏览器访问:http://localhost:8080/yaml/clear 相关的service和namespace都被清理掉了:

    k8s中yaml文件如何编写(K8S官方java客户端之九)(8)

    • 至此,java客户端的yaml支持实战已经完成,轻松愉快的氛围中咱们又掌握一项基本功能;
    新的起点

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

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

    k8s中yaml文件如何编写(K8S官方java客户端之九)(9)

    猜您喜欢: