• java连接kubernete


    最近需要做一个项目,将k8s上的日志经过java工程输出到前端,大概想了下思路,首先要java连接kubernete监控到job的日志,然后通过websocket将日志持续输出到前端,因为这些从来没有写过,所以只能一点一点积累知识,一点一点攻破,目前是java连接kubernete成功了,并取到了日志,暂时记录一下

    1、java连接kubernete方法:配置文件方式,这个文件需要配置到你的工程里面,怎么获取到配置文件?问你们单位的运维,告诉他在机器上帮你取这个文件~/.kube/config 运维说这个是开发环境的超级证书,这个证书只能运维取,因为估计普通测试员没有权限,运维有管理员权限的账号才能取下来

    创建k8sclient文件

    1. package com.example.demo.config;
    2. /**
    3. * @Author: lxx
    4. * @Date: 2022/8/4 下午5:43
    5. */
    6. import io.kubernetes.client.custom.IntOrString;
    7. import io.kubernetes.client.openapi.ApiClient;
    8. import io.kubernetes.client.openapi.ApiException;
    9. import io.kubernetes.client.openapi.apis.CoreV1Api;
    10. import io.kubernetes.client.openapi.apis.ExtensionsV1beta1Api;
    11. import io.kubernetes.client.openapi.apis.NetworkingV1Api;
    12. import io.kubernetes.client.openapi.models.*;
    13. import io.kubernetes.client.util.ClientBuilder;
    14. import io.kubernetes.client.util.KubeConfig;
    15. import lombok.extern.slf4j.Slf4j;
    16. import okhttp3.Call;
    17. import org.slf4j.Logger;
    18. import java.io.FileReader;
    19. import java.io.IOException;
    20. import java.util.Map;
    21. /**
    22. * k8s客户端
    23. *
    24. * @author wanghuidong
    25. * @date 2021/6/18 14:14
    26. */
    27. @Slf4j
    28. public class K8sClient {
    29. /**
    30. * k8s-api客户端
    31. */
    32. private ApiClient apiClient;
    33. /**
    34. * 构建集群POD内通过SA访问的客户端
    35. * loading the in-cluster config, including:
    36. * 1. service-account CA
    37. * 2. service-account bearer-token
    38. * 3. service-account namespace
    39. * 4. master endpoints(ip, port) from pre-set environment variables
    40. */
    41. public K8sClient() {
    42. try {
    43. this.apiClient = ClientBuilder.cluster().build();
    44. } catch (IOException e) {
    45. log.error("构建K8s-Client异常", e);
    46. throw new RuntimeException("构建K8s-Client异常");
    47. }
    48. }
    49. /**
    50. * 构建集群外通过UA访问的客户端
    51. * loading the out-of-cluster config, a kubeconfig from file-system
    52. *
    53. * @param kubeConfigPath kube连接配置文件
    54. */
    55. public K8sClient(String kubeConfigPath) {
    56. try {
    57. this.apiClient = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
    58. } catch (IOException e) {
    59. log.error("读取kubeConfigPath异常", e);
    60. throw new RuntimeException("读取kubeConfigPath异常");
    61. } catch (Exception e) {
    62. log.error("构建K8s-Client异常", e);
    63. throw new RuntimeException("构建K8s-Client异常");
    64. }
    65. }
    66. /**
    67. * 获取所有的Pod
    68. *
    69. * @return podList
    70. */
    71. public V1PodList getAllPodList() throws Exception {
    72. // new a CoreV1Api
    73. CoreV1Api api = new CoreV1Api(apiClient);
    74. // invokes the CoreV1Api client
    75. // V1Pod pod = api.readNamespacedPod("reconcile-l75kp","dev5",null,null,null);
    76. try {
    77. //V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null, null);
    78. V1PodList list = api.listNamespacedPod("dev5",null,null,null,null,null,null,null,null,null,null);
    79. return list;
    80. } catch (ApiException e) {
    81. log.error("获取podlist异常:" + e.getResponseBody(), e);
    82. }
    83. return null;
    84. }
    85. /**
    86. * 创建k8s service
    87. *
    88. * @param namespace 命名空间
    89. * @param serviceName 服务名称
    90. * @param port 服务端口号(和目标pod的端口号一致)
    91. * @param selector pod标签选择器
    92. * @return 创建成功的service对象
    93. */
    94. public V1Service createService(String namespace, String serviceName, Integer port, Map selector) {
    95. //构建service的yaml对象
    96. V1Service svc = new V1ServiceBuilder()
    97. .withNewMetadata()
    98. .withName(serviceName)
    99. .endMetadata()
    100. .withNewSpec()
    101. .addNewPort()
    102. .withProtocol("TCP")
    103. .withPort(port)
    104. .withTargetPort(new IntOrString(port))
    105. .endPort()
    106. .withSelector(selector)
    107. .endSpec()
    108. .build();
    109. // Deployment and StatefulSet is defined in apps/v1, so you should use AppsV1Api instead of CoreV1API
    110. CoreV1Api api = new CoreV1Api(apiClient);
    111. V1Service v1Service = null;
    112. try {
    113. v1Service = api.createNamespacedService(namespace, svc, null, null, null);
    114. } catch (ApiException e) {
    115. log.error("创建service异常:" + e.getResponseBody(), e);
    116. } catch (Exception e) {
    117. log.error("创建service系统异常:", e);
    118. }
    119. return v1Service;
    120. }
    121. /**
    122. * 创建k8s V1Ingress
    123. *
    124. * @param namespace 命名空间
    125. * @param ingressName ingress名称
    126. * @param annotations ingress注解
    127. * @param path 匹配的路径
    128. * @param serviceName 路由到的服务名称
    129. * @param servicePort 路由到的服务端口
    130. * @return 创建成功的ingress对象
    131. */
    132. public V1Ingress createV1Ingress(String namespace, String ingressName, Map annotations, String path,
    133. String serviceName, Integer servicePort) {
    134. //构建ingress的yaml对象
    135. V1Ingress ingress = new V1IngressBuilder()
    136. .withNewMetadata()
    137. .withName(ingressName)
    138. .withAnnotations(annotations)
    139. .endMetadata()
    140. .withNewSpec()
    141. .addNewRule()
    142. .withHttp(new V1HTTPIngressRuleValueBuilder().addToPaths(new V1HTTPIngressPathBuilder()
    143. .withPath(path)
    144. .withPathType("Prefix")
    145. .withBackend(new V1IngressBackendBuilder()
    146. .withService(new V1IngressServiceBackendBuilder()
    147. .withName(serviceName)
    148. .withPort(new V1ServiceBackendPortBuilder()
    149. .withNumber(servicePort).build()).build()).build()).build()).build())
    150. .endRule()
    151. .endSpec()
    152. .build();
    153. //调用对应的API执行创建ingress的操作
    154. NetworkingV1Api api = new NetworkingV1Api(apiClient);
    155. V1Ingress v1Ingress = null;
    156. try {
    157. v1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null);
    158. } catch (ApiException e) {
    159. log.error("创建ingress异常:" + e.getResponseBody(), e);
    160. } catch (Exception e) {
    161. log.error("创建ingress系统异常:", e);
    162. }
    163. return v1Ingress;
    164. }
    165. /**
    166. * 创建k8s ExtensionIngress
    167. *
    168. * @param namespace 命名空间
    169. * @param ingressName ingress名称
    170. * @param annotations ingress注解
    171. * @param path 匹配的路径
    172. * @param serviceName 路由到的服务名称
    173. * @param servicePort 路由到的服务端口
    174. * @return 创建成功的ingress对象
    175. */
    176. public ExtensionsV1beta1Ingress createExtensionIngress(String namespace, String ingressName, Map annotations, String path,
    177. String serviceName, Integer servicePort) {
    178. //构建ingress的yaml对象
    179. ExtensionsV1beta1Ingress ingress = new ExtensionsV1beta1IngressBuilder()
    180. .withNewMetadata()
    181. .withName(ingressName)
    182. .withAnnotations(annotations)
    183. .endMetadata()
    184. .withNewSpec()
    185. .addNewRule()
    186. .withHttp(new ExtensionsV1beta1HTTPIngressRuleValueBuilder().addToPaths(new ExtensionsV1beta1HTTPIngressPathBuilder()
    187. .withPath(path)
    188. .withBackend(new ExtensionsV1beta1IngressBackendBuilder()
    189. .withServiceName(serviceName)
    190. .withServicePort(new IntOrString(servicePort)).build()).build()).build())
    191. .endRule()
    192. .endSpec()
    193. .build();
    194. //调用对应的API执行创建ingress的操作
    195. ExtensionsV1beta1Api api = new ExtensionsV1beta1Api(apiClient);
    196. ExtensionsV1beta1Ingress extensionsV1beta1Ingress = null;
    197. try {
    198. extensionsV1beta1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null);
    199. } catch (ApiException e) {
    200. log.error("创建ingress异常:" + e.getResponseBody(), e);
    201. } catch (Exception e) {
    202. log.error("创建ingress系统异常:", e);
    203. }
    204. return extensionsV1beta1Ingress;
    205. }
    206. public V1Pod readNamespacedPod(String podName,String spaceName)throws Exception{
    207. CoreV1Api api = new CoreV1Api(apiClient);
    208. V1Pod pod = api.readNamespacedPod(podName,spaceName,null,null,null);
    209. return pod;
    210. }
    211. public Call readNamespacedPodLogCall (String podName, String spaceName, Integer tailLines)throws Exception{
    212. CoreV1Api api = new CoreV1Api(apiClient);
    213. Call log = api.readNamespacedPodLogCall(podName,spaceName,null,true,null,null,null,null,null,100,null,null);
    214. return log;
    215. }
    216. public String readNamespacedPodLog (String podName, String spaceName, Integer tailLines)throws Exception{
    217. // CoreV1Api api = new CoreV1Api(apiClient);
    218. CoreV1Api api = new CoreV1Api(apiClient);
    219. String log = api.readNamespacedPodLog(podName,spaceName,null,true,false,1024,"true",false,null,10,false);
    220. return log;
    221. }
    222. }

    写单元测试

    1. package com.example.demo;
    2. import com.example.demo.config.K8sClient;
    3. import io.kubernetes.client.openapi.models.V1Pod;
    4. import io.kubernetes.client.openapi.models.V1PodList;
    5. import org.junit.Test;
    6. import java.io.File;
    7. /**
    8. * @Author:
    9. * @Date: 2022/8/4 下午5:31
    10. */
    11. public class KuberneteTest {
    12. @Test
    13. public void testK8sLog()throws Exception{
    14. String kubeConfigPath = "/Users/xxx/k8s/config";
    15. if (!new File(kubeConfigPath).exists()) {
    16. System.out.println("kubeConfig不存在,跳过");
    17. return;
    18. }
    19. K8sClient k8sClient = new K8sClient(kubeConfigPath);
    20. String call=k8sClient.readNamespacedPodLog("test-l75kp","dev5",100);
    21. System.out.println(call);
    22. }
    23. }

    这样就可以连上kubernete啦,连接k8的用户名密码什么的都在/Users/xxx/k8s/config这个配置文件中,连上之后读取 space为dev5  job名为test-l75kp的日志

    不要觉得代码多,亲自试一试吧!

  • 相关阅读:
    MFC的定义和实际操作方法
    两个输入信号同时输入判断
    教你如何在map上添加自定义控件
    AlexNet重点介绍和源码测试
    经典匹配算法: KMP、Sunday与ShiftAnd
    【2022国赛模拟】[SDWC Day4] 数列——树形DP
    iOS之crash分析篇--捕获signal类型的崩溃信息
    创建型设计模式
    CSS的含义和作用:优化网页外观的编程语言
    安防视频监控平台EasyCVR集成到ios系统不能播放是什么原因?如何解决?
  • 原文地址:https://blog.csdn.net/giiiig/article/details/126221779