putilin_pavel_lab_3

This commit is contained in:
Pavel 2024-12-02 23:57:46 +04:00
parent 9808787f27
commit 3ef7c65962
12 changed files with 260 additions and 0 deletions

View File

@ -0,0 +1,66 @@
# Лабораторная работа №3 - REST API, шлюз и синхронный обмен данными между микросервисами
## Задание
### Цель:
Изучение принципов проектирования с использованием паттерна шлюза, организации синхронной передачи данных между микросервисами и применения архитектурного стиля RESTful API.
### Задачи:
1. Создание двух микросервисов, которые реализуют операции CRUD для связанных сущностей (клиенты и заказы).
2. Реализация механизма синхронного обмена данными между микросервисами.
3. Настройка шлюза на базе Nginx в качестве прозрачного прокси-сервера.
### Микросервисы:
1. **client_service** — сервис, который управляет информацией о клиентах.
2. **order_service** — сервис, который обрабатывает данные о заказах, сделанных клиентами.
### Связь между микросервисами:
- Один клиент может иметь множество заказов (соотношение 1 ко многим).
### Как запустить проект:
Для запуска приложения необходимо выполнить команду:
```
docker-compose up
```
## Описание работы:
Для разработки микросервисов был выбран язык программирования Python с использованием фреймворка Flask. Каждый микросервис реализует стандартные операции CRUD (создание, чтение, обновление и удаление) для своей сущности.
### Синхронный обмен данными
Микросервис `order_service` отправляет HTTP-запросы к сервису `client_service` для получения актуальной информации о клиентах, с которыми связаны заказы. Это позволяет создавать заказ с привязкой к конкретному клиенту, а также обновлять или удалять данные о заказах, учитывая информацию о клиенте.
### Docker Compose
Конфигурационный файл `docker-compose.yml` представляет собой многоконтейнерное приложение, которое включает в себя три сервиса: `client_service`, `order_service` и `nginx`. С помощью Docker Compose можно запустить все три контейнера одновременно. Функция маршрутизации запросов возложена на сервер Nginx, который управляет входящими запросами и перенаправляет их на соответствующие микросервисы.
### Nginx
Конфигурационный файл Nginx (`nginx.conf`) управляет маршрутизацией входящих запросов. В зависимости от URL, запросы перенаправляются на сервисы:
- Запросы по пути `/client/` перенаправляются на сервис `client_service`.
- Запросы по пути `/order/` перенаправляются на сервис `order_service`.
Пример конфигурации Nginx:
```nginx
server {
listen 80;
location /client/ {
proxy_pass http://client_service:8000;
}
location /order/ {
proxy_pass http://order_service:8001;
}
}
```
### Взаимодействие между микросервисами
- **client_service**: Этот сервис управляет информацией о клиентах (например, имя клиента, номер и дата выдачи).
- **order_service**: Этот сервис управляет заказами и хранит информацию о каждом заказе, связанном с конкретным клиентом. Заказы могут быть созданы, обновлены или удалены через RESTful API.
Когда заказ создается или обновляется в `order_service`, он отправляет запрос к `client_service`, чтобы получить подробную информацию о клиенте (например, имя, номер и дата выдачи абонемента).
### ВИДЕО
https://cloud.mail.ru/public/oG1Y/GXywRodDN

View File

@ -0,0 +1,10 @@
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@ -0,0 +1,39 @@
from fastapi import FastAPI, HTTPException
from uuid import uuid4
app = FastAPI()
# Временное хранилище для клиентов
clients = {}
@app.get("/")
def get_clients():
return list(clients.values())
@app.get("/{client_id}")
def get_client(client_id: str):
if client_id not in clients:
raise HTTPException(status_code=404, detail="Client not found")
return clients[client_id]
@app.post("/")
def create_client(client: dict):
client_id = str(uuid4())
new_client = {"id": client_id, **client}
clients[client_id] = new_client
return new_client
@app.put("/{client_id}")
def update_client(client_id: str, client: dict):
if client_id not in clients:
raise HTTPException(status_code=404, detail="Client not found")
updated_client = {"id": client_id, **client}
clients[client_id] = updated_client
return updated_client
@app.delete("/{client_id}")
def delete_client(client_id: str):
if client_id not in clients:
raise HTTPException(status_code=404, detail="Client not found")
del clients[client_id]
return {"detail": "Client deleted successfully"}

View File

@ -0,0 +1,2 @@
fastapi
uvicorn

View File

@ -0,0 +1,36 @@
version: "3.8"
services:
client_service:
build:
context: ./client_service
container_name: client_service
ports:
- "8000:8000"
networks:
- app_network
order_service:
build:
context: ./order_service
container_name: order_service
ports:
- "8001:8001"
networks:
- app_network
environment:
- CLIENT_SERVICE_URL=http://client_service:8000
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- app_network
networks:
app_network:
driver: bridge

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,5 @@
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

View File

@ -0,0 +1,17 @@
server {
listen 80;
location /client/ {
proxy_pass http://client_service:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /order/ {
proxy_pass http://order_service:8001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

View File

@ -0,0 +1,10 @@
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8001"]

View File

@ -0,0 +1,72 @@
from fastapi import FastAPI, HTTPException
from uuid import uuid4
import requests
app = FastAPI()
# Временное хранилище для заказов
orders = {}
# URL микросервиса клиентов (обновим при подключении Docker Compose)
CLIENT_SERVICE_URL = "http://client_service:8000"
@app.get("/")
def get_orders():
return list(orders.values())
@app.get("/{order_id}")
def get_order(order_id: str):
if order_id not in orders:
raise HTTPException(status_code=404, detail="Order not found")
return orders[order_id]
@app.post("/")
def create_order(order: dict):
# Проверка существования клиента
client_id = order.get("client_id")
if not client_id:
raise HTTPException(status_code=400, detail="client_id is required")
try:
response = requests.get(f"{CLIENT_SERVICE_URL}/{client_id}")
response.raise_for_status()
except requests.exceptions.RequestException:
raise HTTPException(status_code=404, detail="Client not found")
# Создание заказа
order_id = str(uuid4())
new_order = {"id": order_id, **order}
orders[order_id] = new_order
return new_order
@app.put("/{order_id}")
def update_order(order_id: str, order: dict):
if order_id not in orders:
raise HTTPException(status_code=404, detail="Order not found")
# Проверка существования клиента
client_id = order.get("client_id")
if not client_id:
raise HTTPException(status_code=400, detail="client_id is required")
try:
response = requests.get(f"{CLIENT_SERVICE_URL}/{client_id}")
response.raise_for_status()
except requests.exceptions.RequestException:
raise HTTPException(status_code=404, detail="Client not found")
updated_order = {"id": order_id, **order}
orders[order_id] = updated_order
return updated_order
@app.delete("/{order_id}")
def delete_order(order_id: str):
if order_id not in orders:
raise HTTPException(status_code=404, detail="Order not found")
del orders[order_id]
return {"detail": "Order deleted successfully"}

View File

@ -0,0 +1,3 @@
fastapi
uvicorn
requests