diff --git a/borschevskaya_anna_lab_2/.gitignore b/borschevskaya_anna_lab_2/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/borschevskaya_anna_lab_2/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/README.md b/borschevskaya_anna_lab_2/README.md new file mode 100644 index 0000000..ebdda6b --- /dev/null +++ b/borschevskaya_anna_lab_2/README.md @@ -0,0 +1,43 @@ +# Отчет. Лабораторная работа 2 + +В рамках лабораторной работы №2 были написаны два сервиса, работающих с текстовыми файлами. +Для первого сервиса был выбран вариант задания №5: +``` +Ищет в каталоге /var/data файл с самым коротким названием и перекладывает его в /var/result/data.txt. +``` +А для второго - №2: +``` +Ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt. +``` +## Описание +Сначала сервис first перемещает данные из файла с самым коротким названием, находящегося в указанной примонтированной директории, в выходную папку. +Доступ к выходной папке имеет второй сервис, который выводит наименьшее число из помещенного первым сервисом файла +в третьей степени в выходной файл. +Выходной файл расположен в примонтированной директории и доступен на машине, где запускаются сервисы. + +В Dockerfile используется многоэтапная сборка с использованием нескольких базовых образов на каждом этапе. +Описание значения каждой строки есть в Dockerfile в сервисе first. + +В файле docker-compose.yml приведено описание новых строк, связанных с подключением примонтированных томов. +Стоит отметить, что для "общения" сервисов используется общий том common, который монтируется в контейнер по пути /var/result. Это позволяет сохранять результаты +работы первого сервиса для использования вторым сервисом. +## Как запустить +Для того, чтобы запустить сервисы, необходимо выполнить следующие действия: +1. Установить и запустить Docker Engine или Docker Desktop +2. Через консоль перейти в папку, в которой расположен файл docker-compose.yml +3. Выполнить команду: +``` +docker compose up --build +``` +В случае успешного запуска всех контейнеров в консоли будет выведено следующее сообщение: +``` + ✔ Network borschevskaya_anna_lab_2_default Created 0.1s + ✔ Container borschevskaya_anna_lab_2-first-1 Created 0.1s + ✔ Container borschevskaya_anna_lab_2-second-1 Created 0.1s +Attaching to borschevskaya_anna_lab_2-first-1, borschevskaya_anna_lab_2-second-1 +``` +Далее, в консоль каждого сервиса будут выведены сообщения о том, как прошла обработка файлов. +В случае отсутствия заданных значений переменных окружения INPUT_PATH и OUTPUT_PATH и +в иных исключительных ситуация будет выведена информация об этом. +## Видео-отчет +Работоспособность лабораторной работы можно оценить в следующем [видео](https://disk.yandex.ru/i/LFxdyRUFQDwXEQ). \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/docker-compose.yml b/borschevskaya_anna_lab_2/docker-compose.yml new file mode 100644 index 0000000..1bf8001 --- /dev/null +++ b/borschevskaya_anna_lab_2/docker-compose.yml @@ -0,0 +1,22 @@ +services: + first: + build: ./first # директория, в которой нужно искать Dockerfile для сборки первого сервиса + environment: + INPUT_PATH: /var/data/ # директория с входными данными для обработки файлов + OUTPUT_PATH: /var/result/ # директория с выходными данными обработки + volumes: + - ./volumes/input:/var/data # монтируется локальная папка с входными данными в папку внутри контейнера + - common:/var/result # монтируется общий для двух сервисов том, в который first сложит результаты обработки по варианту + second: + build: ./second # директория, в которой нужно искать Dockerfile для сборки второго сервиса + depends_on: # сервис second зависит от сервиса first и будет запущен после него + - first + environment: + INPUT_PATH: /var/result/ + OUTPUT_PATH: /var/data/ + volumes: + - ./volumes/output:/var/data + - common:/var/result # монтируется общий для двух сервисов том, из которого second получит результаты обработки first сервиса и выполнит свою логику + +volumes: + common: \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/first/Dockerfile b/borschevskaya_anna_lab_2/first/Dockerfile new file mode 100644 index 0000000..039f7e6 --- /dev/null +++ b/borschevskaya_anna_lab_2/first/Dockerfile @@ -0,0 +1,25 @@ +# Используем образ Maven для сборки +FROM maven:3.8-eclipse-temurin-21-alpine AS build + +# Устанавливаем рабочую директорию +WORKDIR /app + +# Копируем только pom.xml и загружаем зависимости +# Так зависимости закэшируются в Docker при изменении кода закэшированные слои с зависимостями будут подгружаться быстрее +COPY pom.xml . +RUN mvn dependency:go-offline + +# Копируем остальные исходные файлы +COPY src ./src + +# Собираем весь проект +RUN mvn clean package -DskipTests + +# Используем официальный образ JDK для запуска собранного jar-файла +FROM eclipse-temurin:21-jdk-alpine + +# Копируем jar-файл из предыдущего этапа +COPY --from=build /app/target/*.jar /app.jar + +# Указываем команду для запуска приложения +CMD ["java", "-jar", "app.jar"] diff --git a/borschevskaya_anna_lab_2/first/pom.xml b/borschevskaya_anna_lab_2/first/pom.xml new file mode 100644 index 0000000..49750ad --- /dev/null +++ b/borschevskaya_anna_lab_2/first/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + ru.first + first + 1.0.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + lib/ + ru.first.Main + + + + + + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/first/src/main/java/ru/first/Main.java b/borschevskaya_anna_lab_2/first/src/main/java/ru/first/Main.java new file mode 100644 index 0000000..1bdc167 --- /dev/null +++ b/borschevskaya_anna_lab_2/first/src/main/java/ru/first/Main.java @@ -0,0 +1,50 @@ +package ru.first; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Comparator; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.util.Objects.isNull; + +public class Main { + + public static final String INPUT_PATH = System.getenv("INPUT_PATH"); + public static final String OUTPUT_PATH = System.getenv("OUTPUT_PATH"); + public static final String RESULT_FILE_NAME = "data.txt"; + + public static void main(String[] args) throws IOException { + if (isNull(INPUT_PATH) || INPUT_PATH.isEmpty() || isNull(OUTPUT_PATH) || OUTPUT_PATH.isEmpty()) { + System.out.printf("Отсутствуют переменные окружения INPUT_PATH = '%s' или OUTPUT_PATH = '%s'%n", + INPUT_PATH, OUTPUT_PATH); + return; + } + var inputPathDir = Path.of(INPUT_PATH); + if (!Files.exists(inputPathDir)) { + Files.createDirectory(inputPathDir); + } + var inputDirectory = new File(INPUT_PATH); + var allDirFiles = inputDirectory.listFiles(); + if (isNull(allDirFiles) || allDirFiles.length == 0) { + System.out.println("Директория пуста"); + return; + } + var dirFiles = Arrays.stream(allDirFiles).filter(File::isFile).toList(); + if (dirFiles.isEmpty()) { + System.out.println("В указанной директории нет подходящих для обработки файлов"); + return; + } + + var shortestName = dirFiles.stream().min(Comparator.comparing(file -> file.getName().length())).get(); + + var outputPathDir = Path.of(OUTPUT_PATH); + if (!Files.exists(outputPathDir)) { + Files.createDirectory(outputPathDir); + } + var resultFilePath = Path.of(OUTPUT_PATH + File.separator + RESULT_FILE_NAME); + Files.move(Path.of(INPUT_PATH + File.separator + shortestName.getName()), resultFilePath, REPLACE_EXISTING); + } +} \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/second/Dockerfile b/borschevskaya_anna_lab_2/second/Dockerfile new file mode 100644 index 0000000..0ac7d27 --- /dev/null +++ b/borschevskaya_anna_lab_2/second/Dockerfile @@ -0,0 +1,16 @@ +FROM maven:3.8-eclipse-temurin-21-alpine AS build + +WORKDIR /app + +COPY pom.xml . +RUN mvn dependency:go-offline + +COPY src ./src + +RUN mvn clean package -DskipTests + +FROM eclipse-temurin:21-jdk-alpine + +COPY --from=build /app/target/*.jar /app.jar + +CMD ["java", "-jar", "app.jar"] \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/second/pom.xml b/borschevskaya_anna_lab_2/second/pom.xml new file mode 100644 index 0000000..ecf8f93 --- /dev/null +++ b/borschevskaya_anna_lab_2/second/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + ru.second + second + 1.0.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + lib/ + ru.second.Main + + + + + + + + \ No newline at end of file diff --git a/borschevskaya_anna_lab_2/second/src/main/java/ru/second/Main.java b/borschevskaya_anna_lab_2/second/src/main/java/ru/second/Main.java new file mode 100644 index 0000000..d0a4324 --- /dev/null +++ b/borschevskaya_anna_lab_2/second/src/main/java/ru/second/Main.java @@ -0,0 +1,51 @@ +package ru.second; + +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; + +import static java.util.Objects.isNull; + +public class Main { + + public static final String INPUT_PATH = System.getenv("INPUT_PATH"); + public static final String INPUT_FILE_NAME = "data.txt"; + + public static final String OUTPUT_PATH = System.getenv("OUTPUT_PATH"); + public static final String RESULT_FILE_NAME = "result.txt"; + + public static void main(String[] args) { + if (isNull(INPUT_PATH) || INPUT_PATH.isEmpty() || isNull(OUTPUT_PATH) || OUTPUT_PATH.isEmpty()) { + System.out.printf("Отсутствуют переменные окружения INPUT_PATH = '%s' или OUTPUT_PATH = '%s'%n", + INPUT_PATH, OUTPUT_PATH); + return; + } + + var inputFile = new File(INPUT_PATH + File.separator + INPUT_FILE_NAME); + if (!inputFile.exists()) { + System.out.println("Входной файл не существует"); + return; + } + + try (var stream = Files.lines(inputFile.toPath()); + var writer = new FileWriter(OUTPUT_PATH + File.separator + RESULT_FILE_NAME); + ) { + var min = stream.map(Main::parseInt).reduce(Integer::min); + if (min.isEmpty()) { + System.out.println("Не найдено минимальное значение среди строк файла"); + return; + } + var minValue = Math.pow(min.get(), 3); + System.out.printf("Get min value = '%d'%n", min.get()); + writer.append(Double.toString(minValue)); + System.out.printf("To file %s was written value %f%n", RESULT_FILE_NAME, minValue); + } catch (Exception ex) { + System.out.println(ex.getMessage()); + } + } + + private static Integer parseInt(String line) { + line = line.replace("\\n", ""); + return Integer.parseInt(line); + } +} \ No newline at end of file