提交容器 ,镜像,的操作代码,现在只有启动没有写单元测试了,其他的都完成了
This commit is contained in:
parent
1d64da41bb
commit
1daa1f12df
3
.idea/inspectionProfiles/Project_Default.xml
generated
3
.idea/inspectionProfiles/Project_Default.xml
generated
@ -63,6 +63,9 @@
|
||||
<inspection_tool class="AlibabaUnsupportedExceptionWithModifyAsList" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AlibabaUseQuietReferenceNotation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AlibabaUseRightCaseForDateFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.util.Optional,orElseThrow" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ADDITIONAL_TAGS" value="Created,Date" />
|
||||
</inspection_tool>
|
||||
|
24
dependencies/.flattened-pom.xml
vendored
24
dependencies/.flattened-pom.xml
vendored
@ -13,6 +13,7 @@
|
||||
<podam.version>8.0.0.RELEASE</podam.version>
|
||||
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
|
||||
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
|
||||
<okhttp.version>4.12.0</okhttp.version>
|
||||
<mapstruct.version>1.6.2</mapstruct.version>
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<sqlite.version>3.47.1.0</sqlite.version>
|
||||
@ -52,7 +53,7 @@
|
||||
<pf4j.version>3.12.1</pf4j.version>
|
||||
<logback.version>1.2.13</logback.version>
|
||||
<mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
|
||||
<docker-java.version>3.5.0</docker-java.version>
|
||||
<docker-java.version>3.2.13</docker-java.version>
|
||||
<hutool-5.version>5.8.32</hutool-5.version>
|
||||
<revision>2.0.0-jdk17</revision>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
@ -573,11 +574,32 @@
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
<version>${docker-java.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java-transport-httpclient5</artifactId>
|
||||
<version>${docker-java.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.winp</groupId>
|
||||
|
24
dependencies/pom.xml
vendored
24
dependencies/pom.xml
vendored
@ -68,6 +68,7 @@
|
||||
<bizlog-sdk.version>3.0.6</bizlog-sdk.version>
|
||||
<netty.version>4.1.113.Final</netty.version>
|
||||
<oshi-version>6.6.5</oshi-version>
|
||||
<okhttp.version>4.12.0</okhttp.version>
|
||||
<!-- 三方云服务相关 -->
|
||||
<commons-io.version>2.17.0</commons-io.version>
|
||||
<commons-compress.version>1.27.1</commons-compress.version>
|
||||
@ -656,14 +657,33 @@
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
<version>${docker-java.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>guava</artifactId>
|
||||
<groupId>com.google.guava</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<groupId>commons-io</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java-transport-httpclient5</artifactId>
|
||||
<version>${docker-java.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- devops ci- worker start-->
|
||||
<dependency>
|
||||
<groupId>org.jvnet.winp</groupId>
|
||||
|
@ -37,7 +37,6 @@ public class BaseDbUnitTest {
|
||||
OpsMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
|
||||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
||||
MybatisPlusJoinAutoConfiguration.class, // MyBatis 的Join配置类
|
||||
|
||||
// 其它配置类
|
||||
SpringUtil.class
|
||||
})
|
||||
|
7
modules/module-ci-execute/Readme.md
Normal file
7
modules/module-ci-execute/Readme.md
Normal file
@ -0,0 +1,7 @@
|
||||
这个目前制作了docker 的服务,
|
||||
问题一:目的是之前使用ssh进行cmd命令,但是对话框中要使用docker exec/attch等进入容器执行对象的命令,这种方式不太理想
|
||||
问题二:如afl等之类的场景,你只有等容器启动了后才能够知道你的容器id,name虽然可以进行提前设置,但是有冲突的风险,name冲突可以使用
|
||||
Ops+随机数+镜像名称解决,关闭时候需要输入命令docker rm -f xxx进行关闭,或者脚本,目前考虑使用docker 的api进行操作
|
||||
问题三:容器的启动,停止等操作,缺乏统一的操作,同时缺少容器的监控方面内容
|
||||
问题四:容器的日志方面,同问题一一样,需要获取到日志,依赖ssh,存在问题
|
||||
问题五:最好其实和k8s一样,使用go这种云原生的方式,但是这种方式增加了运维的难度,暂时都放到一起,为了方便部署
|
@ -19,22 +19,37 @@
|
||||
<groupId>cd.casic.boot</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cd.casic.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cd.casic.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java-transport-httpclient5</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<version>5.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.core5</groupId>
|
||||
<artifactId>httpcore5</artifactId>
|
||||
<version>5.3.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,76 @@
|
||||
package cd.casic.module.execute.docker;
|
||||
|
||||
import cd.casic.module.execute.docker.dao.DockerEndpointDao;
|
||||
import cd.casic.module.execute.docker.dataobject.convert.DockerEndpointConvert;
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* @description: docker客户端工厂
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:39
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DockerClientFactory implements CommandLineRunner {
|
||||
|
||||
@Resource
|
||||
private DockerEndpointDao dockerEndpointDao;
|
||||
@Getter
|
||||
private final Map<String, DockerClient> clientGroup = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
/*如果在ops里面之前添加过,数据库之前有,那么启动就加载,如果是手动添加的,后面要注意控制*/
|
||||
dockerEndpointDao.selectList().stream()
|
||||
.map(DockerEndpointConvert.INSTANCE::convert)
|
||||
.forEach(endpoint -> {
|
||||
ApacheDockerHttpClient httpClient = createHttpClient(endpoint);
|
||||
if (httpClient != null) {
|
||||
DockerClient client = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
|
||||
clientGroup.put(endpoint.getId(), client);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ApacheDockerHttpClient createHttpClient(DockerEndpoint endpoint) {
|
||||
try {
|
||||
URI dockerHost;
|
||||
if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.LOCAL) {
|
||||
// 使用本地挂载
|
||||
dockerHost = new URI("unix:///var/run/docker.sock");
|
||||
} else if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.REMOTE) {
|
||||
// 远程挂载
|
||||
dockerHost = new URI(format("tcp://%s:%s", endpoint.getHost(), endpoint.getPort()));
|
||||
} else {
|
||||
log.error("Unsupported Docker endpoint type: {}", endpoint.getType());
|
||||
return null;
|
||||
}
|
||||
return new ApacheDockerHttpClient.Builder()
|
||||
.dockerHost(dockerHost)
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI for Docker endpoint {}: {}", endpoint.getId(), e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public DockerClient getdockerClient(String id) {
|
||||
return clientGroup.get(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package cd.casic.module.execute.docker.api;
|
||||
|
||||
import cd.casic.framework.commons.pojo.CommonResult;
|
||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||
import cd.casic.module.execute.docker.dao.DockerEndpointDao;
|
||||
import cd.casic.module.execute.docker.dataobject.convert.DockerEndpointConvert;
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: 容器的管理功能
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 11:14
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Tag(name = "docker管理 - 获取docker列表")
|
||||
@RestController
|
||||
@RequestMapping("/api/dockerClient")
|
||||
@RequiredArgsConstructor
|
||||
public class DockerClientController {
|
||||
|
||||
private final DockerEndpointDao dockerEndpointDao;
|
||||
private final DockerClientFactory dockerClientFactory;
|
||||
|
||||
@GetMapping
|
||||
public CommonResult<List<DockerEndpoint>> list() {
|
||||
List<DockerEndpoint> collect = dockerEndpointDao
|
||||
.selectList()
|
||||
.stream()
|
||||
.map(DockerEndpointConvert.INSTANCE::convert)
|
||||
.toList();
|
||||
return CommonResult.success(collect);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public CommonResult<Boolean> testDockerClient(String dockerClientId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(dockerClientId);
|
||||
dockerClient.pingCmd().exec();
|
||||
return CommonResult.success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cd.casic.module.execute.docker.api;
|
||||
|
||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 11:13
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Tag(name = "docker管理 - 容器管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/container")
|
||||
@RequiredArgsConstructor
|
||||
public class DockerContainerController {
|
||||
|
||||
private final DockerClientFactory dockerClientFactory;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package cd.casic.module.execute.docker.api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:25
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Tag(name = "docker管理 - 镜像管理")
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/images")
|
||||
public class DockerImageController {
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cd.casic.module.execute.docker.api;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 11:14
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class DockerMonitorController {
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package cd.casic.module.execute.docker.callback;
|
||||
|
||||
import com.github.dockerjava.api.async.ResultCallback;
|
||||
import com.github.dockerjava.api.model.Frame;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @description: 之前版本用的ExecStartResultCallback实现,现在废弃了,使用ResultCallback.Adapter<Frame>,未测试
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 18:09
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LoggingCallback extends ResultCallback.Adapter<Frame> {
|
||||
|
||||
private final String containerId;
|
||||
private final String execId;
|
||||
private StringBuffer buffer = new StringBuffer(1024);
|
||||
|
||||
@Override
|
||||
public void onNext(Frame frame) {
|
||||
String streamType = frame.getStreamType().name();
|
||||
String message = new String(frame.getPayload(), StandardCharsets.UTF_8);
|
||||
if (streamType.equals("STDOUT")) {
|
||||
log.info("[容器: {}, ExecID: {}] 标准输出: {}", containerId, execId, message.trim());
|
||||
} else if (streamType.equals("STDERR")) {
|
||||
log.error("[容器: {}, ExecID: {}] 错误输出: {}", containerId, execId, message.trim());
|
||||
}
|
||||
buffer.append(message);
|
||||
super.onNext(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
log.error("[容器: {}, ExecID: {}] 执行命令时出错: {}", containerId, execId, throwable.getMessage());
|
||||
super.onError(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
log.info("[容器: {}, ExecID: {}] 命令执行完毕", containerId, execId);
|
||||
super.onComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
log.debug("[容器: {}, ExecID: {}] 回调已关闭", containerId, execId);
|
||||
super.close();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cd.casic.module.execute.docker.dao;
|
||||
|
||||
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cd.casic.module.execute.docker.dataobject.dto.DockerEndpointDo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:33
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface DockerEndpointDao extends BaseMapperX<DockerEndpointDo> {
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cd.casic.module.execute.docker.dao;
|
||||
|
||||
import cd.casic.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cd.casic.module.execute.docker.dataobject.dto.OperateRecordDo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:58
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface OperateRecordDao extends BaseMapperX<OperateRecordDo> {
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cd.casic.module.execute.docker.dataobject.convert;
|
||||
|
||||
import cd.casic.module.execute.docker.dao.DockerEndpointDao;
|
||||
import cd.casic.module.execute.docker.dataobject.dto.DockerEndpointDo;
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:36
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface DockerEndpointConvert {
|
||||
DockerEndpointConvert INSTANCE = Mappers.getMapper(DockerEndpointConvert.class);
|
||||
|
||||
DockerEndpointDo convert(DockerEndpointDao endpointDao);
|
||||
|
||||
DockerEndpoint convert(DockerEndpointDo endpointDo);
|
||||
|
||||
List<DockerEndpoint> convertList(List<DockerEndpointDo> endpointDos);
|
||||
|
||||
List<DockerEndpointDo> convertList02(List<DockerEndpoint> endpointDos);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cd.casic.module.execute.docker.dataobject.convert;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:57
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Mapper
|
||||
public interface OperateRecordConvert {
|
||||
OperateRecordConvert INSTANCE = Mappers.getMapper(OperateRecordConvert.class);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package cd.casic.module.execute.docker.dataobject.dto;
|
||||
|
||||
import cd.casic.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @description: docker 的端点配置
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:28
|
||||
* @version: 1.0
|
||||
*/
|
||||
@TableName("pipeline_docker_endpoint")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class DockerEndpointDo extends BaseDO {
|
||||
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private DockerEndpoint.DockerEndpointTypeEnum type;
|
||||
|
||||
private DockerEndpoint.DockerEndpointStateEnum state;
|
||||
|
||||
private String host;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private LocalDateTime latestTestTime;
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cd.casic.module.execute.docker.dataobject.dto;
|
||||
|
||||
import cd.casic.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import static cd.casic.module.execute.docker.dataobject.model.OperateRecord.OperatorResource;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:48
|
||||
* @version: 1.0
|
||||
*/
|
||||
@TableName("pipeline_docker_record")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class OperateRecordDo extends BaseDO {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long clientId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String name;
|
||||
|
||||
private OperatorResource resource;
|
||||
|
||||
private String content;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package cd.casic.module.execute.docker.dataobject.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @description: docker 的断电配置类
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:11
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class DockerEndpoint {
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private DockerEndpointTypeEnum type;
|
||||
|
||||
private DockerEndpointStateEnum state = DockerEndpointStateEnum.NORMAL;
|
||||
|
||||
private String host;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private String latestTestTime;
|
||||
|
||||
private String createdAt;
|
||||
|
||||
private String updatedAt;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DockerEndpointTypeEnum {
|
||||
LOCAL("本地"),
|
||||
REMOTE("远程");
|
||||
private final String desc;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DockerEndpointStateEnum {
|
||||
NORMAL("正常"),
|
||||
NOT_CONNECT("无法连接"),
|
||||
AUTH_FAIL("授权失败");
|
||||
private final String desc;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return Optional.ofNullable(this.type).map(DockerEndpointTypeEnum::getDesc).orElse("未知");
|
||||
}
|
||||
|
||||
public String getStateName() {
|
||||
return Optional.ofNullable(this.state).map(DockerEndpointStateEnum::getDesc).orElse("未知");
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package cd.casic.module.execute.docker.dataobject.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:45
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class OperateRecord {
|
||||
|
||||
private String clientId;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String name;
|
||||
|
||||
private OperatorResource resource;
|
||||
|
||||
private Object content;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OperatorResource {
|
||||
IMAGE_v1("操作镜像"),
|
||||
CONTAINER_v1("操作容器"),
|
||||
VOLUME_v1("操作储存卷"),
|
||||
NETWORK_v1("操作网络");
|
||||
private final String desc;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package cd.casic.module.execute.docker.dataobject.model;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @description: 新运行的请求类
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:30
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Data
|
||||
public class RunNewContainer {
|
||||
/**
|
||||
* 使用的镜像ID
|
||||
*/
|
||||
private String imageId;
|
||||
|
||||
/**
|
||||
* 容器名称
|
||||
*/
|
||||
private String containerName;
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
private Map<String, String> envGroup;
|
||||
|
||||
/**
|
||||
* 端口绑定
|
||||
*/
|
||||
private Map<Long, Long> portBound;
|
||||
|
||||
/**
|
||||
* DNS
|
||||
*/
|
||||
private String dns;
|
||||
|
||||
/**
|
||||
* 容器别名
|
||||
*/
|
||||
private String alias;
|
||||
|
||||
/**
|
||||
* 主机名
|
||||
*/
|
||||
private String hostname;
|
||||
|
||||
|
||||
public List<String> findEnvList() {
|
||||
// 若 envGroup 为空,返回空列表;否则将 envGroup 转换为包含键值对字符串的列表
|
||||
return CollUtil.isEmpty(this.envGroup) ? Collections.emptyList() :
|
||||
this.envGroup.entrySet().stream()
|
||||
.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 10:10
|
||||
* @version: 1.0
|
||||
*/
|
||||
package cd.casic.module.execute.docker.dataobject;
|
@ -0,0 +1,95 @@
|
||||
package cd.casic.module.execute.docker.service;
|
||||
|
||||
import cd.casic.module.execute.docker.dataobject.model.RunNewContainer;
|
||||
import com.github.dockerjava.api.command.CreateContainerResponse;
|
||||
import com.github.dockerjava.api.command.InspectContainerResponse;
|
||||
import com.github.dockerjava.api.command.TopContainerResponse;
|
||||
import com.github.dockerjava.api.model.Container;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: 容器服务接口
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 14:27
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface IContainerService {
|
||||
/**
|
||||
* 查询容器列表,这个接口注意一下,showall参数 true 代表的是命令docker ps -a , false代表的是docker ps
|
||||
*
|
||||
* @param showAll
|
||||
*/
|
||||
List<Container> list(String clientId, boolean showAll);
|
||||
|
||||
/**
|
||||
* 运行新的容器
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
CreateContainerResponse run(String clientId, RunNewContainer runNewContainer);
|
||||
|
||||
/**
|
||||
* 启动一个已经存在的容器
|
||||
*
|
||||
* @param containerId 容器ID
|
||||
*/
|
||||
void start(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 停止容器
|
||||
*
|
||||
* @param containerId 停止的容器ID
|
||||
*/
|
||||
void stop(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 暂停容器
|
||||
*
|
||||
* @apiNote 暂停指定容器(异步暂停)
|
||||
*/
|
||||
void pause(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 取消暂停容器
|
||||
*
|
||||
* @param containerId 容器ID
|
||||
* @apiNote 取消暂停容器
|
||||
*/
|
||||
void unpause(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 移除指定容器
|
||||
*
|
||||
* @param containerId 容器ID
|
||||
*/
|
||||
void remove(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 获取容器的资源使用情况
|
||||
*
|
||||
* @param containerId 容器ID
|
||||
*/
|
||||
void rename(String clientId, String containerId, String newName);
|
||||
|
||||
/**
|
||||
* 查询容器的线程信息,默认使用命令aux
|
||||
*
|
||||
* @param containerId 容器ID
|
||||
* @return
|
||||
*/
|
||||
TopContainerResponse top(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 查询容器详情
|
||||
*
|
||||
* @param containerId
|
||||
* @return
|
||||
*/
|
||||
InspectContainerResponse inspect(String clientId, String containerId);
|
||||
|
||||
/**
|
||||
* 容器日志
|
||||
*/
|
||||
void logs(String clientId, String containerId, String... cmd);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cd.casic.module.execute.docker.service;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 14:31
|
||||
* @version: 1.0
|
||||
*/
|
||||
|
||||
public interface IDockerPingService {
|
||||
|
||||
Boolean ping(String clientId);
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package cd.casic.module.execute.docker.service;
|
||||
|
||||
import com.github.dockerjava.api.command.InspectImageResponse;
|
||||
import com.github.dockerjava.api.model.Image;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: 镜像相关服务
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 14:28
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface IImageService {
|
||||
/**
|
||||
* 获取镜像列表
|
||||
*
|
||||
* @param clientId 那个客户端
|
||||
* @return
|
||||
*/
|
||||
List<Image> list(String clientId);
|
||||
|
||||
/**
|
||||
* 通过镜像ID获取镜像
|
||||
*
|
||||
* @param imageId
|
||||
* @return
|
||||
*/
|
||||
InspectImageResponse inspect(String clientId, String imageId);
|
||||
|
||||
/**
|
||||
* 重新打tag。这个打tag注意
|
||||
* hello-world hallo-newworld 74cc54e27dc4 4 months ago 10.1kB
|
||||
* hello-world hallo-newworld1 74cc54e27dc4 4 months ago 10.1kB
|
||||
* hello-world latest 74cc54e27dc4 4 months ago 10.1kB
|
||||
* 类似与上面这样,但是你删除,docker rmi 74cc54e27dc4 ,那这三个全部gg
|
||||
*
|
||||
* @param imageId 镜像ID
|
||||
* @param newTag 新的镜像Tag
|
||||
*/
|
||||
void tag(@Nonnull String clientId, String imageId, String newTag);
|
||||
|
||||
/**
|
||||
* 移除镜像
|
||||
*
|
||||
* @param imageId 镜像ID
|
||||
* @param force
|
||||
* @return
|
||||
*/
|
||||
void remove(@Nonnull String clientId, String imageId, Boolean force);
|
||||
|
||||
/**
|
||||
* 导出镜像
|
||||
*
|
||||
* @param imageId 镜像ID
|
||||
*/
|
||||
void export(@Nonnull String clientId, String imageId);
|
||||
|
||||
|
||||
/**
|
||||
* 通过文件路径导入镜像导入镜像
|
||||
*
|
||||
* @param file 文件路径
|
||||
*/
|
||||
void importByFile(@Nonnull String clientId, String file);
|
||||
|
||||
/**
|
||||
* 通过Tar文件导入镜像
|
||||
*
|
||||
* @param file
|
||||
*/
|
||||
void importByTar(@Nonnull String clientId, String file);
|
||||
|
||||
/**
|
||||
* @param imageId
|
||||
*/
|
||||
boolean exist(@Nonnull String clientId, String imageId);
|
||||
|
||||
/**
|
||||
* 清理镜像
|
||||
*/
|
||||
void pruneImage(@Nonnull String clientId);
|
||||
|
||||
/**
|
||||
* 镜像保存
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Boolean save(@Nonnull String clientId, String imageId, String outputPath);
|
||||
|
||||
/**
|
||||
* 推送保存,如果你想推送镜像,需要在配置文件中修改镜像仓库
|
||||
* 1: 如果你还想修改名字,或者鉴权,在这里修改
|
||||
* dockerClient.pushImageCmd(imageId)
|
||||
* .withTag("new-tag")
|
||||
* .withname("new-name")
|
||||
* .withAuthConfig(authConfig).exec();
|
||||
* 2:如果做了以上操作,需要新增接口或者自己封装
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Boolean pushImage(@Nonnull String clientId, String imageId);
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cd.casic.module.execute.docker.service;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 14:28
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface IMonitorService {
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cd.casic.module.execute.docker.service;
|
||||
|
||||
import cd.casic.module.execute.docker.dataobject.model.OperateRecord;
|
||||
|
||||
/**
|
||||
* @description: 操作日志查询
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:46
|
||||
* @version: 1.0
|
||||
*/
|
||||
public interface IOperateRecordService {
|
||||
/**
|
||||
* 新增操作日志
|
||||
*/
|
||||
void add(OperateRecord record);
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package cd.casic.module.execute.docker.service.impl;
|
||||
|
||||
import cd.casic.framework.commons.util.json.JsonUtils;
|
||||
import cd.casic.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||
import cd.casic.module.execute.docker.callback.LoggingCallback;
|
||||
import cd.casic.module.execute.docker.dataobject.model.OperateRecord;
|
||||
import cd.casic.module.execute.docker.dataobject.model.RunNewContainer;
|
||||
import cd.casic.module.execute.docker.service.IContainerService;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.async.ResultCallback;
|
||||
import com.github.dockerjava.api.command.CreateContainerResponse;
|
||||
import com.github.dockerjava.api.command.InspectContainerResponse;
|
||||
import com.github.dockerjava.api.command.TopContainerResponse;
|
||||
import com.github.dockerjava.api.model.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:34
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ContainerService implements IContainerService {
|
||||
|
||||
private final DockerClientFactory dockerClientFactory;
|
||||
private final OperateRecordService operateRecordService;
|
||||
|
||||
@Override
|
||||
public List<Container> list(String clientId, boolean showAll) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
return dockerClient.listContainersCmd().withShowAll(showAll).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateContainerResponse run(String clientId, RunNewContainer runNewContainer) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
HostConfig hostConfig = HostConfig.newHostConfig();
|
||||
hostConfig.withBinds(Bind.parse("/host:/container:ro"))
|
||||
.withPortBindings(PortBinding.parse("12:44")).withLinks(Link.parse(""))
|
||||
.withDns(runNewContainer.getDns()).withNetworkMode("网络名");
|
||||
final CreateContainerResponse response = dockerClient
|
||||
.createContainerCmd(runNewContainer.getImageId())
|
||||
.withAliases(runNewContainer.getAlias())
|
||||
.withHostConfig(hostConfig)
|
||||
.withEnv(runNewContainer.findEnvList())
|
||||
.withName(runNewContainer.getContainerName())
|
||||
.withHostName(runNewContainer.getHostname()).exec();
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.startContainerCmd(containerId).exec();
|
||||
log.info("启动容器,containerId={}", containerId);
|
||||
/*增加日志*/
|
||||
extracted(containerId, "启动容器");
|
||||
}
|
||||
|
||||
private void extracted(String containerId, String type) {
|
||||
try {
|
||||
Map<String, String> param = new HashMap<>();
|
||||
param.put("containerId", containerId);
|
||||
param.put("type", type);
|
||||
OperateRecord operateRecord = OperateRecord.builder()
|
||||
.userId(SecurityFrameworkUtils.getLoginUserId())
|
||||
/*这个是没有必要存放的*/
|
||||
.clientId("")
|
||||
.content(JsonUtils.toJsonString(param))
|
||||
.name("未知")
|
||||
.resource(OperateRecord.OperatorResource.CONTAINER_v1).build();
|
||||
operateRecordService.add(operateRecord);
|
||||
} catch (Exception ignore) {
|
||||
//ignore exception
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.stopContainerCmd(containerId).exec();
|
||||
log.info("停止容器,containerId={}", containerId);
|
||||
/*增加日志*/
|
||||
extracted(containerId, "停止容器");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.pauseContainerCmd(containerId).exec();
|
||||
log.info("暂停容器,containerId={}", containerId);
|
||||
extracted(containerId, "暂停容器");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpause(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.unpauseContainerCmd(containerId).exec();
|
||||
log.info("继续容器,containerId={}", containerId);
|
||||
extracted(containerId, "恢复容器");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.removeContainerCmd(containerId)
|
||||
/*删除默认强制删除,并且挂载内容一并删除*/
|
||||
.withForce(true)
|
||||
.withRemoveVolumes(true).exec();
|
||||
log.info("移除容器,containerId={}", containerId);
|
||||
extracted(containerId, "移除容器");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rename(String clientId, String containerId, String newName) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.renameContainerCmd(containerId).withName(newName).exec();
|
||||
log.info("重命名容器:[{}]为[{}]", containerId, newName);
|
||||
extracted(containerId, "重命名容器");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TopContainerResponse top(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
return dockerClient.topContainerCmd(containerId).withPsArgs("aux").exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectContainerResponse inspect(String clientId, String containerId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
final InspectContainerResponse response =
|
||||
dockerClient.inspectContainerCmd(containerId).withSize(Boolean.TRUE).exec();
|
||||
extracted(containerId, "Inspect容器");
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logs(String clientId, String containerId, String... cmd) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
/*创建命令*/
|
||||
String execId = dockerClient.execCreateCmd(containerId)
|
||||
.withCmd(cmd)
|
||||
.withAttachStdin(true)
|
||||
.withAttachStdout(true)
|
||||
.withAttachStderr(true)
|
||||
.withTty(true)
|
||||
.exec().getId();
|
||||
// 执行命令并记录日志
|
||||
ResultCallback<Frame> callback = new LoggingCallback(containerId, execId);
|
||||
/*这个是异步的方法*/
|
||||
dockerClient.execStartCmd(execId)
|
||||
.withTty(true)
|
||||
.exec(callback);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cd.casic.module.execute.docker.service.impl;
|
||||
|
||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||
import cd.casic.module.execute.docker.service.IDockerPingService;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 14:32
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DockerPingService implements IDockerPingService {
|
||||
|
||||
private final DockerClientFactory dockerClientFactory;
|
||||
|
||||
@Override
|
||||
public Boolean ping(String clientId) {
|
||||
DockerClient dockerClient = Optional.of(StringUtils.hasText(clientId) ? clientId : "DEFAULT")
|
||||
.map(id -> id.toUpperCase(Locale.ROOT))
|
||||
.map(dockerClientFactory::getdockerClient)
|
||||
.orElseThrow(() -> new RuntimeException("客户端不存在"));
|
||||
dockerClient.pingCmd().exec();
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package cd.casic.module.execute.docker.service.impl;
|
||||
|
||||
import cd.casic.module.execute.docker.DockerClientFactory;
|
||||
import cd.casic.module.execute.docker.service.IImageService;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.InspectImageResponse;
|
||||
import com.github.dockerjava.api.command.SaveImageCmd;
|
||||
import com.github.dockerjava.api.exception.NotFoundException;
|
||||
import com.github.dockerjava.api.model.Image;
|
||||
import com.github.dockerjava.api.model.PruneType;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description: 镜像的服务类
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 15:06
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ImageService implements IImageService {
|
||||
|
||||
private final DockerClientFactory dockerClientFactory;
|
||||
|
||||
@Override
|
||||
public List<Image> list(@Nonnull String clientId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
return dockerClient.listImagesCmd().exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InspectImageResponse inspect(@Nonnull String clientId, @Nonnull String imageId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
return dockerClient.inspectImageCmd(imageId).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tag(@Nonnull String clientId, String imageId, String newTag) {
|
||||
InspectImageResponse inspect = inspect(clientId, imageId);
|
||||
if (inspect == null) {
|
||||
throw new RuntimeException("操作失败,镜像不存在");
|
||||
}
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.tagImageCmd(imageId, inspect.getRepoTags().get(0), newTag).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(@Nonnull String clientId, String imageId, Boolean force) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.removeImageCmd(imageId).withForce(force).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export(@Nonnull String clientId, String imageId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
/*这个api我要查下,不生效也无所,感觉场景很少*/
|
||||
}
|
||||
|
||||
/*经过测试,只有local 模式下面生效*/
|
||||
@Override
|
||||
public void importByFile(@Nonnull String clientId, String file) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
/*test 测试下,这个不知道生效不*/
|
||||
dockerClient.loadImageCmd(FileUtil.getInputStream(file)).exec();
|
||||
}
|
||||
|
||||
/*经过测试,只有local 模式下面生效*/
|
||||
@Override
|
||||
public void importByTar(@Nonnull String clientId, String file) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
/*test 测试下,这个不知道生效不*/
|
||||
dockerClient.loadImageCmd(FileUtil.getInputStream(file)).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exist(@Nonnull String clientId, String imageId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
try {
|
||||
final InspectImageResponse inspectImage = dockerClient.inspectImageCmd(imageId).exec();
|
||||
return inspectImage != null;
|
||||
} catch (NotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pruneImage(String clientId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
dockerClient.pruneCmd(PruneType.IMAGES).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean save(@Nonnull String clientId, String imageId, String outputPath) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
/*imageid 如 nginx:latest */
|
||||
try (OutputStream fos = new FileOutputStream(outputPath);
|
||||
SaveImageCmd saveImageCmd = dockerClient.saveImageCmd(imageId)) {
|
||||
// 执行命令并将输出写入文件流
|
||||
InputStream exec = saveImageCmd.exec();
|
||||
IoUtil.copy(exec, fos);
|
||||
log.info("镜像已成功保存到: " + outputPath);
|
||||
return Boolean.TRUE;
|
||||
} catch (IOException e) {
|
||||
log.error("保存镜像时发生 IO 错误: " + e.getMessage());
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean pushImage(@NotNull String clientId, String imageId) {
|
||||
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
|
||||
try {
|
||||
dockerClient.pushImageCmd(imageId).exec(null);
|
||||
} catch (Exception e) {
|
||||
log.error("推送镜像失败: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cd.casic.module.execute.docker.service.impl;
|
||||
|
||||
import cd.casic.module.execute.docker.dao.OperateRecordDao;
|
||||
import cd.casic.module.execute.docker.dataobject.model.OperateRecord;
|
||||
import cd.casic.module.execute.docker.service.IOperateRecordService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 16:47
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OperateRecordService implements IOperateRecordService {
|
||||
|
||||
private final OperateRecordDao operateRecordDao;
|
||||
|
||||
@Override
|
||||
public void add(OperateRecord record) {
|
||||
// OperateRecordDo operateRecordDo = OperateRecordConvert.INSTANCE.convert(record);
|
||||
// int insert = operateRecordDao.insert(operateRecordDo);
|
||||
// if (insert != 1) {
|
||||
// log.error("新增操作日志失败");
|
||||
// }
|
||||
}
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
package cd.casic.module.execute;
|
||||
|
||||
import cd.casic.module.execute.docker.callback.LoggingCallback;
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.async.ResultCallback;
|
||||
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
|
||||
import com.github.dockerjava.api.command.InspectContainerResponse;
|
||||
import com.github.dockerjava.api.command.TopContainerResponse;
|
||||
import com.github.dockerjava.api.exception.NotFoundException;
|
||||
import com.github.dockerjava.api.model.Container;
|
||||
import com.github.dockerjava.api.model.Frame;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.Thread.sleep;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 20:11
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class ContainerServiceTest {
|
||||
|
||||
private final Map<String, DockerClient> clientGroup = new ConcurrentHashMap<>();
|
||||
|
||||
private ApacheDockerHttpClient createHttpClient(DockerEndpoint endpoint) {
|
||||
try {
|
||||
URI dockerHost;
|
||||
if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.LOCAL) {
|
||||
// 使用本地挂载
|
||||
dockerHost = new URI("unix:///var/run/docker.sock");
|
||||
} else if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.REMOTE) {
|
||||
// 远程挂载
|
||||
dockerHost = new URI(format("tcp://%s:%s", endpoint.getHost(), endpoint.getPort()));
|
||||
} else {
|
||||
log.error("Unsupported Docker endpoint type: {}", endpoint.getType());
|
||||
return null;
|
||||
}
|
||||
return new ApacheDockerHttpClient.Builder()
|
||||
.dockerHost(dockerHost)
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI for Docker endpoint {}: {}", endpoint.getId(), e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
DockerEndpoint endpoint = new DockerEndpoint();
|
||||
endpoint.setId("158");
|
||||
endpoint.setType(DockerEndpoint.DockerEndpointTypeEnum.REMOTE);
|
||||
endpoint.setHost("175.6.27.158");
|
||||
endpoint.setPort(22375);
|
||||
endpoint.setName("test");
|
||||
ApacheDockerHttpClient httpClient = createHttpClient(endpoint);
|
||||
DockerClient dockerClient = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
|
||||
clientGroup.put(endpoint.getId(), dockerClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void list() {
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
List<Container> exec =
|
||||
dockerClient.listContainersCmd().withShowAll(true).exec();
|
||||
System.out.println(exec.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start() {
|
||||
String containerId = "d7d747696f43";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.startContainerCmd(containerId).exec();
|
||||
log.info("启动容器,containerId={}", containerId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stop() {
|
||||
String containerId = "d7d747696f43";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.stopContainerCmd(containerId).exec();
|
||||
log.info("停止容器,containerId={}", containerId);
|
||||
}
|
||||
|
||||
/*没有成功,不知道为啥,暂停不研究了*/
|
||||
@Test
|
||||
public void pause() {
|
||||
String containerId = "c1ffcaf2ff8d";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.pauseContainerCmd(containerId).exec();
|
||||
log.info("停止容器,containerId={}", containerId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unpause() {
|
||||
String containerId = "c1ffcaf2ff8d";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
try {
|
||||
dockerClient.unpauseContainerCmd(containerId).exec();
|
||||
log.info("重启容器,containerId={}", containerId);
|
||||
} catch (NotFoundException e) {
|
||||
log.info("重启容器失败,containerId={},异常", containerId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rename() {
|
||||
String containerId = "d7d747696f43";
|
||||
String newName = "nginx";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.renameContainerCmd(containerId).withName(newName).exec();
|
||||
log.info("重命名容器:[{}]为[{}]", containerId, newName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void top() {
|
||||
String containerId = "d7d747696f43";
|
||||
String newName = "nginx";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
TopContainerResponse aux = dockerClient.topContainerCmd(containerId).withPsArgs("aux").exec();
|
||||
log.info("", aux.getTitles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inspect() {
|
||||
String containerId = "d7d747696f43";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
final InspectContainerResponse response =
|
||||
dockerClient.inspectContainerCmd(containerId).withSize(Boolean.TRUE).exec();
|
||||
System.out.println(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void remove() {
|
||||
String containerId = "d7d747696f43";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.removeContainerCmd(containerId)
|
||||
/*删除默认强制删除,并且挂载内容一并删除*/
|
||||
.withForce(true)
|
||||
.withRemoveVolumes(true).exec();
|
||||
log.info("移除容器,containerId={}", containerId);
|
||||
}
|
||||
|
||||
/*这个测试,用处不大*/
|
||||
@Test
|
||||
public void setLog() throws InterruptedException {
|
||||
String containerId = "d7d747696f43";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
/*创建命令*/
|
||||
String execId = dockerClient.execCreateCmd(containerId)
|
||||
.withCmd("ls")
|
||||
.withAttachStdin(true)
|
||||
.withAttachStdout(true)
|
||||
.withAttachStderr(true)
|
||||
.withTty(true)
|
||||
.exec().getId();
|
||||
// 执行命令并记录日志
|
||||
ResultCallback<Frame> callback = new LoggingCallback(containerId, execId);
|
||||
/*这个是异步的方法*/
|
||||
dockerClient.execStartCmd(execId)
|
||||
.withTty(true)
|
||||
.exec(callback);
|
||||
sleep(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void execCmd() throws InterruptedException {
|
||||
String containerId = "c1ffcaf2ff8d22ae9f1d9a91d0714d086ec2812809aec1558c9512b04168c125";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId)
|
||||
.withAttachStdout(true)
|
||||
.withAttachStderr(true)
|
||||
.withCmd("ls", "-l")
|
||||
.exec();
|
||||
dockerClient
|
||||
.execStartCmd(execCreateCmdResponse.getId())
|
||||
.exec(new CustomExecCallback())
|
||||
.awaitCompletion();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义执行命令回调类,用于处理命令执行过程中的输出和错误信息。
|
||||
*/
|
||||
private static class CustomExecCallback extends ResultCallback.Adapter<Frame> {
|
||||
|
||||
@Override
|
||||
public void onNext(Frame frame) {
|
||||
String output = new String(frame.getPayload(), StandardCharsets.UTF_8);
|
||||
switch (frame.getStreamType()) {
|
||||
case STDOUT:
|
||||
System.out.print(output);
|
||||
// log.info("标准输出: {}", output.trim());
|
||||
break;
|
||||
case STDERR:
|
||||
System.err.print(output);
|
||||
log.error("错误输出: {}", output.trim());
|
||||
break;
|
||||
default:
|
||||
log.warn("未知流类型: {}", frame.getStreamType());
|
||||
}
|
||||
super.onNext(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
log.error("执行命令时出错: {}", throwable.getMessage(), throwable);
|
||||
super.onError(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
log.info("命令执行完毕");
|
||||
super.onComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
log.debug("回调已关闭");
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package cd.casic.module.execute;
|
||||
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 20:11
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class DockerPingService {
|
||||
private final Map<String, DockerClient> clientGroup = new ConcurrentHashMap<>();
|
||||
|
||||
private ApacheDockerHttpClient createHttpClient(DockerEndpoint endpoint) {
|
||||
try {
|
||||
URI dockerHost;
|
||||
if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.LOCAL) {
|
||||
// 使用本地挂载
|
||||
dockerHost = new URI("unix:///var/run/docker.sock");
|
||||
} else if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.REMOTE) {
|
||||
// 远程挂载
|
||||
dockerHost = new URI(format("tcp://%s:%s", endpoint.getHost(), endpoint.getPort()));
|
||||
} else {
|
||||
log.error("Unsupported Docker endpoint type: {}", endpoint.getType());
|
||||
return null;
|
||||
}
|
||||
return new ApacheDockerHttpClient.Builder()
|
||||
.dockerHost(dockerHost)
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI for Docker endpoint {}: {}", endpoint.getId(), e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
DockerEndpoint endpoint = new DockerEndpoint();
|
||||
endpoint.setId("158");
|
||||
endpoint.setType(DockerEndpoint.DockerEndpointTypeEnum.REMOTE);
|
||||
endpoint.setHost("175.6.27.158");
|
||||
endpoint.setPort(22375);
|
||||
endpoint.setName("test");
|
||||
ApacheDockerHttpClient httpClient = createHttpClient(endpoint);
|
||||
DockerClient dockerClient = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
|
||||
clientGroup.put(endpoint.getId(), dockerClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ping(){
|
||||
String clientId = "158";
|
||||
DockerClient dockerClient = Optional.of(StringUtils.hasText(clientId) ? clientId : "DEFAULT")
|
||||
.map(id -> id.toUpperCase(Locale.ROOT))
|
||||
.map(t->clientGroup.get("158"))
|
||||
.orElseThrow(() -> new RuntimeException("客户端不存在"));
|
||||
dockerClient.pingCmd().exec();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package cd.casic.module.execute;
|
||||
|
||||
import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.InspectImageResponse;
|
||||
import com.github.dockerjava.api.model.Image;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 20:11
|
||||
* @version: 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class ImageServiceTest {
|
||||
private final Map<String, DockerClient> clientGroup = new ConcurrentHashMap<>();
|
||||
|
||||
private ApacheDockerHttpClient createHttpClient(DockerEndpoint endpoint) {
|
||||
try {
|
||||
URI dockerHost;
|
||||
if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.LOCAL) {
|
||||
// 使用本地挂载
|
||||
dockerHost = new URI("unix:///var/run/docker.sock");
|
||||
} else if (endpoint.getType() == DockerEndpoint.DockerEndpointTypeEnum.REMOTE) {
|
||||
// 远程挂载
|
||||
dockerHost = new URI(format("tcp://%s:%s", endpoint.getHost(), endpoint.getPort()));
|
||||
} else {
|
||||
log.error("Unsupported Docker endpoint type: {}", endpoint.getType());
|
||||
return null;
|
||||
}
|
||||
return new ApacheDockerHttpClient.Builder()
|
||||
.dockerHost(dockerHost)
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("Failed to create URI for Docker endpoint {}: {}", endpoint.getId(), e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
DockerEndpoint endpoint = new DockerEndpoint();
|
||||
endpoint.setId("158");
|
||||
endpoint.setType(DockerEndpoint.DockerEndpointTypeEnum.REMOTE);
|
||||
endpoint.setHost("175.6.27.158");
|
||||
endpoint.setPort(22375);
|
||||
endpoint.setName("test");
|
||||
ApacheDockerHttpClient httpClient = createHttpClient(endpoint);
|
||||
DockerClient dockerClient = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
|
||||
clientGroup.put(endpoint.getId(), dockerClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listTest() {
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
List<Image> exec = dockerClient.listImagesCmd().exec();
|
||||
System.out.println(exec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inspect() {
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
InspectImageResponse exec = dockerClient
|
||||
.inspectImageCmd("5a9e3ee3b8c1be74f5f89b092aea791d3ca058054ec0f3522b79d9985eff3087").exec();
|
||||
System.out.println(exec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tag() {
|
||||
/* 测试的hallo-world */
|
||||
String imagesId = "74cc54e27dc4";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
InspectImageResponse inspect = dockerClient
|
||||
.inspectImageCmd(imagesId).exec();
|
||||
if (inspect == null) {
|
||||
throw new RuntimeException("操作失败,镜像不存在");
|
||||
}
|
||||
dockerClient.tagImageCmd(imagesId, inspect.getRepoTags().get(0), "hallo-newworld1").exec();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void remove() {
|
||||
String imageId = "be69f2940aaf";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
dockerClient.removeImageCmd(imageId).withForce(true).exec();
|
||||
}
|
||||
|
||||
/*todo local 模式生效*/
|
||||
@Test
|
||||
public void importByTar() {
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
File file = new File("/home/ubuntu/nginx.tar");
|
||||
Void exec = dockerClient.loadImageCmd(FileUtil.getInputStream(file)).exec();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exist() {
|
||||
String imageId = "be69f2940aaf";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
System.out.println(dockerClient.inspectImageCmd(imageId).exec() != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pushImage() {
|
||||
String imageId = "be69f2940aaf";
|
||||
DockerClient dockerClient = clientGroup.get("158");
|
||||
try {
|
||||
dockerClient.pushImageCmd(imageId).exec(null);
|
||||
log.info("推送镜像成功: ");
|
||||
} catch (Exception e) {
|
||||
log.error("推送镜像失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cd.casic.module.execute;
|
||||
|
||||
/**
|
||||
* @description: TODO
|
||||
* @author: mianbin
|
||||
* @date: 2025/5/26 20:11
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class MonitorService {
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user