| @@ -54,7 +54,8 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||
| private String argoWorkflowPodLog; | |||
| @Value("${argo.ins.logsLines}") | |||
| private int logsLines; | |||
| @Resource | |||
| private K8sClientUtil k8sClientUtil; | |||
| private final MinioUtil minioUtil; | |||
| public ExperimentInsServiceImpl(MinioUtil minioUtil) { | |||
| @@ -520,7 +521,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||
| @Override | |||
| public String getRealtimePodLogFromPod(PodLogVo podLogVo) { | |||
| return K8sClientUtil.getPodLogs(podLogVo.getPodName(), podLogVo.getNamespace(),podLogVo.getContainerName(), logsLines); | |||
| return k8sClientUtil.getPodLogs(podLogVo.getPodName(), podLogVo.getNamespace(),podLogVo.getContainerName(), logsLines); | |||
| } | |||
| private boolean isTerminatedState(ExperimentIns ins) throws IOException { | |||
| @@ -1,30 +1,28 @@ | |||
| package com.ruoyi.platform.service.impl; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.domain.*; | |||
| import com.ruoyi.platform.domain.Image; | |||
| import com.ruoyi.platform.domain.ImageVersion; | |||
| import com.ruoyi.platform.mapper.ImageDao; | |||
| import com.ruoyi.platform.mapper.ImageVersionDao; | |||
| import com.ruoyi.platform.service.ImageService; | |||
| import com.ruoyi.platform.service.ImageVersionService; | |||
| import com.ruoyi.platform.service.MinioService; | |||
| import com.ruoyi.platform.utils.FileUtil; | |||
| import com.ruoyi.platform.utils.K8sClientUtil; | |||
| import com.ruoyi.platform.vo.ImageVo; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import io.kubernetes.client.openapi.models.V1Pod; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageImpl; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.transaction.annotation.Transactional; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import javax.annotation.Resource; | |||
| import java.io.InputStream; | |||
| import java.util.Date; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| /** | |||
| @@ -45,7 +43,8 @@ public class ImageServiceImpl implements ImageService { | |||
| @Resource | |||
| private ImageVersionDao imageVersionDao; | |||
| @Resource | |||
| private K8sClientUtil k8sClientUtil; | |||
| @Resource | |||
| private MinioService minioService; | |||
| @Value("${harbor.bucketName}") | |||
| @@ -194,17 +193,17 @@ public class ImageServiceImpl implements ImageService { | |||
| @Override | |||
| public String createImageFromNet(String imageName, String imageTag, String netPath) throws Exception { | |||
| // 得到容器 | |||
| V1Pod pod = K8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| if (pod == null) { | |||
| throw new Exception("镜像推送服务不存在"); | |||
| } | |||
| String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; | |||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | |||
| String loginlog = K8sClientUtil.executeCommand(pod,loginCmd); | |||
| String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); | |||
| // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | |||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||
| // | |||
| String logs2 = K8sClientUtil.executeCommand(pod,"docker pull "+netPath); | |||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker pull "+netPath); | |||
| // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | |||
| if (StringUtils.isNoneBlank(logs2)){ | |||
| String substring = logs2.substring(logs2.indexOf(harborUrl), logs2.length()); | |||
| @@ -212,8 +211,8 @@ public class ImageServiceImpl implements ImageService { | |||
| String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | |||
| String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | |||
| String cmd2 = "docker push " + imageUrl; | |||
| String s = K8sClientUtil.executeCommand(pod, cmd1); | |||
| if (StringUtils.isNotEmpty(K8sClientUtil.executeCommand(pod, cmd2))){ | |||
| String s = k8sClientUtil.executeCommand(pod, cmd1); | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | |||
| return imageUrl; | |||
| }else { | |||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||
| @@ -226,18 +225,18 @@ public class ImageServiceImpl implements ImageService { | |||
| @Override | |||
| public String createImageFromLocal(String imageName, String imageTag, String path) throws Exception { | |||
| // 得到容器 | |||
| V1Pod pod = K8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| if (pod == null) { | |||
| throw new Exception("镜像推送服务不存在"); | |||
| } | |||
| String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; | |||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | |||
| String loginlog = K8sClientUtil.executeCommand(pod,loginCmd); | |||
| String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); | |||
| // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | |||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||
| // | |||
| String filePath = "/data/argo-workflow/" + bucketName + "/" +path; | |||
| String logs2 = K8sClientUtil.executeCommand(pod,"docker load -i "+filePath); | |||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker load -i "+filePath); | |||
| // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | |||
| if (StringUtils.isNoneBlank(logs2)){ | |||
| String substring = logs2.substring(logs2.indexOf(harborUrl), logs2.length()); | |||
| @@ -245,8 +244,8 @@ public class ImageServiceImpl implements ImageService { | |||
| String cmd1 = "docker tag " + cleanedString+ " " + harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | |||
| String imageUrl = harborUrl+"/"+repository+"/"+username+"/" + imageName + imageTag; | |||
| String cmd2 = "docker push " + imageUrl; | |||
| String s = K8sClientUtil.executeCommand(pod, cmd1); | |||
| if (StringUtils.isNotEmpty(K8sClientUtil.executeCommand(pod, cmd2))){ | |||
| String s = k8sClientUtil.executeCommand(pod, cmd1); | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, cmd2))){ | |||
| return imageUrl; | |||
| }else { | |||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | |||
| @@ -34,6 +34,8 @@ public class JupyterServiceImpl implements JupyterService { | |||
| private final MinioUtil minioUtil; | |||
| @Resource | |||
| private K8sClientUtil k8sClientUtil; | |||
| @Resource | |||
| private MlflowUtil mlflowUtil; | |||
| @@ -46,8 +48,8 @@ public class JupyterServiceImpl implements JupyterService { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String podName = loginUser.getUsername().toLowerCase() + "-editor-pod"; | |||
| String pvcName = loginUser.getUsername().toLowerCase() + "-editor-pvc"; | |||
| V1PersistentVolumeClaim pvc = K8sClientUtil.createPvc(namespace, pvcName, storage,storageClassName); | |||
| Integer podPort = K8sClientUtil.createPod(podName, namespace, port, mountPath, pvc, image); | |||
| V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage,storageClassName); | |||
| Integer podPort = k8sClientUtil.createPod(podName, namespace, port, mountPath, pvc, image); | |||
| return masterIp + ":" + podPort; | |||
| } | |||
| @@ -12,6 +12,7 @@ import net.sf.jsqlparser.schema.Database; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Service; | |||
| import javax.annotation.Resource; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.Date; | |||
| @@ -25,7 +26,8 @@ public class TensorBoardServiceImpl implements TensorBoardService { | |||
| private String mountPath; | |||
| @Value("${tensorBoard.masterIp}") | |||
| private String masterIp; | |||
| @Resource | |||
| private K8sClientUtil k8sClientUtil; | |||
| @Override | |||
| public String getTensorBoardStatus(FrameLogPathVo frameLogPathVo){ | |||
| String status = TensorBoardStatus.Terminated.getName(); | |||
| @@ -36,7 +38,7 @@ public class TensorBoardServiceImpl implements TensorBoardService { | |||
| String podName = loginUser.getUsername().toLowerCase()+"-"+frameLogPathVo.getPath().split("/")[2]+ "-tensorboard-pod"; | |||
| try { | |||
| String podStatus = K8sClientUtil.getPodStatus(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace()) ? "default" : frameLogPathVo.getNamespace()); | |||
| String podStatus = k8sClientUtil.getPodStatus(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace()) ? "default" : frameLogPathVo.getNamespace()); | |||
| System.out.println(podStatus); | |||
| } catch (Exception e) { | |||
| return TensorBoardStatus.Terminated.getName(); | |||
| @@ -51,7 +53,7 @@ public class TensorBoardServiceImpl implements TensorBoardService { | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String podName = loginUser.getUsername().toLowerCase()+"-"+frameLogPathVo.getPath().split("/")[2]+ "-tensorboard-pod"; | |||
| Integer podPort = K8sClientUtil.createPodWithSubPath(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace())?"default":frameLogPathVo.getNamespace(), port, mountPath,frameLogPathVo.getPath(), frameLogPathVo.getPvcName(), image); | |||
| Integer podPort = k8sClientUtil.createPodWithSubPath(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace())?"default":frameLogPathVo.getNamespace(), port, mountPath,frameLogPathVo.getPath(), frameLogPathVo.getPvcName(), image); | |||
| return masterIp + ":" + podPort; | |||
| } | |||
| } | |||
| @@ -35,12 +35,8 @@ import java.util.Map; | |||
| @Slf4j | |||
| @Component | |||
| public class K8sClientUtil { | |||
| @Value("${k8s.http}") | |||
| private String http; | |||
| @Value("${k8s.token}") | |||
| private String token; | |||
| /** | |||
| * k8s-api客户端 | |||
| */ | |||
| @@ -54,6 +50,19 @@ public class K8sClientUtil { | |||
| * 3. service-account namespace | |||
| * 4. master endpoints(ip, port) from pre-set environment variables | |||
| */ | |||
| @Autowired | |||
| public K8sClientUtil(@Value("${k8s.http}") String http, @Value("${k8s.token}") String token) { | |||
| this.http = http; | |||
| this.token = token; | |||
| try { | |||
| this.apiClient = new ClientBuilder(). | |||
| setBasePath(http).setVerifyingSsl(false). | |||
| setAuthentication(new AccessTokenAuthentication(token)).build(); | |||
| } catch (Exception e) { | |||
| log.error("构建K8s-Client异常", e); | |||
| throw new RuntimeException("构建K8s-Client异常"); | |||
| } | |||
| } | |||
| // @Autowired | |||
| // public K8sClientUtil() { | |||
| // try { | |||
| @@ -65,12 +74,12 @@ public class K8sClientUtil { | |||
| // throw new RuntimeException("构建K8s-Client异常"); | |||
| // } | |||
| // } | |||
| @PostConstruct | |||
| public void init() { | |||
| this.apiClient = new ClientBuilder(). | |||
| setBasePath(http).setVerifyingSsl(false). | |||
| setAuthentication(new AccessTokenAuthentication(token)).build(); | |||
| } | |||
| // @PostConstruct | |||
| // public void init() { | |||
| // this.apiClient = new ClientBuilder(). | |||
| // setBasePath(http).setVerifyingSsl(false). | |||
| // setAuthentication(new AccessTokenAuthentication(token)).build(); | |||
| // } | |||
| /** | |||
| * 构建集群外通过UA访问的客户端 | |||
| @@ -78,7 +87,7 @@ public class K8sClientUtil { | |||
| * | |||
| * @param kubeConfigPath kube连接配置文件 | |||
| */ | |||
| // public K8sClientUtil(String kubeConfigPath) { | |||
| // public K8sClientUtil() { | |||
| // try { | |||
| // this.apiClient = new ClientBuilder(). | |||
| // setBasePath("https://172.20.32.181:6443").setVerifyingSsl(false). | |||
| @@ -174,7 +183,7 @@ public class K8sClientUtil { | |||
| * @param pvcName 服务名称 | |||
| * @return 创建成功的service对象 | |||
| */ | |||
| public static 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; | |||
| @@ -229,7 +238,7 @@ public class K8sClientUtil { | |||
| * @return 创建成功的pod,的nodePort端口 | |||
| */ | |||
| public static 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); | |||
| @@ -299,7 +308,7 @@ public class K8sClientUtil { | |||
| * @return 创建成功的pod,的nodePort端口 | |||
| */ | |||
| public static 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); | |||
| @@ -361,7 +370,7 @@ public class K8sClientUtil { | |||
| * | |||
| * @return podList | |||
| */ | |||
| public static 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; | |||
| @@ -381,7 +390,7 @@ public class K8sClientUtil { | |||
| return null; | |||
| } | |||
| public static String executeCommand(V1Pod item, String command) { | |||
| public String executeCommand(V1Pod item, String command) { | |||
| try { | |||
| // 创建API实例 | |||
| // 创建Exec实例 | |||
| @@ -408,13 +417,13 @@ public class K8sClientUtil { | |||
| * @param podName Pod的名称 | |||
| * @param namespace Pod所在的Namespace | |||
| */ | |||
| public static 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(); | |||
| } | |||
| public static 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); | |||