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基本概念和操作的实战,有了这些扎实的基本功,接下来可以进入进阶篇了,前方有更多精彩的内容等着咱们!
欢迎关注我的公众号:程序员欣宸