diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/callback/MonitorCallback.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/callback/MonitorCallback.java new file mode 100644 index 00000000..3a26efcb --- /dev/null +++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/callback/MonitorCallback.java @@ -0,0 +1,49 @@ +package cd.casic.module.execute.docker.callback; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Statistics; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +/** + * @description: 镜像的状态监控 + * @author: mianbin + * @date: 2025/5/28 10:45 + * @version: 1.0 + */ +@Data +@Slf4j +public class MonitorCallback extends ResultCallback.Adapter { + + private Statistics statistics; + private CompletableFuture future = new CompletableFuture<>(); + + @Override + public void onNext(Statistics statistics) { + future.complete(statistics); + super.onNext(statistics); + log.info("状态使用情况:{}", statistics); + } + + @Override + public void onError(Throwable throwable) { + super.onError(throwable); + log.error("docker 拉取异常,{}", throwable.getMessage()); + future.completeExceptionally(throwable); + } + + @Override + public void onComplete() { + super.onComplete(); + log.info("完成:{}", 1); + } + + @Override + public void close() throws IOException { + super.close(); + log.info("关闭:{}", 1); + } +} diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/RunNewContainer.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/RunNewContainer.java index 80c331b8..9c9ffcfb 100644 --- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/RunNewContainer.java +++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/RunNewContainer.java @@ -39,7 +39,7 @@ public class RunNewContainer { /** * DNS */ - private String dns; + private List dns; /** * 容器别名 @@ -51,6 +51,13 @@ public class RunNewContainer { */ private String hostname; + /** + * 网络名 + * + * @return + */ + private String networkMode; + public List findEnvList() { // 若 envGroup 为空,返回空列表;否则将 envGroup 转换为包含键值对字符串的列表 diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IMonitorService.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IMonitorService.java index 42b7b1f1..6e383dba 100644 --- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IMonitorService.java +++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IMonitorService.java @@ -1,5 +1,9 @@ package cd.casic.module.execute.docker.service; +import com.github.dockerjava.api.model.Statistics; + +import java.util.concurrent.BlockingQueue; + /** * @description: TODO * @author: mianbin @@ -8,4 +12,7 @@ package cd.casic.module.execute.docker.service; */ public interface IMonitorService { + Statistics monitorDocker(String clientId, String containerId); + + BlockingQueue monitorsDocker(String clientId, String containerId); } diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/MonitorService.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/MonitorService.java new file mode 100644 index 00000000..88e7e6be --- /dev/null +++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/MonitorService.java @@ -0,0 +1,100 @@ +package cd.casic.module.execute.docker.service.impl; + +import cd.casic.module.execute.docker.DockerClientFactory; +import cd.casic.module.execute.docker.service.IMonitorService; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Statistics; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.concurrent.*; + +/** + * @description: + * @author: mianbin + * @date: 2025/5/28 11:07 + * @version: 1.0 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class MonitorService implements IMonitorService { + + private final DockerClientFactory dockerClientFactory; + + /* + * 镜像里面的监控获取,没问题,但是,如果你是获取持续的,比如一直获取,那么这个就不行,这个是一次的 + * */ + @Override + public Statistics monitorDocker(String clientId, String containerId) { + CompletableFuture future = new CompletableFuture<>(); + DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId); + dockerClient.statsCmd(containerId).exec(new ResultCallback.Adapter() { + @SneakyThrows(RuntimeException.class) + @Override + public void onNext(Statistics statistics) { + future.complete(statistics); +// throw new RuntimeException("镜像{" + containerId + "},采集状态失败,停止运行"); + } + + @Override + public void onError(Throwable throwable) { + if (throwable instanceof RuntimeException) { + return; + } + log.error("docker 拉取状态异常,{}", throwable.getMessage()); + future.completeExceptionally(throwable); + } + }); + try { + // 最多等待 3 秒 + Statistics statistics = future.get(3, TimeUnit.SECONDS); + return statistics; + } catch (TimeoutException e) { + log.warn("获取 Docker 统计信息超时"); + return new Statistics(); + } catch (InterruptedException | ExecutionException e) { + log.error("获取 Docker 统计信息出错", e); + return new Statistics(); + } + } + + @Override + public BlockingQueue monitorsDocker(String clientId, String containerId) { + // 创建一个阻塞队列用于存储持续获取的统计信息 + BlockingQueue statsQueue = new LinkedBlockingQueue<>(); + DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId); + dockerClient.statsCmd(containerId).exec(new ResultCallback.Adapter() { + @Override + public void onNext(Statistics statistics) { + try { + // 将获取到的统计信息添加到队列中 + statsQueue.put(statistics); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("向队列添加统计信息时被中断", e); + } + } + + @Override + public void onError(Throwable throwable) { + log.error("docker 拉取状态异常,{}", throwable.getMessage()); + } + + @Override + public void onComplete() { + log.info("Docker 状态监控完成"); + try { + super.close(); + } catch (IOException e) { + // igonre it + } + } + }); + return statsQueue; + } +} diff --git a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/ContainerServiceTest.java b/modules/module-ci-execute/src/test/java/cd.casic.module.execute/ContainerServiceTest.java index fc89e9ad..a3f2dc93 100644 --- a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/ContainerServiceTest.java +++ b/modules/module-ci-execute/src/test/java/cd.casic.module.execute/ContainerServiceTest.java @@ -2,14 +2,15 @@ package cd.casic.module.execute; import cd.casic.module.execute.docker.callback.CommandExecCallback; import cd.casic.module.execute.docker.dataobject.model.DockerEndpoint; +import cd.casic.module.execute.docker.dataobject.model.RunNewContainer; 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.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.api.model.*; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import lombok.extern.slf4j.Slf4j; @@ -18,6 +19,7 @@ import org.junit.jupiter.api.Test; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -79,12 +81,36 @@ public class ContainerServiceTest { System.out.println(exec.size()); } + /** + * 能启动,但是参数都没生效的样子 + * + */ @Test public void start() { - String containerId = "d7d747696f43"; + String imagesId = "be69f2940aaf"; DockerClient dockerClient = clientGroup.get("158"); - dockerClient.startContainerCmd(containerId).exec(); - log.info("启动容器,containerId={}", containerId); + // 创建 RunNewContainer 对象并设置属性 + RunNewContainer runNewContainer = new RunNewContainer(); + runNewContainer.setImageId(imagesId); + runNewContainer.setAlias("nginx"); + runNewContainer.setDns(Arrays.asList("8.8.8.8", "8.8.4.4")); + runNewContainer.setContainerName("nginx_test_api"); + runNewContainer.setHostname("nginx.testapi.host.name"); + Map key1 = Map.of("KEY1", "VALUE1", "KEY2", "VALUE2"); + runNewContainer.setEnvGroup(key1); + runNewContainer.setNetworkMode("nginx_test_net_work"); + + HostConfig hostConfig = HostConfig.newHostConfig(); + hostConfig.withBinds(Bind.parse("/host:/container:ro")) + .withPortBindings(PortBinding.parse("12:44")) + .withDns(runNewContainer.getDns()).withNetworkMode(runNewContainer.getNetworkMode()); + final CreateContainerResponse response = dockerClient + .createContainerCmd(runNewContainer.getImageId()) + .withAliases(runNewContainer.getAlias()) + .withHostConfig(hostConfig) + .withEnv(runNewContainer.findEnvList()) + .withName(runNewContainer.getContainerName()) + .withHostName(runNewContainer.getHostname()).exec(); } @Test @@ -190,4 +216,5 @@ public class ContainerServiceTest { .exec(new CommandExecCallback(containerId)) .awaitCompletion(); } + } diff --git a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingService.java b/modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingServiceTest.java similarity index 98% rename from modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingService.java rename to modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingServiceTest.java index 2b30898b..ace0c168 100644 --- a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingService.java +++ b/modules/module-ci-execute/src/test/java/cd.casic.module.execute/DockerPingServiceTest.java @@ -25,7 +25,7 @@ import static java.lang.String.format; * @version: 1.0 */ @Slf4j -public class DockerPingService { +public class DockerPingServiceTest { private final Map clientGroup = new ConcurrentHashMap<>(); private ApacheDockerHttpClient createHttpClient(DockerEndpoint endpoint) { diff --git a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/MonitorService.java b/modules/module-ci-execute/src/test/java/cd.casic.module.execute/MonitorService.java deleted file mode 100644 index a90a264b..00000000 --- a/modules/module-ci-execute/src/test/java/cd.casic.module.execute/MonitorService.java +++ /dev/null @@ -1,11 +0,0 @@ -package cd.casic.module.execute; - -/** - * @description: TODO - * @author: mianbin - * @date: 2025/5/26 20:11 - * @version: 1.0 - */ -public class MonitorService { - -}