## Лабораторная работа 2. Вариант 4. ### Задание - Разработать два приложения такие, что результат первого является исходными данными для второго. - Изучить файлы сборки образов `docker` и разработать их для созданных приложений. - Собрать файл `docker-compose.yaml` для запуска приложений. Разобраться с монтированием каталогов из хост-системы. Вариант задания: - `worker-1` - Берёт из каталога `/var/data` случайный файл и перекладывает его в `/var/result/data.txt`. - `worker-2` - Сохраняет произведение первого и последнего числа из файла `/var/data/data.txt` в `/var/result/result.txt`. ### Как запустить В директории с файлом характеристик `docker-compose.yaml` выполнить команду: ``` docker-compose -f docker-compose.yaml up ``` Это запустит `docker-compose`, который развернёт в общем контейнере 2 контейнера с сервисами по собранным из `Dockerfile` образам. ### Описание работы #### Подготовка файлов В корневой папке лабораторной работы создадим две директории: `data` и `result`. Директория `data` будет являться удалённой директорией с входными файлами для 1го приложения. Входные файлы и их содержание: ``` rand0.txt - 42, 17, 99, 23, 76 rand1.txt - 55, 12, 88, 37, 61 rand2.txt - 29, 83, 44, 68, 91 rand3.txt - 10, 57, 72, 33, 94 ``` Директория `result` будет служить далённой директорией с входными файлами для 2го приложения и удалённой директорией для выходного файла 1го приложения, поэтому оставляем её пустой. #### Разработка приложения Worker-1 Согласно заданию, `worker-1` берёт из каталога `/var/data` случайный файл и перекладывает его в `/var/result/data.txt`. Приложение реализовано на языке Java. Код логической части приложения: ```java Files.move(files[rm.nextInt(files.length)].toPath(), new File(result_directory).toPath(), StandardCopyOption.REPLACE_EXISTING); ``` Для сборки образа и запуска приложения в контейнере создадим `Dockerfile`: ```dockerfile FROM openjdk:21-jdk RUN ["mkdir", "/var/data"] RUN ["mkdir", "/var/result"] COPY src/Main.java /opt/app/Main.java WORKDIR /opt/app RUN ["javac", "Main.java"] CMD ["java", "Main"] ``` В данном файле с помощью функции `RUN` мы передаём в `bash` среду созданного контейнера комманды создания входных и выходных директорий `mkdir /var/data` и `mkdir /var/result`. После этого мы задаём в контейнере рабочую директорию, копируем исполняемый класс приложения в рабочую директорию и компилируем его. При запуске контейнера с помощью функции `CMD` указыыаем действие `java Main` запуска приложения. #### Разработка приложения Worker-2 Согласно заданию, `worker-2` сохраняет произведение первого и последнего числа из файла `/var/data/data.txt` в `/var/result/result.txt`. Приложение реализовано на языке Java. Код логической части приложения: ```java Scanner scanner = new Scanner(data_file); int[] num = Arrays.stream(scanner.nextLine().split(", ")) .mapToInt(Integer::parseInt) .toArray(); scanner.close(); FileWriter writer = new FileWriter(result_file); writer.write(num[0] * num[num.length - 1] + ""); writer.close(); System.out.println("" + (num[0] * num[num.length - 1])); ``` Для сборки образа и запуска приложения в контейнере создадим `Dockerfile`: ```dockerfile FROM openjdk:21-jdk RUN ["mkdir", "/var/data"] RUN ["mkdir", "/var/result"] COPY src/Main.java /opt/app/Main.java WORKDIR /opt/app RUN ["javac", "Main.java"] CMD ["java", "Main"] ``` Логика сборки образа приложения `worker-2` идентична логике приложения `worker-1`. #### Разворачивание приложений Конфигурации `worker-1` в `docker-compose.yaml`: ```yaml worker-1: build: context: /worker-1 dockerfile: Dockerfile volumes: - .\data:/var/data - .\result:/var/result ``` Где `build` указывает на метод сборки образа в котором: `context` указывает на корневую директорию приложения, а `dockerfile` указывает на путь к `Dockerfile`,`volumes` устанавливает локальную папку `data` как папку входных файлов `/var/data`, а локальную папку `result` - как папку выходных файлов `/var/result`. Конфигурации `worker-2` в `docker-compose.yaml`: ```yaml worker-2: depends_on: - worker-1 build: context: /worker-2 dockerfile: Dockerfile volumes: - .\result:/var/data - .\result:/var/result ``` Где `depends_on` указывает на зависимость от 1го приложения и возможность запуска только после него, `build` указывает на метод сборки образа в котором: `context` указывает на корневую директорию приложения, а `dockerfile` указывает на путь к `Dockerfile`,`volumes` устанавливает локальную папку `result` как папку входных файлов `/var/data` и как папку выходных файлов `/var/result` одновременно. #### Запуск приложений Выполнение команды docker-compose и log-журнал контейнеров: ![](pic1.png "") ![](pic2.png "") Файлы директоиии `data` и их содержание: ``` rand0.txt - 42, 17, 99, 23, 76 rand2.txt - 29, 83, 44, 68, 91 rand3.txt - 10, 57, 72, 33, 94 ``` Файлы директоиии `result` и их содержание: ``` data.txt - 55, 12, 88, 37, 61 result.txt - 3355 ``` ### Видео https://youtu.be/WASbBhDiAwg