This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 50ffbdb015e971bd772bc866ef929bc12d46b13e Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Fri Aug 9 15:24:46 2024 -0400 Fix #1354 --- .../camel/karavan/docker/DockerForKaravan.java | 10 +- .../apache/camel/karavan/docker/DockerService.java | 253 ++++++++++++++------- .../karavan/scheduler/DockerStatusScheduler.java | 10 +- 3 files changed, 181 insertions(+), 92 deletions(-) diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java index f3fea917..feb08009 100644 --- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java +++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java @@ -30,6 +30,7 @@ import org.jboss.logging.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import static org.apache.camel.karavan.KaravanConstants.*; import static org.apache.camel.karavan.service.CodeService.BUILD_SCRIPT_FILENAME; @@ -65,8 +66,15 @@ public class DockerForKaravan { env.add(ENV_VAR_JBANG_OPTIONS + "=" + jBangOptions); } + var imageName = projectDevmodeImage != null ? projectDevmodeImage : devmodeImage; + + if (dockerService.getImages().stream().noneMatch(i -> Objects.equals(i.getTag(), imageName))) { + LOGGER.info("Pulling DevMode image from DockerHub: " + imageName); + dockerService.pullImageFromDockerHub(imageName, true); + } + return dockerService.createContainer(projectId, - (projectDevmodeImage != null ? projectDevmodeImage : devmodeImage), + (imageName), env, compose.getPortsMap(), healthCheck, Map.of(LABEL_TYPE, PodContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId, diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java index 43921da5..e5710187 100644 --- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java +++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java @@ -17,14 +17,12 @@ package org.apache.camel.karavan.docker; import com.github.dockerjava.api.DockerClient; -import com.github.dockerjava.api.command.CreateContainerCmd; -import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.command.ListImagesCmd; -import com.github.dockerjava.api.command.PullImageCmd; +import com.github.dockerjava.api.command.*; import com.github.dockerjava.api.model.*; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.core.command.ExecStartResultCallback; import com.github.dockerjava.transport.DockerHttpClient; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; import io.quarkus.runtime.ShutdownEvent; @@ -85,13 +83,17 @@ public class DockerService { private DockerClient dockerClient; + private DockerClient dockerClientConnectedToRegistry; + void onStart(@Observes StartupEvent ev) { if (!ConfigService.inKubernetes()) { - getDockerClient().eventsCmd().exec(dockerEventHandler); + try (EventsCmd cmd = getDockerClient().eventsCmd()) { + cmd.exec(dockerEventHandler); + } } } - void onStop(@Observes ShutdownEvent ev) throws IOException { + void onStop(@Observes ShutdownEvent ev) throws IOException { if (!ConfigService.inKubernetes()) { dockerEventHandler.close(); } @@ -99,7 +101,9 @@ public class DockerService { public boolean checkDocker() { try { - getDockerClient().pingCmd().exec(); + try (PingCmd cmd = getDockerClient().pingCmd()) { + cmd.exec(); + } LOGGER.info("Docker is available"); return true; } catch (Exception e) { @@ -108,13 +112,17 @@ public class DockerService { } } - public Info getInfo(){ - return getDockerClient().infoCmd().exec(); + public Info getInfo() { + try (InfoCmd cmd = getDockerClient().infoCmd()) { + return cmd.exec(); + } } public Container getContainer(String id) { - List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id)).exec(); - return containers.isEmpty() ? null : containers.get(0); + try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(List.of(id))) { + List<Container> containers = cmd.exec(); + return containers.isEmpty() ? null : containers.get(0); + } } public Container getContainerByName(String name) { @@ -123,7 +131,9 @@ public class DockerService { } public List<Container> getAllContainers() { - return getDockerClient().listContainersCmd().withShowAll(true).exec(); + try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true)) { + return cmd.exec(); + } } public Container createContainerFromCompose(DockerComposeService compose, Map<String, String> labels, Boolean pullAlways, String... command) throws InterruptedException { @@ -142,7 +152,7 @@ public class DockerService { restartPolicy = RestartPolicy.alwaysRestart(); } - return createContainer(compose.getContainer_name(), compose.getImage(), + return createContainer(compose.getContainer_name(), compose.getImage(), env, compose.getPortsMap(), healthCheck, labels, compose.getVolumesMap(), networkName, restartPolicy, pullAlways, compose.getCpus(), compose.getCpu_percent(), compose.getMem_limit(), compose.getMem_reservation(), command); @@ -153,8 +163,9 @@ public class DockerService { } public List<Container> findContainer(String containerName) { - return getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(containerName)).exec() - .stream().filter(c -> Objects.equals(c.getNames()[0].replaceFirst("/", ""), containerName)).toList(); + try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(containerName))) { + return cmd.exec().stream().filter(c -> Objects.equals(c.getNames()[0].replaceFirst("/", ""), containerName)).toList(); + } } public Container createContainer(String name, String image, List<String> env, Map<Integer, Integer> ports, @@ -166,38 +177,39 @@ public class DockerService { if (containers.isEmpty()) { pullImage(image, pullAlways); - CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image) - .withName(name).withLabels(labels).withEnv(env).withHostName(name).withHealthcheck(healthCheck); - - Ports portBindings = DockerUtils.getPortBindings(ports); - - List<Mount> mounts = new ArrayList<>(); - if (volumes != null && !volumes.isEmpty()) { - volumes.forEach((hostPath, containerPath) -> { - mounts.add(new Mount().withType(MountType.BIND).withSource(hostPath).withTarget(containerPath)); - }); + try (CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image).withName(name).withLabels(labels).withEnv(env).withHostName(name).withHealthcheck(healthCheck)) { + Ports portBindings = DockerUtils.getPortBindings(ports); + + List<Mount> mounts = new ArrayList<>(); + if (volumes != null && !volumes.isEmpty()) { + volumes.forEach((hostPath, containerPath) -> { + mounts.add(new Mount().withType(MountType.BIND).withSource(hostPath).withTarget(containerPath)); + }); + } + if (command.length > 0) { + createContainerCmd.withCmd(command); + } + if (Objects.equals(labels.get(LABEL_PROJECT_ID), PodContainerStatus.ContainerType.build.name())) { + mounts.add(new Mount().withType(MountType.BIND).withSource("/var/run/docker.sock").withTarget("/var/run/docker.sock")); + } + + createContainerCmd.withHostConfig(new HostConfig() + .withRestartPolicy(restartPolicy) + .withPortBindings(portBindings) + .withMounts(mounts) + .withMemory(DockerUtils.parseMemory(mem_limit)) + .withMemoryReservation(DockerUtils.parseMemory(mem_reservation)) + .withCpuPercent(NumberUtils.toLong(cpu_percent)) + .withNanoCPUs(NumberUtils.toLong(cpus)) + .withNetworkMode(network != null ? network : networkName)); + + CreateContainerResponse response = createContainerCmd.exec(); + LOGGER.info("Container created: " + response.getId()); + + try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true).withIdFilter(Collections.singleton(response.getId()))) { + return cmd.exec().get(0); + } } - if (command.length > 0) { - createContainerCmd.withCmd(command); - } - if (Objects.equals(labels.get(LABEL_PROJECT_ID), PodContainerStatus.ContainerType.build.name())) { - mounts.add(new Mount().withType(MountType.BIND).withSource("/var/run/docker.sock").withTarget("/var/run/docker.sock")); - } - - createContainerCmd.withHostConfig(new HostConfig() - .withRestartPolicy(restartPolicy) - .withPortBindings(portBindings) - .withMounts(mounts) - .withMemory(DockerUtils.parseMemory(mem_limit)) - .withMemoryReservation(DockerUtils.parseMemory(mem_reservation)) - .withCpuPercent(NumberUtils.toLong(cpu_percent)) - .withNanoCPUs(NumberUtils.toLong(cpus)) - .withNetworkMode(network != null ? network : networkName)); - - CreateContainerResponse response = createContainerCmd.exec(); - LOGGER.info("Container created: " + response.getId()); - return getDockerClient().listContainersCmd().withShowAll(true) - .withIdFilter(Collections.singleton(response.getId())).exec().get(0); } else { LOGGER.info("Container already exists: " + containers.get(0).getId()); return containers.get(0); @@ -213,9 +225,13 @@ public class DockerService { public void runContainer(Container container) { if (container.getState().equals("paused")) { - getDockerClient().unpauseContainerCmd(container.getId()).exec(); + try (UnpauseContainerCmd cmd = getDockerClient().unpauseContainerCmd(container.getId())) { + cmd.exec(); + } } else if (!container.getState().equals("running")) { - getDockerClient().startContainerCmd(container.getId()).exec(); + try (StartContainerCmd cmd = getDockerClient().startContainerCmd(container.getId())) { + cmd.exec(); + } } } @@ -256,14 +272,15 @@ public class DockerService { try { Container container = getContainerByName(containerName); if (container != null) { - getDockerClient().logContainerCmd(container.getId()) + try (LogContainerCmd cmd = getDockerClient().logContainerCmd(container.getId()) .withStdOut(true) .withStdErr(true) .withTimestamps(false) .withFollowStream(true) - .withTail(100) - .exec(callback); - callback.awaitCompletion(); + .withTail(100)) { + cmd.exec(callback); + callback.awaitCompletion(); + } } } catch (Exception e) { LOGGER.error(e.getMessage()); @@ -275,7 +292,9 @@ public class DockerService { if (containers.size() == 1) { Container container = containers.get(0); if (container.getState().equals("running")) { - getDockerClient().pauseContainerCmd(container.getId()).exec(); + try (PauseContainerCmd cmd = getDockerClient().pauseContainerCmd(container.getId())) { + cmd.exec(); + } } } } @@ -285,7 +304,9 @@ public class DockerService { if (containers.size() == 1) { Container container = containers.get(0); if (container.getState().equals("running") || container.getState().equals("paused")) { - getDockerClient().stopContainerCmd(container.getId()).exec(); + try (StopContainerCmd cmd = getDockerClient().stopContainerCmd(container.getId())) { + cmd.exec(); + } } } } @@ -294,21 +315,62 @@ public class DockerService { List<Container> containers = findContainer(name); if (containers.size() == 1) { Container container = containers.get(0); - getDockerClient().removeContainerCmd(container.getId()).withForce(true).exec(); + try (RemoveContainerCmd cmd = getDockerClient().removeContainerCmd(container.getId()).withForce(true)) { + cmd.exec(); + } + } + } + + public void execCommandInContainer(String containerName, String cmd) throws InterruptedException { + List<Container> containers = findContainer(containerName); + if (containers.size() == 1) { + Container container = containers.get(0); + if (container.getState().equals("running")) { + try (ExecCreateCmd execCreateCmd = getDockerClient().execCreateCmd(container.getId()).withAttachStdout(true).withAttachStderr(true).withCmd(cmd.split("\\s+"))) { + var execCreateCmdResponse = execCreateCmd.exec(); + try (ExecStartCmd execStartCmd = getDockerClient().execStartCmd(execCreateCmdResponse.getId())) { + execStartCmd.exec(new ExecStartResultCallback(System.out, System.err)).awaitCompletion(); + } + + + } + } } } public void pullImage(String image, boolean pullAlways) throws InterruptedException { - List<Image> images = getDockerClient().listImagesCmd().withShowAll(true).exec(); - List<String> tags = images.stream() - .map(i -> Arrays.stream(i.getRepoTags()).collect(Collectors.toList())) - .flatMap(Collection::stream) - .toList(); - - if (pullAlways || images.stream().noneMatch(i -> tags.contains(image))) { - var callback = new DockerPullCallback(LOGGER::info); - getDockerClient().pullImageCmd(image).exec(callback); - callback.awaitCompletion(); + try (ListImagesCmd cmd = getDockerClient().listImagesCmd().withShowAll(true)) { + List<Image> images = cmd.exec(); + List<String> tags = images.stream() + .map(i -> Arrays.stream(i.getRepoTags()).collect(Collectors.toList())) + .flatMap(Collection::stream) + .toList(); + + if (pullAlways || images.stream().noneMatch(i -> tags.contains(image))) { + var callback = new DockerPullCallback(LOGGER::info); + try (PullImageCmd pullImageCmd = getDockerClient().pullImageCmd(image)) { + pullImageCmd.exec(callback); + callback.awaitCompletion(); + } + } + } + } + + public void pullImageFromDockerHub(String image, boolean pullAlways) throws InterruptedException { + try (ListImagesCmd cmd = getDockerClientNotConnectedToRegistry().listImagesCmd().withShowAll(true)) { + List<Image> images = cmd.exec(); + List<String> tags = images.stream() + .map(i -> Arrays.stream(i.getRepoTags()).collect(Collectors.toList())) + .flatMap(Collection::stream) + .toList(); + + if (pullAlways || images.stream().noneMatch(i -> tags.contains(image))) { + var callback = new DockerPullCallback(LOGGER::info); + try (PullImageCmd pullImageCmd = getDockerClientNotConnectedToRegistry().pullImageCmd(image)) { + pullImageCmd.exec(callback); + callback.awaitCompletion(); + } + } } } @@ -323,16 +385,18 @@ public class DockerService { } } - private DockerClientConfig getDockerClientConfig() { - LOGGER.info("Docker Client Configuring...."); - LOGGER.info("Docker Client Registry " + registry); - LOGGER.info("Docker Client Username " + (username.isPresent() ? "is not empty " : "is empty")); - LOGGER.info("Docker Client Password " + (password.isPresent() ? "is not empty " : "is empty")); - DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(); - if (!Objects.equals(registry, "registry:5000") && username.isPresent() && password.isPresent()) { - builder.withRegistryUrl(registry); - builder.withRegistryUsername(username.get()); - builder.withRegistryPassword(password.get()); + private DockerClientConfig getDockerClientConfig(boolean connectedToRegistry) { + LOGGER.info("Docker Client Configuring " + (connectedToRegistry ? "( connectedToRegistry)" : "")); + DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder(); + if (connectedToRegistry) { + LOGGER.info("Docker Client Registry " + registry); + LOGGER.info("Docker Client Username " + (username.isPresent() ? "is not empty " : "is empty")); + LOGGER.info("Docker Client Password " + (password.isPresent() ? "is not empty " : "is empty")); + if (!Objects.equals(registry, "registry:5000") && username.isPresent() && password.isPresent()) { + builder.withRegistryUrl(registry); + builder.withRegistryUsername(username.get()); + builder.withRegistryPassword(password.get()); + } } return builder.build(); } @@ -347,21 +411,32 @@ public class DockerService { public DockerClient getDockerClient() { if (dockerClient == null) { - DockerClientConfig config = getDockerClientConfig(); + DockerClientConfig config = getDockerClientConfig(true); DockerHttpClient httpClient = getDockerHttpClient(config); dockerClient = DockerClientImpl.getInstance(config, httpClient); } return dockerClient; } + public DockerClient getDockerClientNotConnectedToRegistry() { + if (dockerClientConnectedToRegistry == null) { + DockerClientConfig config = getDockerClientConfig(false); + DockerHttpClient httpClient = getDockerHttpClient(config); + dockerClientConnectedToRegistry = DockerClientImpl.getInstance(config, httpClient); + } + return dockerClientConnectedToRegistry; + } + public int getMaxPortMapped(int port) { - return getDockerClient().listContainersCmd().withShowAll(true).exec().stream() - .map(c -> List.of(c.ports)) - .flatMap(List::stream) - .filter(p -> Objects.equals(p.getPrivatePort(), port)) - .map(ContainerPort::getPublicPort).filter(Objects::nonNull) - .mapToInt(Integer::intValue) - .max().orElse(port); + try (ListContainersCmd cmd = getDockerClient().listContainersCmd().withShowAll(true)) { + return cmd.exec().stream() + .map(c -> List.of(c.ports)) + .flatMap(List::stream) + .filter(p -> Objects.equals(p.getPrivatePort(), port)) + .map(ContainerPort::getPublicPort).filter(Objects::nonNull) + .mapToInt(Integer::intValue) + .max().orElse(port); + } } public List<ContainerImage> getImages() { @@ -374,10 +449,14 @@ public class DockerService { } public void deleteImage(String imageName) { - Optional<Image> image = getDockerClient().listImagesCmd().withShowAll(true).exec().stream() - .filter(i -> Arrays.stream(i.getRepoTags()).anyMatch(s -> Objects.equals(s, imageName))).findFirst(); - if (image.isPresent()) { - getDockerClient().removeImageCmd(image.get().getId()).exec(); + try (ListImagesCmd listImagesCmd = getDockerClient().listImagesCmd().withShowAll(true)) { + Optional<Image> image = listImagesCmd.exec().stream() + .filter(i -> Arrays.asList(i.getRepoTags()).contains(imageName)).findFirst(); + if (image.isPresent()) { + try (RemoveImageCmd removeImageCmd = getDockerClient().removeImageCmd(image.get().getId())) { + removeImageCmd.exec(); + } + } } } } diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java index 7a435e8b..32c2857a 100644 --- a/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java +++ b/karavan-app/src/main/java/org/apache/camel/karavan/scheduler/DockerStatusScheduler.java @@ -47,10 +47,12 @@ public class DockerStatusScheduler { @Scheduled(every = "{karavan.container.statistics.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP) void collectContainersStatistics() { - List<PodContainerStatus> statusesInDocker = getContainersStatuses(); - statusesInDocker.forEach(containerStatus -> { - eventBus.publish(CMD_COLLECT_CONTAINER_STATISTIC, JsonObject.mapFrom(containerStatus)); - }); + if (!ConfigService.inKubernetes()) { + List<PodContainerStatus> statusesInDocker = getContainersStatuses(); + statusesInDocker.forEach(containerStatus -> { + eventBus.publish(CMD_COLLECT_CONTAINER_STATISTIC, JsonObject.mapFrom(containerStatus)); + }); + } } @Scheduled(every = "{karavan.container.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)