diff --git a/alkin_ivan_lab_3/README.md b/alkin_ivan_lab_3/README.md new file mode 100644 index 0000000..810d813 --- /dev/null +++ b/alkin_ivan_lab_3/README.md @@ -0,0 +1,42 @@ +# Лабораторная работа №3: REST API, шлюз и синхронный обмен данными между микросервисами + +## Задание + +### Цель +Изучение принципов проектирования на основе паттерна шлюза, организации синхронного взаимодействия микросервисов и использования RESTful API. + +### Основные задачи +1. Разработка двух микросервисов с поддержкой CRUD-операций для связанных сущностей. +2. Организация синхронного обмена данными между микросервисами. +3. Настройка шлюза на базе Nginx, выступающего в роли прозрачного прокси-сервера. + +### Микросервисы +1. **hero_service** — микросервис для управления информацией о героях. +2. **item_service** — микросервис для обработки данных о предметах, принадлежащих героям. + +### Связь между микросервисами +- Один герой (**hero**) может иметь множество связанных предметов (**items**) (соотношение 1:многие). + +## Инструкция по запуску +Для запуска проекта выполните команду: +```bash +docker-compose up +``` + +## Описание работы + +### Разработка микросервисов +Микросервисы разработаны с использованием языка программирования Python. + +### Синхронное взаимодействие +`hero_service` обращается к `item_service` через HTTP-запросы для выполнения операций CRUD. Это позволяет получать актуальные данные о предметах, связанных с героями. + +### Docker Compose +Файл `docker-compose.yml` описывает многоконтейнерное приложение, включающее три сервиса: `hero_service`, `item_service` и `nginx`. Nginx выполняет маршрутизацию запросов между сервисами. + +### Nginx +Конфигурация Nginx задает параметры веб-сервера и обратного прокси, который принимает входящие запросы и направляет их к соответствующим микросервисам. + +### Видеоматериал +Подробнее ознакомиться с проектом можно в видео: +https://vkvideo.ru/video150882239_456240342 \ No newline at end of file diff --git a/alkin_ivan_lab_3/docker-compose.yml b/alkin_ivan_lab_3/docker-compose.yml new file mode 100644 index 0000000..eaa095c --- /dev/null +++ b/alkin_ivan_lab_3/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + hero_service: + build: + context: ./hero_service + dockerfile: Dockerfile + ports: + - "5000:5000" + + item_service: + build: + context: ./item_service + dockerfile: Dockerfile + ports: + - "5001:5001" + + nginx: + image: nginx:latest + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf + ports: + - "80:80" + depends_on: + - hero_service + - item_service diff --git a/alkin_ivan_lab_3/hero_service/Dockerfile b/alkin_ivan_lab_3/hero_service/Dockerfile new file mode 100644 index 0000000..7a7319a --- /dev/null +++ b/alkin_ivan_lab_3/hero_service/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["python", "main.py"] diff --git a/alkin_ivan_lab_3/hero_service/main.py b/alkin_ivan_lab_3/hero_service/main.py new file mode 100644 index 0000000..9efb650 --- /dev/null +++ b/alkin_ivan_lab_3/hero_service/main.py @@ -0,0 +1,51 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +heroes = {} + +@app.route('/heroes', methods=['GET']) +def get_heroes(): + return jsonify(list(heroes.values())) + +@app.route('/heroes/', methods=['GET']) +def get_hero(hero_uuid): + hero = heroes.get(str(hero_uuid)) + if hero: + return jsonify(hero) + return jsonify({'error': 'Not found'}), 404 + +@app.route('/heroes', methods=['POST']) +def create_hero(): + data = request.get_json() + hero_uuid = str(uuid.uuid4()) + hero = { + 'uuid': hero_uuid, + 'name': data['name'], + 'role': data['role'], + 'strength': data['strength'] + } + heroes[hero_uuid] = hero + return jsonify(hero), 201 + +@app.route('/heroes/', methods=['PUT']) +def update_hero(hero_uuid): + hero = heroes.get(str(hero_uuid)) + if not hero: + return jsonify({'error': 'Not found'}), 404 + data = request.get_json() + hero['name'] = data['name'] + hero['role'] = data['role'] + hero['strength'] = data['strength'] + return jsonify(hero) + +@app.route('/heroes/', methods=['DELETE']) +def delete_hero(hero_uuid): + if str(hero_uuid) in heroes: + del heroes[str(hero_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) diff --git a/alkin_ivan_lab_3/hero_service/requirements.txt b/alkin_ivan_lab_3/hero_service/requirements.txt new file mode 100644 index 0000000..e3e9a71 --- /dev/null +++ b/alkin_ivan_lab_3/hero_service/requirements.txt @@ -0,0 +1 @@ +Flask diff --git a/alkin_ivan_lab_3/item_service/Dockerfile b/alkin_ivan_lab_3/item_service/Dockerfile new file mode 100644 index 0000000..7a7319a --- /dev/null +++ b/alkin_ivan_lab_3/item_service/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["python", "main.py"] diff --git a/alkin_ivan_lab_3/item_service/main.py b/alkin_ivan_lab_3/item_service/main.py new file mode 100644 index 0000000..a1c4890 --- /dev/null +++ b/alkin_ivan_lab_3/item_service/main.py @@ -0,0 +1,51 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +items = {} + +@app.route('/items', methods=['GET']) +def get_items(): + return jsonify(list(items.values())) + +@app.route('/items/', methods=['GET']) +def get_item(item_uuid): + item = items.get(str(item_uuid)) + if item: + return jsonify(item) + return jsonify({'error': 'Not found'}), 404 + +@app.route('/items', methods=['POST']) +def create_item(): + data = request.json + item_uuid = str(uuid.uuid4()) + item = { + 'uuid': item_uuid, + 'name': data['name'], + 'type': data['type'], + 'hero_uuid': data['hero_uuid'] + } + items[item_uuid] = item + return jsonify(item), 201 + +@app.route('/items/', methods=['PUT']) +def update_item(item_uuid): + item = items.get(str(item_uuid)) + if not item: + return jsonify({'error': 'Not found'}), 404 + data = request.json + item['name'] = data['name'] + item['type'] = data['type'] + item['hero_uuid'] = data['hero_uuid'] + return jsonify(item) + +@app.route('/items/', methods=['DELETE']) +def delete_item(item_uuid): + if str(item_uuid) in items: + del items[str(item_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001) diff --git a/alkin_ivan_lab_3/item_service/requirements.txt b/alkin_ivan_lab_3/item_service/requirements.txt new file mode 100644 index 0000000..e3e9a71 --- /dev/null +++ b/alkin_ivan_lab_3/item_service/requirements.txt @@ -0,0 +1 @@ +Flask diff --git a/alkin_ivan_lab_3/nginx/nginx.conf b/alkin_ivan_lab_3/nginx/nginx.conf new file mode 100644 index 0000000..3774360 --- /dev/null +++ b/alkin_ivan_lab_3/nginx/nginx.conf @@ -0,0 +1,11 @@ +server { + listen 80; + + location /heroes { + proxy_pass http://hero_service:5000; + } + + location /items { + proxy_pass http://item_service:5001; + } +}