diff --git a/zhimolostnova_anna_lab_2/.gitignore b/zhimolostnova_anna_lab_2/.gitignore new file mode 100644 index 0000000..cc114d2 --- /dev/null +++ b/zhimolostnova_anna_lab_2/.gitignore @@ -0,0 +1,2 @@ +result/ +data/ \ No newline at end of file diff --git a/zhimolostnova_anna_lab_2/README.md b/zhimolostnova_anna_lab_2/README.md new file mode 100644 index 0000000..7e25ae0 --- /dev/null +++ b/zhimolostnova_anna_lab_2/README.md @@ -0,0 +1,50 @@ +# Отчет по лабораторной работе №2 + +## Поставленные задачи + +1. Согласно вашему варианту (выбирайте любой) разработать два приложения такие, что результат первого является исходными данными для второго. +2. Изучить файлы сборки образов docker и разработать их для созданных приложений. +3. Собрать файл docker-compose.yml для запуска приложений. Разобраться с монтированием каталогов из хост-системы. +4. Правильно закоммитить результат без лишних файлов. +5. Оформить pull request по правилам и отправить его на проверку. + +## Варианты заданий + +1. **Программа 1 под вариантом 5:** Ищет в каталоге /var/data файл с самым коротким названием и перекладывает его в /var/result/data.txt. +2. **Программа 2 под вариантом 2:** Ищет наименьшее число из файла /var/data/data.txt и сохраняет его третью степень в /var/result/result.txt. + +## Запуск работы + +1. Убедиться, что установлены необходимые технологии: + - Docker: Платформа для контейнеризации приложений. + - Docker Compose: Инструмент для запуска многоконтейнерных приложений на основе `docker-compose.yaml`. Обычно поставляется вместе с Docker. Чтобы проверить, установлена ли утилита, нужно запустить команду: +```bash + docker-compose --version +``` + +2. В директории, где находится файл `docker-compose.yaml`, выполнить следующую команду для запуска всех сервисов: +```bash + docker-compose up --build +``` +Эта команда сначала выполнит сборку, а затем запустит контейнеры. + +3. После успешного запуска можно перейти в каталог проекта и увидеть папку data со сгенерированными файлами и папку result, в которой два текстовых файла: + - data.txt - файл, полученный после выполнения первой программы. + - result.txt -файл, полученный после выполнения второй программы. + +## Ход работы + +1. **Реализация генератора файлов** + Написание скрипта generate_files.py, который генерирует случайные файлы с числами и сохраняет их в папке data. Создание Dockerfile для генератора, который устанавливает Python и копирует скрипт в контейнер. (ПОстрочное описание скрипта и Dockerfile представлено в папке generator) +2. **Реализация первого приложения** + Создание первой программы в app.py, которая ищет файл с самым коротким именем в папке data и копирует его содержимое в result/data.txt. Создание Dockerfile для первого приложения с аналогичной для Dockerfile из generate структурой. +3. **Реализация второго приложения** + Создание второй программы в app.py, которая находит минимальное число из result/data.txt и записывает его третью степень в result/result.txt. Создание Dockerfile для второго приложения с аналогичной для Dockerfile из generate структурой. +4. **Создание файла docker-compose.yml** + Создание файла docker-compose.yml, в котором описываются все три сервиса (генератор, первое приложение, второе приложение). Необходимо настроить их зависимости и монтирование папок. + +Построчное описание docker-compose.yaml и других файлов выполнено в самих файлах. + +## Демонстрационное видео + +Видеозапись доступна по адресу: [https://vk.com/video193898050_456240869](https://vk.com/video193898050_456240869) \ No newline at end of file diff --git a/zhimolostnova_anna_lab_2/docker-compose.yml b/zhimolostnova_anna_lab_2/docker-compose.yml new file mode 100644 index 0000000..22c6970 --- /dev/null +++ b/zhimolostnova_anna_lab_2/docker-compose.yml @@ -0,0 +1,28 @@ +services: + # Сервис генератора файлов + generator: + build: + context: ./generator # Путь к директории с Dockerfile и скриптом генератора + volumes: + - ./data:/var/data # Монтирование локальной папки data в /var/data в контейнере + entrypoint: ["sh", "-c", "if [ -z \"$(ls -A /var/data)\" ]; then python generate_files.py; else echo '/var/data is not empty'; fi"] + # Запуск команды, проверяющей, пуста ли папка /var/data. Если пуста, запускается скрипт генерации данных. + + # Первый сервис, который ищет файл с коротким именем + first_app: + build: + context: ./first_app # Путь к директории с Dockerfile для первого приложения + volumes: + - ./data:/var/data # Монтирование локальной папки data в /var/data + - ./result:/var/result # Монтирование локальной папки result в /var/result + depends_on: + - generator # Указывает, что первый сервис зависит от завершения работы генератора + + # Второй сервис, который ищет минимальное число + second_app: + build: + context: ./second_app # Путь к директории с Dockerfile для второго приложения + volumes: + - ./result:/var/result # Монтирование локальной папки result в /var/result + depends_on: + - first_app # Указывает, что второй сервис зависит от завершения работы первого сервиса diff --git a/zhimolostnova_anna_lab_2/first_app/Dockerfile b/zhimolostnova_anna_lab_2/first_app/Dockerfile new file mode 100644 index 0000000..fa8d828 --- /dev/null +++ b/zhimolostnova_anna_lab_2/first_app/Dockerfile @@ -0,0 +1,8 @@ +# См. описание Dockerfile для генератора файлов (generator) +FROM python:3.9-slim + +WORKDIR /app + +COPY app.py /app/ + +CMD ["python", "app.py"] diff --git a/zhimolostnova_anna_lab_2/first_app/app.py b/zhimolostnova_anna_lab_2/first_app/app.py new file mode 100644 index 0000000..aa22b3c --- /dev/null +++ b/zhimolostnova_anna_lab_2/first_app/app.py @@ -0,0 +1,28 @@ +import os + +def find_shortest_filename(source_dir, result_file): + # Существует ли папка result? Если нет, то создается + result_dir = os.path.dirname(result_file) + if not os.path.exists(result_dir): + os.makedirs(result_dir) + print(f"Created directory {result_dir}") + + # Поиск файлов в исходной директории + files = [f for f in os.listdir(source_dir) if os.path.isfile(os.path.join(source_dir, f))] + + if not files: + print(f"No files found in {source_dir}") + return + + # Поиск файла с самым коротким именем + shortest_file = min(files, key=len) + shortest_file_path = os.path.join(source_dir, shortest_file) + + # Копирование содержимого в result/data.txt. Файл будет перезаписан, если уже существует + with open(shortest_file_path, 'r') as f_in, open(result_file, 'w') as f_out: + f_out.write(f_in.read()) + + print(f"Moved {shortest_file} to {result_file}") + +if __name__ == "__main__": + find_shortest_filename('/var/data', '/var/result/data.txt') diff --git a/zhimolostnova_anna_lab_2/generator/Dockerfile b/zhimolostnova_anna_lab_2/generator/Dockerfile new file mode 100644 index 0000000..966d9c5 --- /dev/null +++ b/zhimolostnova_anna_lab_2/generator/Dockerfile @@ -0,0 +1,13 @@ +# задание базового образа, на основе которого строится контейнер. +# в данном случае slim версия, , которая содержит минимальные необходимые +# компоненты для запуска Python, что уменьшает размер контейнера. +FROM python:3.9-slim + +# задание рабочей директории внутри контейнера. +WORKDIR /app + +# перемещение файлов из хоста в контейнер. +COPY generate_files.py /app/ + +# команда, выполняющаяся при запуске контейнера. +CMD ["python", "generate_files.py"] \ No newline at end of file diff --git a/zhimolostnova_anna_lab_2/generator/generate_files.py b/zhimolostnova_anna_lab_2/generator/generate_files.py new file mode 100644 index 0000000..2db8ac7 --- /dev/null +++ b/zhimolostnova_anna_lab_2/generator/generate_files.py @@ -0,0 +1,31 @@ +import os +import random +import string + +def generate_random_filename(length): + return ''.join(random.choices(string.ascii_lowercase + string.digits, k=length)) + '.txt' + +def generate_data_files(directory, num_files, min_lines, max_lines): + # Создание директории, если таковой не существует + if not os.path.exists(directory): + os.makedirs(directory) + + # Проверка, пустая ли директория + if os.listdir(directory): + print(f"{directory} is not empty, skipping file generation.") + return + + # Генерация файлов + for _ in range(num_files): + file_name = generate_random_filename(random.randint(1, 20)) + file_path = os.path.join(directory, file_name) + + with open(file_path, 'w') as f: + num_lines = random.randint(min_lines, max_lines) + for _ in range(num_lines): + f.write(f"{random.randint(1, 1000)}\n") + + print(f"Generated file: {file_path}") + +if __name__ == "__main__": + generate_data_files('/var/data', num_files=random.randint(5, 15), min_lines=1, max_lines=50) diff --git a/zhimolostnova_anna_lab_2/second_app/Dockerfile b/zhimolostnova_anna_lab_2/second_app/Dockerfile new file mode 100644 index 0000000..fa8d828 --- /dev/null +++ b/zhimolostnova_anna_lab_2/second_app/Dockerfile @@ -0,0 +1,8 @@ +# См. описание Dockerfile для генератора файлов (generator) +FROM python:3.9-slim + +WORKDIR /app + +COPY app.py /app/ + +CMD ["python", "app.py"] diff --git a/zhimolostnova_anna_lab_2/second_app/app.py b/zhimolostnova_anna_lab_2/second_app/app.py new file mode 100644 index 0000000..b119f8b --- /dev/null +++ b/zhimolostnova_anna_lab_2/second_app/app.py @@ -0,0 +1,26 @@ +import os + +def find_smallest_number_and_cube(input_file, output_file): + # Проверка, существует ли файл data.txt + if not os.path.exists(input_file): + print(f"File {input_file} does not exist.") + return + + # Чтение чисел из файла + with open(input_file, 'r') as f: + numbers = [int(line.strip()) for line in f.readlines()] + + if numbers: + smallest_number = min(numbers) + result = smallest_number ** 3 + + # Запись результата в result.txt + with open(output_file, 'w') as f_out: + f_out.write(str(result)) + + print(f"Saved the cube of the smallest number {smallest_number} to {output_file}") + else: + print(f"No numbers found in {input_file}") + +if __name__ == "__main__": + find_smallest_number_and_cube('/var/result/data.txt', '/var/result/result.txt')