# Лабораторная работа 3. REST API, Gateway и синхронный обмен между микросервисами ### Задание на лабораторную работу 1. Создать 2 микросервиса, реализующих CRUD на связанных сущностях. 2. Реализовать механизм синхронного обмена сообщениями между микросервисами. 3. Реализовать шлюз на основе прозрачного прокси-сервера nginx. *** ### Как запустить лабораторную работу Для сборки и запуска программ необходимо перейти в директорию с файлом `docker-compose.yaml` и выполнить команду: ``` docker-compose up -d ``` *** ### Описание работы Были созданы два микросервиса на *java*, каждый реализует CRUD-операции: список записей, подробности конкретной записи, создание, удаление и изменение записи. Микросервисы реализованы при помощи фреймворка *spring*. **Описание сущностей:** - *user* - пользователь. Поля: *id* (уникальный идентификатор пользователя), *fullName* (ФИО), *phoneNumber* (номер телефона), *role* (роль - ученик/репетитор). - *message* - сообщение. Поля: *id* (уникальный идентификатор сообщения), *text* (текст), *status* (статус - отправлено/получено/прочитано), *date* (дата отправки), *userId* (id пользователя). Сущности связаны отношением один-ко-многим (пользователь-сообщения). **Реализация синхронного обмена:** Синхронный обмен между сообщениями реализуется при помощи RestTemplate. При получении информации о сообщении через GET запрос к user-service получаются данные о пользователе-отправителе сообщения. Пример реализации при получении записи о сообщении в `MessageService`: ``` private final MessageRepository messageRepository; private final RestTemplate restTemplate; private final String URL = "http://user-service:8085/user/"; @Autowired public MessageService(MessageRepository messageRepository, RestTemplate restTemplate) { this.messageRepository = messageRepository; this.restTemplate = restTemplate; } @Transactional(readOnly = true) public MessageWithUserInfoDto findMessage(Long id) { final Message message = messageRepository.findById(id).orElse(null); if (message == null) { throw new MessageNotFoundException(id); } UserInfoDto userInfo = restTemplate.getForObject(URL + message.getUserId(), UserInfoDto.class); return new MessageWithUserInfoDto(message, userInfo); } ``` **Dockerfile** Используется базовый образ *openjdk:17-jdk*, на основе которого будет создан контейнер. Внутри контейнера создается директория `/usr/src/app/`, после устанавливается рабочая директория и файлы из каталога, где находится Dockerfile, копируются внутрь контейнера в директорию `/usr/src/app/`. Выполняется сборка проекта с помощью инструмента gradlew. Задается порт и указывается точка входа для контейнера. Запуск java-приложения осуществляется посредством запуска jar-файла. Содержимое `Dockerfile` для сервиса `user-service`: ``` FROM openjdk:17 RUN mkdir -p /usr/src/app/ WORKDIR /usr/src/app/ COPY . /usr/src/app/ RUN ./gradlew clean build EXPOSE 8085 ENTRYPOINT ["java","-jar","build/libs/user-service-1.0-SNAPSHOT.jar"] ``` Аналогично был составлен `Dockerfile` для сервиса `message-service`. **Файл конфигурации nginx.conf** Файл `nginx.conf` содержит конфигурацию для сервера *nginx*. Конфигурация позволяет перенаправлять запросы, начинающиеся с /user-service/ на сервер user-service на порту 8085, а запросы, начинающиеся с /message-service/, на сервер message-service на порту 8086. ``` server { listen 80; listen [::]:80; server_name localhost; location /user-service/ { proxy_pass http://user-service:8085/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Prefix /user-service; } location /message-service/ { proxy_pass http://message-service:8086/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Prefix /message-service; } } ``` **Файл конфигурации docker-compose.yml** В файле `docker-compose.yml` указана версия синтаксиса *Docker Compose*, определен список сервисов, которые будут развернуты в приложении, и определена сеть с именем "network", которая будет использоваться для связи между контейнерами. Файл определяет три сервиса: *user-service*, *message-service* и *nginx*. Для сервисов user-service и message-service используются образы приложений, созданные при помощи Dockerfile. Сервис *nginx* использует образ *nginx*. Параметр *depends_on* определяет зависимости сервисов (*nginx* зависит от сервисов *user-service* и *message-service* и разворачивается только после их запуска), в *ports* настраивается проброс портов. ``` version: '3' services: user-service: build: context: /user-service dockerfile: Dockerfile ports: - 8085:8085 networks: - network message-service: build: context: /message-service dockerfile: Dockerfile ports: - 8086:8086 networks: - network nginx: image: nginx ports: - 8087:80 networks: - network volumes: - ./nginx-conf:/etc/nginx/conf.d depends_on: - user-service - message-service networks: network: driver: bridge ``` *** ### Скриншоты ***Результаты сборки и запуска программ в консоли*** ![](images/console.jpg) ***Образы в Dockerhub*** ![](images/dockerhub1.jpg) ***Контейнеры в Dockerhub*** ![](images/dockerhub2.jpg) ***Информация по пользователю*** ![](images/user.jpg) ***Информация по сообщению*** ![](images/message.jpg) ### Ссылка на видео: https://drive.google.com/file/d/19pw4LWiuzK2tDHlSSbKbxNWPsvbUzWwd/view?usp=sharing