diff --git a/vasina_ekaterina_lab_3/README.md b/vasina_ekaterina_lab_3/README.md new file mode 100644 index 0000000..9546373 --- /dev/null +++ b/vasina_ekaterina_lab_3/README.md @@ -0,0 +1,53 @@ + +# Лабораторная работа №3 - REST API, шлюз и синхронный обмен данными между микросервисами + +## Задание + +### Цель +Изучение принципов проектирования с использованием паттерна шлюза, организации синхронной передачи данных между микросервисами и применения архитектурного стиля RESTful API. + +### Задачи +1. Создание двух микросервисов, которые реализуют операции CRUD для связанных сущностей. +2. Реализация механизма синхронного обмена данными между микросервисами. +3. Настройка шлюза на базе Nginx в качестве прозрачного прокси-сервера. + +### Микросервисы +1. **user_service** — сервис, который управляет информацией о пользователях. +2. **order_service** — сервис, который обрабатывает данные о заказах пользователей. + +### Связь между микросервисами +- Один документ (user) может иметь множество связанных предметов (orders) (соотношение 1 ко многим). + +### Структура проекта + +``` +lab_3/ +|-- nginx/ +| |-- nginx.conf +|-- order_service/ +| |-- Dockerfile +| |-- main.py +| |-- requirements.txt +|-- user_service/ +| |-- Dockerfile +| |-- main.py +| |-- requirements.txt +|-- docker-compose.yml +``` + +## Описание работы: + +Для разработки микросервисов был выбран язык программирования Python. + +### Синхронный обмен данными +Сервис `user_service` отправляет HTTP-запросы к `order_service` при выполнении определенных операций CRUD. Это позволяет получать актуальную информацию о предметах, связанных с конкретными героями. + +### Docker Compose +Конфигурационный файл `docker-compose.yml` представляет собой многоконтейнерное приложение, которое включает в себя три сервиса: `user_service`, `order_service` и `nginx`. Функция маршрутизации возложена на сервер Nginx, который обрабатывает запросы и перенаправляет их на соответствующие микросервисы. + +### Nginx +Конфигурационный файл Nginx определяет настройки веб-сервера и обратного прокси, который управляет входящими запросами и направляет их на соответствующие сервисы. + +### Видеозапись работы программы + +https://vkvideo.ru/video174596752_456239396 \ No newline at end of file diff --git a/vasina_ekaterina_lab_3/docker-compose.yml b/vasina_ekaterina_lab_3/docker-compose.yml new file mode 100644 index 0000000..7afd3c4 --- /dev/null +++ b/vasina_ekaterina_lab_3/docker-compose.yml @@ -0,0 +1,24 @@ +services: + user_service: + build: + context: ./user_service + dockerfile: Dockerfile + ports: + - "5000:5000" + + order_service: + build: + context: ./order_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: + - user_service + - order_service diff --git a/vasina_ekaterina_lab_3/nginx/nginx.conf b/vasina_ekaterina_lab_3/nginx/nginx.conf new file mode 100644 index 0000000..cc99b23 --- /dev/null +++ b/vasina_ekaterina_lab_3/nginx/nginx.conf @@ -0,0 +1,11 @@ +server { + listen 80; + + location /users { + proxy_pass http://user_service:5000; + } + + location /orders { + proxy_pass http://order_service:5001; + } +} diff --git a/vasina_ekaterina_lab_3/order_service/Dockerfile b/vasina_ekaterina_lab_3/order_service/Dockerfile new file mode 100644 index 0000000..7a7319a --- /dev/null +++ b/vasina_ekaterina_lab_3/order_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/vasina_ekaterina_lab_3/order_service/main.py b/vasina_ekaterina_lab_3/order_service/main.py new file mode 100644 index 0000000..2c056b6 --- /dev/null +++ b/vasina_ekaterina_lab_3/order_service/main.py @@ -0,0 +1,56 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +orders = {} + +# вывод всех заказов +@app.route('/orders', methods=['GET']) +def get_orders(): + return jsonify(list(orders.values())) + +# получение заказа по uuid +@app.route('/orders/', methods=['GET']) +def get_order(order_uuid): + order = orders.get(str(order_uuid)) + if order: + return jsonify(order) + return jsonify({'error': 'Not found'}), 404 + +# добавление нового заказа +@app.route('/orders', methods=['POST']) +def create_order(): + data = request.json + order_uuid = str(uuid.uuid4()) + order = { + 'uuid': order_uuid, + 'number': data['number'], + 'product': data['product'], + 'user_uuid': data['user_uuid'] + } + orders[order_uuid] = order + return jsonify(order), 201 + +# изменение заказа по uuid +@app.route('/orders/', methods=['PUT']) +def update_order(order_uuid): + order = orders.get(str(order_uuid)) + if not order: + return jsonify({'error': 'Not found'}), 404 + data = request.json + order['number'] = data['number'] + order['product'] = data['product'] + order['user_uuid'] = data['user_uuid'] + return jsonify(order) + +# удаление заказа по uuid +@app.route('/orders/', methods=['DELETE']) +def delete_order(order_uuid): + if str(order_uuid) in orders: + del orders[str(order_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001) diff --git a/vasina_ekaterina_lab_3/order_service/requirements.txt b/vasina_ekaterina_lab_3/order_service/requirements.txt new file mode 100644 index 0000000..e3e9a71 --- /dev/null +++ b/vasina_ekaterina_lab_3/order_service/requirements.txt @@ -0,0 +1 @@ +Flask diff --git a/vasina_ekaterina_lab_3/user_service/Dockerfile b/vasina_ekaterina_lab_3/user_service/Dockerfile new file mode 100644 index 0000000..7a7319a --- /dev/null +++ b/vasina_ekaterina_lab_3/user_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/vasina_ekaterina_lab_3/user_service/main.py b/vasina_ekaterina_lab_3/user_service/main.py new file mode 100644 index 0000000..632063a --- /dev/null +++ b/vasina_ekaterina_lab_3/user_service/main.py @@ -0,0 +1,54 @@ +from flask import Flask, jsonify, request +import uuid + +app = Flask(__name__) + +users = {} + +# вывод всех пользователей +@app.route('/users', methods=['GET']) +def get_users(): + return jsonify(list(users.values())) + +# получение пользователя по uuid +@app.route('/users/', methods=['GET']) +def get_user(user_uuid): + user = users.get(str(user_uuid)) + if user: + return jsonify(user) + return jsonify({'error': 'Not found'}), 404 + +# добавление нового пользователя +@app.route('/users', methods=['POST']) +def create_user(): + data = request.get_json() + user_uuid = str(uuid.uuid4()) + user = { + 'uuid': user_uuid, + 'name': data['name'], + 'age': data['age'] + } + users[user_uuid] = user + return jsonify(user), 201 + +# изменение пользователя по uuid +@app.route('/users/', methods=['PUT']) +def update_user(user_uuid): + user = users.get(str(user_uuid)) + if not user: + return jsonify({'error': 'Not found'}), 404 + data = request.get_json() + user['name'] = data['name'] + user['age'] = data['age'] + return jsonify(user) + +# удаление пользователя по uuid +@app.route('/users/', methods=['DELETE']) +def delete_user(user_uuid): + if str(user_uuid) in users: + del users[str(user_uuid)] + return '', 204 + return jsonify({'error': 'Not found'}), 404 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000) diff --git a/vasina_ekaterina_lab_3/user_service/requirements.txt b/vasina_ekaterina_lab_3/user_service/requirements.txt new file mode 100644 index 0000000..e3e9a71 --- /dev/null +++ b/vasina_ekaterina_lab_3/user_service/requirements.txt @@ -0,0 +1 @@ +Flask