Kubernetes 官方 java 客户端之八:fluent style,java 语言视频教学
public static void main(String[] args) {
SpringApplication.run(FluentStyleApplication.class, args);
}
定义常量 NAMESPACE 作为本次实战的 namespace:
private final static String NAMESPACE = "fluent";
用 @PostConstruct 注解修饰 setDefaultApiClient 方法,令其在实例化时执行一次,里面做了一些全局性的初始化设置,注意 kubeConfigPath 变量对应的 config 文件路径要正确:
/**
默认的全局设置
@return
@throws Exception
*/
@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);
}
接下来是创建 namespace 的 web 服务,如下所示,由于 namespace 在 kubernetes 的 apiVersion 是 v1,因此创建的是 V1Namespace 实例:
@RequestMapping(value = "/fluent/createnamespace")
public V1Namespace createnamespace() throws Exception {
V1Namespace v1Namespace = new V1NamespaceBuilder()
.withNewMetadata()
.withName(NAMESPACE)
.addToLabels("label1", "aaa")
.addToLabels("label2", "bbb")
.endMetadata()
.build();
return new CoreV1Api().createNamespace(v1Namespace, null, null, null);
}
为了更清晰的展现 fluent style 效果,将上述代码与创建 namespace 的 yaml 文件内容放在一起对比,如下图所示,可见对照着 yaml 文件就能将代码写出来:
接下来是创建 service 的代码,为了便于和 yaml 对应起来,代码中特意加了缩进:
@RequestMapping(value = "/fluent/createservice")
public V1Service createservice() throws Exception {
V1Service v1Service = new V1ServiceBuilder()
// meta 设置
.withNewMetadata()
.withName("nginx")
.endMetadata()
// spec 设置
.withNewSpec()
.withType("NodePort")
.addToPorts(new V1ServicePort().port(80).nodePort(30103))
.addToSelector("name", "nginx")
.endSpec()
.build();
return new CoreV1Api().createNamespacedService(NAMESPACE, v1Service, null, null, null);
}
创建 deployment 的代码如下,因为内容较多所以相对复杂一些,请注意,由于 deployment 在 kubernetes 的 apiVersion 是 extensions/v1beta1,因此创建的是 ExtensionsV1beta1Deployment 实例:
@RequestMapping(value = "/fluent/createdeployment")
public ExtensionsV1beta1Deployment createdeployment() throws Exception {
ExtensionsV1beta1Deployment v1Deployment = new ExtensionsV1beta1DeploymentBuilder()
// meta 设置
.withNewMetadata()
.withName("nginx")
.endMetadata()
// spec 设置
.withNewSpec()
.withReplicas(1)
// spec 的 templat
.withNewTemplate()
// template 的 meta
.withNewMetadata()
.addToLabels("name", "nginx")
.endMetadata()
// template 的 spec
.withNewSpec()
.addNewContainer()
.withName("nginx")
.withImage("nginx:1.18.0")
.addToPorts(new V1ContainerPort().containerPort(80))
.endContainer()
.endSpec()
.endTemplate()
.endSpec()
.build();
return new ExtensionsV1beta1Api().createNamespacedDeployment(NAMESPACE, v1Deployment, null, null, null);
}
从上述代码可见,withXXX 和 endXXX 是成对出现的,请在编程的时候注意不要遗漏了 endXXX,建议在写 withXXX 的同时就把 endXXX 写上;
最后一个方法是清理所有资源的,前面创建的 deployment、service、namespace 都在此一次性清理掉,实际操作中发现了一个尴尬的情况:删除 deployment 和 namespace 时,发送到 API Server 的删除请求都收到的操作成功的响应,但 kubernetes 客户端在反序列化响应内容时抛出异常(日志中显示了详细情况),鄙人能力有限暂未找到解决之道,因此只能用 try catch 来避免整个方法抛出异常,好在 kubernetes 实际上已经删除成功了,影响不大:
@RequestMapping(value = "/fluent/clear")
public String clear() throws Exception {
// 删除 deployment
try {
new ExtensionsV1beta1Api().deleteNamespacedDeployment("nginx", NAMESPACE, null, null, null, null, null, null);
} catch (Exception e)
{
log.error("delete deployment error", e);
}
CoreV1Api coreV1Api = new CoreV1Api();
// 删除 service
coreV1Api.deleteNamespacedService("nginx", 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();
}
编码已完成,启动 fluent 工程,接下来开始验证功能是否正常;
[](
)验证
将 fluent 工程直接在 IEDA 环境启动;
浏览器访问:http://localhost:8080/fluent/createnamespace ,页面会展示 API Server 返回的完整 namespace 信息:
浏览器访问:http://localhost:8080/fluent/createservice ,页面会展示 API Server 返回的完整 service 信息:
评论