k8s中yaml文件如何编写(K8S官方java客户端之九)
k8s中yaml文件如何编写(K8S官方java客户端之九)
欢迎访问我的GitHubhttps://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客户端之三:外部应用 》
 
今天的实战由以下步骤组成:
- 编码:编写namespace和service的yaml文件;
 - 编码:用java客户端的API,基于yaml文件创建namespace和service;
 - 编码:用java客户端的API,将namespace和service对象转成yaml格式的字符串;
 - 验证:运行应用,验证上述代码的功能:通过http请求创建namespace、service,通过http请求下载已有namespace和service的yaml文件、通过http请求清理本次实战的所有资源;
 
https://github.com/zq2599/blog_demos):

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

- 在父工程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();
    }
- 编码已经完成,下图红框中是新增的三个文件:
 

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

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

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

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

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

- 至此,java客户端的yaml支持实战已经完成,轻松愉快的氛围中咱们又掌握一项基本功能;
 
截止目前,《K8S官方java客户端》系列已经推出九篇文章,这些都是紧密结合kubernetes基本概念和操作的实战,有了这些扎实的基本功,接下来可以进入进阶篇了,前方有更多精彩的内容等着咱们!
欢迎关注我的公众号:程序员欣宸




