上传镜像到目标主机功能
This commit is contained in:
parent
6d6c2c8f58
commit
cb22cd43c6
@ -27,6 +27,10 @@
|
|||||||
<groupId>cd.casic.boot</groupId>
|
<groupId>cd.casic.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cd.casic.boot</groupId>
|
||||||
|
<artifactId>module-ci-machine</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.docker-java</groupId>
|
<groupId>com.github.docker-java</groupId>
|
||||||
<artifactId>docker-java</artifactId>
|
<artifactId>docker-java</artifactId>
|
||||||
@ -61,6 +65,10 @@
|
|||||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||||
<version>3.1.0</version>
|
<version>3.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jsch</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ import cd.casic.module.execute.docker.dataobject.model.DockerImage;
|
|||||||
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
|
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
|
||||||
import cd.casic.module.execute.docker.service.IImageService;
|
import cd.casic.module.execute.docker.service.IImageService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
@ -47,4 +49,14 @@ public class DockerImageController {
|
|||||||
return success(imageService.getLocalImagePage(pageVO));
|
return success(imageService.getLocalImagePage(pageVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/localImagePush")
|
||||||
|
@Operation(summary = "镜像推送,或者部署到目标服务器")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "imageId", description = "镜像id"),
|
||||||
|
@Parameter(name = "machineId", description = "主机id")
|
||||||
|
})
|
||||||
|
@PreAuthorize("@ss.hasPermission('docker:images:localImagePush')")
|
||||||
|
public CommonResult localImagePush(@RequestParam(value = "imageId") String imageId, @RequestParam("machineId") String machineId) {
|
||||||
|
return success(imageService.localImagePush(imageId,machineId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package cd.casic.module.execute.docker.dataobject.convert;
|
|
||||||
|
|
||||||
import cd.casic.module.execute.docker.dataobject.dto.DockerImageDo;
|
|
||||||
import cd.casic.module.execute.docker.dataobject.model.DockerImage;
|
|
||||||
import org.mapstruct.Mapper;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Yuru Pu
|
|
||||||
* @version 1.0
|
|
||||||
* @since 2025/7/23 17:16
|
|
||||||
*/
|
|
||||||
@Mapper(componentModel = "spring")
|
|
||||||
public interface DockerImageConvert {
|
|
||||||
DockerImageConvert INSTANCE = Mappers.getMapper(DockerImageConvert.class);
|
|
||||||
|
|
||||||
DockerImageDo convert(DockerImage dockerImage);
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +1,6 @@
|
|||||||
package cd.casic.module.execute.docker.dataobject.model;
|
package cd.casic.module.execute.docker.dataobject.model;
|
||||||
|
|
||||||
import cd.casic.framework.commons.dataobject.BaseDO;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地镜像
|
* 本地镜像
|
||||||
@ -12,8 +10,7 @@ import lombok.experimental.Accessors;
|
|||||||
* @since 2025/7/23 16:22
|
* @since 2025/7/23 16:22
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
public class DockerImage {
|
||||||
public class DockerImage extends BaseDO {
|
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
|
@ -109,4 +109,6 @@ public interface IImageService {
|
|||||||
int localImageUpload(DockerImage dockerImage);
|
int localImageUpload(DockerImage dockerImage);
|
||||||
|
|
||||||
PageResult<DockerImageDo> getLocalImagePage(DockerImagePageReqVO pageVO);
|
PageResult<DockerImageDo> getLocalImagePage(DockerImagePageReqVO pageVO);
|
||||||
|
|
||||||
|
Object localImagePush(String imageId, String machineId);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,33 @@
|
|||||||
package cd.casic.module.execute.docker.service.impl;
|
package cd.casic.module.execute.docker.service.impl;
|
||||||
|
|
||||||
|
import cd.casic.ci.commons.properties.TargetFileUploadProperties;
|
||||||
import cd.casic.framework.commons.pojo.PageResult;
|
import cd.casic.framework.commons.pojo.PageResult;
|
||||||
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||||
import cd.casic.module.execute.docker.dao.DockerImageDao;
|
import cd.casic.module.execute.docker.dao.DockerImageDao;
|
||||||
import cd.casic.module.execute.docker.dataobject.convert.DockerImageConvert;
|
|
||||||
import cd.casic.module.execute.docker.dataobject.dto.DockerImageDo;
|
import cd.casic.module.execute.docker.dataobject.dto.DockerImageDo;
|
||||||
import cd.casic.module.execute.docker.dataobject.model.DockerImage;
|
import cd.casic.module.execute.docker.dataobject.model.DockerImage;
|
||||||
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
|
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
|
||||||
import cd.casic.module.execute.docker.service.IImageService;
|
import cd.casic.module.execute.docker.service.IImageService;
|
||||||
|
import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
|
||||||
|
import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
|
||||||
|
import cd.casic.module.machine.dal.mysql.MachineInfoMapper;
|
||||||
|
import cd.casic.module.machine.dal.mysql.SecretKeyMapper;
|
||||||
|
import cd.casic.module.machine.enums.AuthenticationType;
|
||||||
|
import cd.casic.module.machine.utils.CryptogramUtil;
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.extra.ftp.FtpConfig;
|
||||||
|
import cn.hutool.extra.ssh.JschUtil;
|
||||||
|
import cn.hutool.extra.ssh.Sftp;
|
||||||
import com.github.dockerjava.api.DockerClient;
|
import com.github.dockerjava.api.DockerClient;
|
||||||
import com.github.dockerjava.api.command.InspectImageResponse;
|
import com.github.dockerjava.api.command.InspectImageResponse;
|
||||||
import com.github.dockerjava.api.command.SaveImageCmd;
|
import com.github.dockerjava.api.command.SaveImageCmd;
|
||||||
import com.github.dockerjava.api.exception.NotFoundException;
|
import com.github.dockerjava.api.exception.NotFoundException;
|
||||||
import com.github.dockerjava.api.model.Image;
|
import com.github.dockerjava.api.model.Image;
|
||||||
import com.github.dockerjava.api.model.PruneType;
|
import com.github.dockerjava.api.model.PruneType;
|
||||||
|
import com.jcraft.jsch.Session;
|
||||||
import jakarta.annotation.Nonnull;
|
import jakarta.annotation.Nonnull;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -24,11 +35,11 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.io.FileOutputStream;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 镜像的服务类
|
* @description: 镜像的服务类
|
||||||
@ -46,6 +57,15 @@ public class ImageService implements IImageService {
|
|||||||
@Resource
|
@Resource
|
||||||
private DockerImageDao dockerImageDao;
|
private DockerImageDao dockerImageDao;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MachineInfoMapper machineInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TargetFileUploadProperties fileUploadProperties;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SecretKeyMapper secretKeyMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Image> list(@Nonnull String clientId) {
|
public List<Image> list(@Nonnull String clientId) {
|
||||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||||
@ -144,7 +164,9 @@ public class ImageService implements IImageService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public int localImageUpload(DockerImage dockerImage) {
|
public int localImageUpload(DockerImage dockerImage) {
|
||||||
return dockerImageDao.insert(DockerImageConvert.INSTANCE.convert(dockerImage));
|
DockerImageDo imageDo = new DockerImageDo();
|
||||||
|
BeanUtil.copyProperties(dockerImage,imageDo);
|
||||||
|
return dockerImageDao.insert(imageDo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -153,4 +175,59 @@ public class ImageService implements IImageService {
|
|||||||
PageResult<DockerImageDo> page = dockerImageDao.selectPage(pageVO, queryWrapperX.likeIfPresent(DockerImageDo::getName, pageVO.getName()).orderByDesc(DockerImageDo::getCreateTime));
|
PageResult<DockerImageDo> page = dockerImageDao.selectPage(pageVO, queryWrapperX.likeIfPresent(DockerImageDo::getName, pageVO.getName()).orderByDesc(DockerImageDo::getCreateTime));
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 先下载后上传到目标主机
|
||||||
|
* @param imageId
|
||||||
|
* @param machineId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object localImagePush(String imageId, String machineId) {
|
||||||
|
if (Objects.isNull(imageId) || Objects.isNull(machineId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DockerImageDo imageDo = dockerImageDao.selectById(imageId);
|
||||||
|
//1 远程下载
|
||||||
|
// 1.1 建立连接 下载
|
||||||
|
Sftp sftp = getSftp(FtpConfig.create().setHost(fileUploadProperties.getRemoteHost()).setPort(fileUploadProperties.getRemotePort()).setUser(fileUploadProperties.getUsername()).setPassword(fileUploadProperties.getPassword()));
|
||||||
|
String srcPath = imageDo.getPath();
|
||||||
|
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
|
||||||
|
sftp.download(srcPath, byteOut); //远程下载到中间缓存区
|
||||||
|
sftp.close();
|
||||||
|
// 2 建立连接 区分密码还是秘钥
|
||||||
|
MachineInfoDO machineInfoDO = machineInfoMapper.selectById(machineId);
|
||||||
|
FtpConfig targetFtp = FtpConfig.create().setHost(machineInfoDO.getHostIp()).setPort(machineInfoDO.getSshPort()).setUser(machineInfoDO.getUsername()).setPassword(CryptogramUtil.doDecrypt(machineInfoDO.getPassword()));
|
||||||
|
if (AuthenticationType.of(machineInfoDO.getAuthenticationType()).equals(AuthenticationType.SECRET_KEY)) {
|
||||||
|
SecretKeyDO secretKeyDO = secretKeyMapper.selectById(machineInfoDO.getSecretKeyId());
|
||||||
|
targetFtp.setSystemKey(CryptogramUtil.doDecrypt(secretKeyDO.getPrivateKey()));
|
||||||
|
targetFtp.setPassword(CryptogramUtil.doDecrypt(secretKeyDO.getPassword()));
|
||||||
|
}
|
||||||
|
Sftp uploadSftp = getSftp(targetFtp);
|
||||||
|
// 2.1 上传
|
||||||
|
String suffix = FileUtil.getSuffix(srcPath);
|
||||||
|
String fileName = imageDo.getName() + "." + suffix;
|
||||||
|
ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(byteOut.toByteArray()); //转换
|
||||||
|
String romPath = "/home/image/" + UUID.randomUUID()+"/";
|
||||||
|
uploadSftp.mkDirs(romPath);//递归创建
|
||||||
|
uploadSftp.upload(romPath, fileName, arrayInputStream);
|
||||||
|
uploadSftp.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 获取Sftp连接
|
||||||
|
* @param config 连接配置
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Sftp getSftp(FtpConfig config){
|
||||||
|
Session session;
|
||||||
|
if (Objects.nonNull(config.getSystemKey())) {
|
||||||
|
session = JschUtil.getSession(config.getHost(), config.getPort(), config.getUser(), config.getSystemKey().getBytes(StandardCharsets.UTF_8), config.getPassword().getBytes());
|
||||||
|
} else {
|
||||||
|
session = JschUtil.getSession(config.getHost(), config.getPort(), config.getUser(), config.getPassword());
|
||||||
|
}
|
||||||
|
return new Sftp(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user