|
|
|
@@ -1,6 +1,5 @@ |
|
|
|
package com.ruoyi.platform.utils; |
|
|
|
|
|
|
|
import com.alibaba.nacos.shaded.com.google.gson.reflect.TypeToken; |
|
|
|
import com.ruoyi.platform.constant.Constant; |
|
|
|
import com.ruoyi.platform.mapper.ComputingResourceDao; |
|
|
|
import io.kubernetes.client.Exec; |
|
|
|
@@ -8,20 +7,16 @@ import io.kubernetes.client.custom.IntOrString; |
|
|
|
import io.kubernetes.client.custom.Quantity; |
|
|
|
import io.kubernetes.client.openapi.ApiClient; |
|
|
|
import io.kubernetes.client.openapi.ApiException; |
|
|
|
import io.kubernetes.client.openapi.ApiResponse; |
|
|
|
import io.kubernetes.client.openapi.apis.CoreV1Api; |
|
|
|
import io.kubernetes.client.openapi.models.*; |
|
|
|
import io.kubernetes.client.util.ClientBuilder; |
|
|
|
import io.kubernetes.client.util.Watch; |
|
|
|
import io.kubernetes.client.util.credentials.AccessTokenAuthentication; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
|
import org.apache.poi.ss.formula.functions.T; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.beans.factory.annotation.Value; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
|
|
|
|
import javax.annotation.PostConstruct; |
|
|
|
import javax.annotation.Resource; |
|
|
|
import java.io.BufferedReader; |
|
|
|
import java.io.InputStreamReader; |
|
|
|
@@ -45,6 +40,7 @@ public class K8sClientUtil { |
|
|
|
|
|
|
|
@Resource |
|
|
|
private ComputingResourceDao computingResourceDao; |
|
|
|
|
|
|
|
/** |
|
|
|
* 构建集群POD内通过SA访问的客户端 |
|
|
|
* loading the in-cluster config, including: |
|
|
|
@@ -138,11 +134,11 @@ public class K8sClientUtil { |
|
|
|
} catch (ApiException e) { |
|
|
|
log.error("获取 SVC 异常:", e); |
|
|
|
} |
|
|
|
if (v1ServiceList!=null) { |
|
|
|
if (v1ServiceList != null) { |
|
|
|
for (V1Service svc : v1ServiceList.getItems()) { |
|
|
|
if (StringUtils.equals(svc.getMetadata().getName(), serviceName)) { |
|
|
|
// SVC 已存在 |
|
|
|
return svc; |
|
|
|
return svc; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -182,22 +178,22 @@ public class K8sClientUtil { |
|
|
|
/** |
|
|
|
* 创建k8s PVC |
|
|
|
* |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param pvcName 服务名称 |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param pvcName 服务名称 |
|
|
|
* @return 创建成功的service对象 |
|
|
|
*/ |
|
|
|
public V1PersistentVolumeClaim createPvc(String namespace, String pvcName ,String storage, String storageClassName){ |
|
|
|
public V1PersistentVolumeClaim createPvc(String namespace, String pvcName, String storage, String storageClassName) { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
|
|
|
|
V1PersistentVolumeClaimList pvcList = null; |
|
|
|
try { |
|
|
|
pvcList = api.listNamespacedPersistentVolumeClaim(namespace, null,null, null, null, null,null,null, null, null, null); |
|
|
|
pvcList = api.listNamespacedPersistentVolumeClaim(namespace, null, null, null, null, null, null, null, null, null, null); |
|
|
|
} catch (ApiException e) { |
|
|
|
log.error("获取 PVC 异常:", e); |
|
|
|
} |
|
|
|
if (pvcList!=null) { |
|
|
|
if (pvcList != null) { |
|
|
|
for (V1PersistentVolumeClaim pvc1 : pvcList.getItems()) { |
|
|
|
if (StringUtils.equals(pvc1.getMetadata().getName(),pvcName)) { |
|
|
|
if (StringUtils.equals(pvc1.getMetadata().getName(), pvcName)) { |
|
|
|
// PVC 已存在 |
|
|
|
return pvc1; |
|
|
|
} |
|
|
|
@@ -232,16 +228,17 @@ public class K8sClientUtil { |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建k8s 临时POD |
|
|
|
* |
|
|
|
* @param podName pod name |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param port port |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param port port |
|
|
|
* @param mountPath 映射路径 |
|
|
|
* @param pvc 存储 |
|
|
|
* @param image 镜像 |
|
|
|
* @param pvc 存储 |
|
|
|
* @param image 镜像 |
|
|
|
* @return 创建成功的pod,的nodePort端口 |
|
|
|
*/ |
|
|
|
|
|
|
|
public Integer createPod(String podName, String namespace, Integer port ,String mountPath, V1PersistentVolumeClaim pvc, String image){ |
|
|
|
public Integer createPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image) { |
|
|
|
|
|
|
|
Map<String, String> selector = new LinkedHashMap<String, String>(); |
|
|
|
selector.put("k8s-jupyter", podName); |
|
|
|
@@ -253,7 +250,7 @@ public class K8sClientUtil { |
|
|
|
} catch (ApiException e) { |
|
|
|
log.error("获取 POD 异常:", e); |
|
|
|
} |
|
|
|
if (v1PodList!=null) { |
|
|
|
if (v1PodList != null) { |
|
|
|
for (V1Pod pod1 : v1PodList.getItems()) { |
|
|
|
if (StringUtils.equals(pod1.getMetadata().getName(), podName)) { |
|
|
|
// PVC 已存在 |
|
|
|
@@ -301,17 +298,18 @@ public class K8sClientUtil { |
|
|
|
|
|
|
|
/** |
|
|
|
* 创建k8s 临时POD |
|
|
|
* |
|
|
|
* @param podName pod name |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param port port |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @param port port |
|
|
|
* @param mountPath 映射路径 |
|
|
|
* @param subPath pvc子路径 |
|
|
|
* @param pvcName 存储名 |
|
|
|
* @param image 镜像 |
|
|
|
* @param subPath pvc子路径 |
|
|
|
* @param pvcName 存储名 |
|
|
|
* @param image 镜像 |
|
|
|
* @return 创建成功的pod,的nodePort端口 |
|
|
|
*/ |
|
|
|
|
|
|
|
public Integer createPodWithSubPath(String podName, String namespace, Integer port ,String mountPath,String subPath,String pvcName, String image){ |
|
|
|
public Integer createPodWithSubPath(String podName, String namespace, Integer port, String mountPath, String subPath, String pvcName, String image) { |
|
|
|
|
|
|
|
Map<String, String> selector = new LinkedHashMap<String, String>(); |
|
|
|
selector.put("k8s-jupyter", podName); |
|
|
|
@@ -323,7 +321,7 @@ public class K8sClientUtil { |
|
|
|
} catch (ApiException e) { |
|
|
|
log.error("获取 POD 异常:", e); |
|
|
|
} |
|
|
|
if (v1PodList!=null) { |
|
|
|
if (v1PodList != null) { |
|
|
|
for (V1Pod pod1 : v1PodList.getItems()) { |
|
|
|
if (StringUtils.equals(pod1.getMetadata().getName(), podName)) { |
|
|
|
// PVC 已存在 |
|
|
|
@@ -381,7 +379,7 @@ public class K8sClientUtil { |
|
|
|
} |
|
|
|
|
|
|
|
// 创建配置好的Pod |
|
|
|
public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String dataPvcName, String datasetPath, String modelPath) { |
|
|
|
public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String computingResource, String dataPvcName, String datasetPath, String modelPath) { |
|
|
|
|
|
|
|
//设置选择节点,pod反亲和性 |
|
|
|
Map<String, String> selector = new LinkedHashMap<>(); |
|
|
|
@@ -473,7 +471,9 @@ public class K8sClientUtil { |
|
|
|
try { |
|
|
|
pod = api.createNamespacedPod(namespace, pod, null, null, null); |
|
|
|
String nodeName = getNodeName(podName, namespace); |
|
|
|
computingResourceDao.updateUsedStateByNode(nodeName, Constant.Used_State_used); |
|
|
|
if (Constant.Computing_Resource_GPU.equals(computingResource)) { |
|
|
|
computingResourceDao.updateUsedStateByNode(nodeName, Constant.Used_State_used); |
|
|
|
} |
|
|
|
} catch (ApiException e) { |
|
|
|
log.error("创建pod异常:" + e.getResponseBody(), e); |
|
|
|
} catch (Exception e) { |
|
|
|
@@ -485,14 +485,12 @@ public class K8sClientUtil { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 根据获取namespace,deploymentName的Pod Name |
|
|
|
* |
|
|
|
* @return podList |
|
|
|
*/ |
|
|
|
public V1Pod getNSPodList(String namespace,String deploymentName) throws Exception { |
|
|
|
public V1Pod getNSPodList(String namespace, String deploymentName) throws Exception { |
|
|
|
// new a CoreV1Api |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
V1PodList v1PodList = null; |
|
|
|
@@ -513,12 +511,12 @@ public class K8sClientUtil { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
public String executeCommand(V1Pod item, String command) { |
|
|
|
public String executeCommand(V1Pod item, String command) { |
|
|
|
try { |
|
|
|
// 创建API实例 |
|
|
|
// 创建Exec实例 |
|
|
|
Exec exec = new Exec(apiClient); |
|
|
|
String[] cmd = { "/bin/sh", "-c", command}; |
|
|
|
String[] cmd = {"/bin/sh", "-c", command}; |
|
|
|
Process proc = exec.exec(item, cmd, false); |
|
|
|
// 读取输出 |
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); |
|
|
|
@@ -543,10 +541,11 @@ public class K8sClientUtil { |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据Pod的名称和Namespace查询Pod的状态 |
|
|
|
* @param podName Pod的名称 |
|
|
|
* |
|
|
|
* @param podName Pod的名称 |
|
|
|
* @param namespace Pod所在的Namespace |
|
|
|
*/ |
|
|
|
public String getPodStatus(String podName, String namespace) throws Exception { |
|
|
|
public String getPodStatus(String podName, String namespace) throws Exception { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); |
|
|
|
return pod.getStatus().getPhase(); |
|
|
|
@@ -554,14 +553,15 @@ public class K8sClientUtil { |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据Pod的名称和Namespace查询Pod的容器信息 |
|
|
|
* @param podName Pod的名称 |
|
|
|
* |
|
|
|
* @param podName Pod的名称 |
|
|
|
* @param namespace Pod所在的Namespace |
|
|
|
*/ |
|
|
|
public String getPodContainerId(String podName, String namespace) throws Exception { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); |
|
|
|
|
|
|
|
if(pod.getStatus().getContainerStatuses().size() !=1){ |
|
|
|
if (pod.getStatus().getContainerStatuses().size() != 1) { |
|
|
|
throw new RuntimeException("容器错误"); |
|
|
|
} |
|
|
|
String containerId = pod.getStatus().getContainerStatuses().get(0).getContainerID().split("//")[1]; |
|
|
|
@@ -580,10 +580,10 @@ public class K8sClientUtil { |
|
|
|
return pod.getSpec().getNodeName(); |
|
|
|
} |
|
|
|
|
|
|
|
public String getPodLogs(String podName,String namespace,String container,int line) { |
|
|
|
public String getPodLogs(String podName, String namespace, String container, int line) { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
try { |
|
|
|
String log = api.readNamespacedPodLog(podName, namespace, StringUtils.isEmpty(container)?null:container, null, null, null, null,null, null, line, null); |
|
|
|
String log = api.readNamespacedPodLog(podName, namespace, StringUtils.isEmpty(container) ? null : container, null, null, null, null, null, null, line, null); |
|
|
|
return log; |
|
|
|
} catch (ApiException e) { |
|
|
|
throw new RuntimeException("获取Pod日志异常", e); |
|
|
|
@@ -592,7 +592,7 @@ public class K8sClientUtil { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public V1Pod createPodWithEnv(String podName,String namespace,String proxyUrl ,String mountPath,String pvcName, String image){ |
|
|
|
public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String pvcName, String image) { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
V1PodList v1PodList = null; |
|
|
|
V1Pod pod = new V1PodBuilder() |
|
|
|
@@ -636,7 +636,7 @@ public class K8sClientUtil { |
|
|
|
/** |
|
|
|
* 删除 Pod |
|
|
|
* |
|
|
|
* @param podName Pod 名称 |
|
|
|
* @param podName Pod 名称 |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @throws ApiException 异常 |
|
|
|
*/ |
|
|
|
@@ -655,7 +655,7 @@ public class K8sClientUtil { |
|
|
|
/** |
|
|
|
* 删除 Service |
|
|
|
* |
|
|
|
* @param svcName Service 名称 |
|
|
|
* @param svcName Service 名称 |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @throws ApiException 异常 |
|
|
|
*/ |
|
|
|
@@ -674,7 +674,7 @@ public class K8sClientUtil { |
|
|
|
/** |
|
|
|
* 检查 Pod 是否存在 |
|
|
|
* |
|
|
|
* @param podName Pod 名称 |
|
|
|
* @param podName Pod 名称 |
|
|
|
* @param namespace 命名空间 |
|
|
|
* @return 是否存在 |
|
|
|
* @throws ApiException 异常 |
|
|
|
@@ -682,7 +682,7 @@ public class K8sClientUtil { |
|
|
|
public boolean checkPodExists(String podName, String namespace) throws ApiException { |
|
|
|
CoreV1Api api = new CoreV1Api(apiClient); |
|
|
|
try { |
|
|
|
api.readNamespacedPod(podName, namespace, null,false,false); |
|
|
|
api.readNamespacedPod(podName, namespace, null, false, false); |
|
|
|
return true; |
|
|
|
} catch (ApiException e) { |
|
|
|
if (e.getCode() == 404) { |
|
|
|
|