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
The following commit(s) were added to refs/heads/main by this push: new 3d36c52d change to limit container resoures for docker (#1149) 3d36c52d is described below commit 3d36c52db74d2607d9d9bf9c886cc887f41272f3 Author: Vidhya Sagar <36588343+vidhyasag...@users.noreply.github.com> AuthorDate: Tue Feb 27 23:17:13 2024 +0800 change to limit container resoures for docker (#1149) Co-authored-by: Vidhya Sagar <vidhyasa...@ascertain.com.my> --- .../camel/karavan/docker/DockerForKaravan.java | 14 ++++++-- .../apache/camel/karavan/docker/DockerService.java | 12 +++++-- .../camel/karavan/docker/DockerServiceUtils.java | 34 ++++++++++++++++-- .../camel/karavan/model/DockerComposeService.java | 41 ++++++++++++++++++++++ .../main/resources/snippets/docker-compose.yaml | 3 ++ 5 files changed, 96 insertions(+), 8 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 7c07cbc4..42c9d6f0 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 @@ -22,7 +22,9 @@ import com.github.dockerjava.api.model.RestartPolicy; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.camel.karavan.model.ContainerStatus; +import org.apache.camel.karavan.model.DockerComposeService; import org.apache.camel.karavan.model.Project; +import org.apache.camel.karavan.service.ProjectService; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; @@ -46,6 +48,9 @@ public class DockerForKaravan { @Inject DockerService dockerService; + @Inject + ProjectService projectService; + public void runProjectInDevMode(String projectId, String jBangOptions, Map<Integer, Integer> ports, Map<String, String> files) throws Exception { Map<String, String> volumes = getMavenVolumes(); @@ -64,13 +69,16 @@ public class DockerForKaravan { ? List.of(ENV_VAR_JBANG_OPTIONS + "=" + jBangOptions) : List.of(); + DockerComposeService composeService = projectService.getProjectDockerComposeService(projectId); + return dockerService.createContainer(projectId, devmodeImage, env, ports, healthCheck, Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId, LABEL_CAMEL_RUNTIME, CamelRuntime.CAMEL_MAIN.getValue() ), - volumes, null, RestartPolicy.noRestart(), false); + volumes, null, RestartPolicy.noRestart(), false, + composeService.getCpus(), composeService.getCpu_percent(), composeService.getMem_limit(), composeService.getMem_reservation()); } @@ -96,7 +104,9 @@ public class DockerForKaravan { LABEL_PROJECT_ID, project.getProjectId(), LABEL_TAG, tag ), - volumes, null,RestartPolicy.noRestart(), false, "/karavan/builder/build.sh"); + volumes, null,RestartPolicy.noRestart(), false, + null, null, null, null, + "/karavan/builder/build.sh"); } private Map<String,String> getMavenVolumes(){ 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 f1a41476..bfd49f1a 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 @@ -36,6 +36,7 @@ import org.apache.camel.karavan.model.ContainerStatus; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; @@ -205,8 +206,9 @@ public class DockerService extends DockerServiceUtils { restartPolicy = RestartPolicy.alwaysRestart(); } - return createContainer(compose.getContainer_name(), compose.getImage(), - env, compose.getPortsMap(), healthCheck, labels, volumes, networkName, restartPolicy, pullAlways, command); + return createContainer(compose.getContainer_name(), compose.getImage(), + env, compose.getPortsMap(), healthCheck, labels, volumes, networkName, restartPolicy, pullAlways, + compose.getCpus(), compose.getCpu_percent(), compose.getMem_limit(), compose.getMem_reservation(), command); } else { LOGGER.info("Compose Service already exists: " + containers.get(0).getId()); @@ -222,7 +224,7 @@ public class DockerService extends DockerServiceUtils { public Container createContainer(String name, String image, List<String> env, Map<Integer, Integer> ports, HealthCheck healthCheck, Map<String, String> labels, Map<String, String> volumes, String network, RestartPolicy restartPolicy, - boolean pullAlways, + boolean pullAlways, String cpus, String cpu_percent, String mem_limit, String mem_reservation, String... command) throws InterruptedException { List<Container> containers = findContainer(name); if (containers.isEmpty()) { @@ -249,6 +251,10 @@ public class DockerService extends DockerServiceUtils { .withRestartPolicy(restartPolicy) .withPortBindings(portBindings) .withMounts(mounts) + .withMemory(parseMemory(mem_limit)) + .withMemoryReservation(parseMemory(mem_reservation)) + .withCpuPercent(NumberUtils.toLong(cpu_percent)) + .withNanoCPUs(NumberUtils.toLong(cpus)) .withNetworkMode(network != null ? network : networkName)); CreateContainerResponse response = createContainerCmd.exec(); diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java index 10a030e9..67b0a6ae 100644 --- a/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java +++ b/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java @@ -43,6 +43,31 @@ public class DockerServiceUtils { protected static final DecimalFormat formatGiB = new DecimalFormat("0.00"); protected static final Map<String, Tuple2<Long, Long>> previousStats = new ConcurrentHashMap<>(); + private static final Map<String, Long> UNIT_MULTIPLIERS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);; + static { + UNIT_MULTIPLIERS.put("b", 1L); + UNIT_MULTIPLIERS.put("k", 1024L); + UNIT_MULTIPLIERS.put("m", 1024L * 1024); + UNIT_MULTIPLIERS.put("g", 1024L * 1024 * 1024); + // Add more units if needed + } + + public static Long parseMemory(String memory) { + + if (memory != null && !memory.isEmpty()) { + memory = memory.trim(); + String numericPart = memory.replaceAll("[^\\d.]", ""); + double numericValue = Double.parseDouble(numericPart); + String unitPart = memory.replaceAll("[\\d.]", "").toLowerCase(); + Long multiplier = UNIT_MULTIPLIERS.get(unitPart); + if (multiplier == null) { + throw new IllegalArgumentException("Invalid unit in memory: " + unitPart); + } + return (long) (numericValue * multiplier); + } + return null; + } + protected ContainerStatus getContainerStatus(Container container, String environment) { String name = container.getNames()[0].replace("/", ""); List<ContainerPort> ports = Arrays.stream(container.getPorts()) @@ -53,7 +78,8 @@ public class DockerServiceUtils { String created = Instant.ofEpochSecond(container.getCreated()).toString(); String projectId = container.getLabels().getOrDefault(LABEL_PROJECT_ID, name); String camelRuntime = container.getLabels().getOrDefault(LABEL_CAMEL_RUNTIME, ""); - return ContainerStatus.createWithId(projectId, name, environment, container.getId(), container.getImage(), ports, type, commands, container.getState(), created, camelRuntime); + return ContainerStatus.createWithId(projectId, name, environment, container.getId(), container.getImage(), + ports, type, commands, container.getState(), created, camelRuntime); } protected void updateStatistics(ContainerStatus containerStatus, Statistics stats) { @@ -171,8 +197,10 @@ public class DockerServiceUtils { protected String formatCpu(String containerName, Statistics stats) { try { double cpuUsage = 0; - long previousCpu = previousStats.containsKey(containerName) ? previousStats.get(containerName).getItem1() : -1; - long previousSystem = previousStats.containsKey(containerName) ? previousStats.get(containerName).getItem2() : -1; + long previousCpu = previousStats.containsKey(containerName) ? previousStats.get(containerName).getItem1() + : -1; + long previousSystem = previousStats.containsKey(containerName) ? previousStats.get(containerName).getItem2() + : -1; CpuStatsConfig cpuStats = stats.getCpuStats(); if (cpuStats != null) { diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java index 5936af4f..426ea7f9 100644 --- a/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java +++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/DockerComposeService.java @@ -28,6 +28,10 @@ public class DockerComposeService { private String container_name; private String image; private String restart; + private String cpus; + private String cpu_percent; + private String mem_limit; + private String mem_reservation; private List<String> ports; private List<String> expose; private List<String> depends_on; @@ -142,12 +146,48 @@ public class DockerComposeService { this.networks = networks; } + public String getCpu_percent() { + return cpu_percent; + } + + public void setCpu_percent(String cpu_percent) { + this.cpu_percent = cpu_percent; + } + + public String getCpus() { + return cpus; + } + + public void setCpus(String cpus) { + this.cpus = cpus; + } + + public String getMem_limit() { + return mem_limit; + } + + public void setMem_limit(String mem_limit) { + this.mem_limit = mem_limit; + } + + public String getMem_reservation() { + return mem_reservation; + } + + public void setMem_reservation(String mem_reservation) { + this.mem_reservation = mem_reservation; + } + @Override public String toString() { return "DockerComposeService {" + "container_name='" + container_name + '\'' + ", image='" + image + '\'' + ", restart='" + restart + '\'' + + ", cpus='" + cpus + '\'' + + ", cpu_percent='" + cpu_percent + '\'' + + ", mem_limit='" + mem_limit + '\'' + + ", mem_reservation='" + mem_reservation + '\'' + ", ports=" + ports + ", env_file=" + env_file + ", networks=" + networks + @@ -157,4 +197,5 @@ public class DockerComposeService { ", healthcheck=" + healthcheck + '}'; } + } diff --git a/karavan-app/src/main/resources/snippets/docker-compose.yaml b/karavan-app/src/main/resources/snippets/docker-compose.yaml index 36c668af..15563049 100644 --- a/karavan-app/src/main/resources/snippets/docker-compose.yaml +++ b/karavan-app/src/main/resources/snippets/docker-compose.yaml @@ -1,6 +1,9 @@ services: {projectId}: image: {projectImage} + cpu_percent: 10 + mem_limit: 1024M + mem_reservation: 512M restart: always ports: - "{projectPort}:8080"