# Лабораторная работа №3 ## ПИбд-42 Машкова Маргарита ## Задание 1. Создать 2 микросервиса, реализующих CRUD на связанных сущностях. 2. Реализовать механизм синхронного обмена сообщениями между микросервисами. 3. Реализовать шлюз на основе прозрачного прокси-сервера nginx. ## Запуск программы В директории с файлом `docker-compose.yml` выполнить команду: ``` docker-compose up -d ``` ## Описание работы программы ### 2 микросервиса, реализующих CRUD на связанных сущностях: #### Описание сущностей: - `Groupe` - группа в университете, содержит 2 атрибута: id и name. P.S. Слово `group` специально написано неправильно, т.к. такое слово зарезервиравано в СУБД :) - `Student` - студент, сущность содержит 4 атрибута: id, name, surname, groupeId. Соответственно сущности связаны один (группа) - ко многим (студенты). Данные микросервисы, выполняющие CRUD операции над сущностями, реализованы при помощи фреймворка `spring`. ### Реализация механизма синхронного обмена сообщениями между микросервисами: Реализуется при помощи `RestTemplate`. При получении информации о студенте или о всех студентах отправляется GET запрос к сервису `groupe-service`, чтобы получить информацию о группе, в которой учится студент. ``` private final RestTemplate restTemplate = new RestTemplate(); private final String URL = "http://groupe-service:8080/groupe/"; public StudentInfoDto findStudentInfo(Integer id){ Student student = studentRepository.findById(id) .orElseThrow(() -> new RuntimeException(String.format("Student with id %s was not found", id))); GroupeInfoDto group = restTemplate.getForObject(URL + student.getGroupeId(), GroupeInfoDto.class); StudentInfoDto studentInfoDto = new StudentInfoDto(); studentInfoDto.setId(id); studentInfoDto.setName(student.getName()); studentInfoDto.setSurname(student.getSurname()); studentInfoDto.setGroupeInfoDto(group); return studentInfoDto; } ``` ### Файл конфигурации `docker-compose.yml`: Для обеспечения работы прокси-сервера nginx в качестве шлюза, необходимо чтобы все управляемые им сервисы находились в одной сети типа "мост": ``` networks: my-network: driver: bridge ``` #### Настройка сервисов: Для сервиса БД `db-university` используется образ postgres. Также указывается порт взаимодействия, переменные окружения - логин, пароль для учетной записи в postgres и имя БД. Сервис добавлятся в созданную сеть. Опция `restart: always` означает, что docker-compose перезапустит контейнер, если тот вдруг остановится. ``` db-university: image: postgres:latest container_name: db-university ports: - 5432:5432 environment: POSTGRES_PASSWORD: admin POSTGRES_USER: admin POSTGRES_DB: university restart: always networks: - my-network ``` Для сервисов `groupe-service` и `student-service` используются образы приложений, созданные при помощи Dockerfile. Также указывается порт взаимодействия, зависимость от сервиса БД (контейнер микросервиса запускается только после запуска контейнера БД). Сервис добавлятся в созданную сеть. Опция `restart: always` означает, что docker-compose перезапустит контейнер, если тот вдруг остановится. ``` groupe-service: build: context: . dockerfile: ./groupe-service/Dockerfile container_name: groupe-service ports: - 8080:8080 restart: always depends_on: - db-university networks: - my-network student-service: build: context: . dockerfile: ./student-service/Dockerfile container_name: student-service ports: - 8081:8081 restart: always depends_on: - db-university networks: - my-network ``` ### Dockerfile сервиса `groupe-service`: Используется базовый образ openjdk:17-jdk. Задается рабочая директория /app. В нее копируется jar файл приложения. Указывается порт, на котором работает приложение. Запуск программы осуществляется посредством запуска jar файла. ``` FROM openjdk:17-jdk WORKDIR /app COPY ./groupe-service/build/libs/groupe-service-1.0-SNAPSHOT.jar /app/groupe-service-1.0-SNAPSHOT.jar EXPOSE 8080 CMD ["java", "-jar", "groupe-service-1.0-SNAPSHOT.jar"] ``` ### Dockerfile сервиса `student-service`: Структура аналогична Dockerfile сервиса `groupe-service`. ``` FROM openjdk:17-jdk WORKDIR /app COPY ./student-service/build/libs/student-service-1.0-SNAPSHOT.jar /app/student-service-1.0-SNAPSHOT.jar EXPOSE 8081 CMD ["java", "-jar", "student-service-1.0-SNAPSHOT.jar"] ``` ### Реализация шлюза на основе прозрачного прокси-сервера nginx: Для сервиса `nginx` используется образ nginx, указывается порт взаимодействия. `volumes` указывает, что при запуске контейнера, локальный файл конфигураций nginx.conf следует поместить вместо стандартного файла конфигураций nginx, а `depends_on` указывает, что данный прокси-сервер зависит от обоих сервисов и разворачивается только после их запуска. ``` nginx: image: nginx container_name: nginx ports: - "80:80" networks: - my-network volumes: - ./nginx-conf:/etc/nginx/conf.d depends_on: - groupe-service - student-service ``` ### Файл конфигурации `nginx.conf`: Данная конфигурация позволяет перенаправлять запросы, начинающиеся с `/groupe-service/` на сервер groupe-service на порту 8080, а запросы, начинающиеся с `/student-service/`, на сервер student-service на порту 8081. Заголовки запроса также передаются и устанавливаются соответствующие значения для Host и X-Forwarded-Prefix. Заголовок Host будет установлен в значение $host, заголовок X-Forwarded-Prefix - в значение `/student-service` или `/groupe-service`. ``` server { listen 80; location /groupe-service/ { proxy_pass_request_headers on; proxy_set_header Host $host; proxy_set_header X-Forwarded-Prefix '/groupe-service'; proxy_pass http://groupe-service:8080/; } location /student-service/ { proxy_pass_request_headers on; proxy_set_header Host $host; proxy_set_header X-Forwarded-Prefix '/student-service'; proxy_pass http://student-service:8081/; } } ``` ## Запуск сервисов ### Результат выполнения команды `docker-compose up -d`: ![Вывод в консоли](build_images.png) ### Созданные образы: ![Созданные образы](images.png) ### Созданные контейнеры: ![Созданные контейнеры](containers.png) ### Результаты синхронного обмена сообщениями между микросервисами: При получения списка студентов, сервис `student-service` обращается к сервису `groupe-service`, чтобы отобразить данные группы. ![results](results.png) Ссылка на видео: https://youtu.be/BCF0Lxc6veo