Готовая лабораторная работа 3

This commit is contained in:
2025-10-23 18:22:53 +04:00
parent f769aef564
commit 94830fea4d
9 changed files with 407 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
# Лабораторная работа №1
## Как запустить лабораторную работу
1. Переносим в Visual Studia Code нашу папку с docker-compose.yml и остальными файлами.
2. Открываем сочитанием Ctrl + Shift + ` терминал.
3. Вводим туда команду docker-compose up --build (Нужно подождать пока все пакеты загрузятся). При вводе команды нужно убедится что Docker Desktop запущен.
4. Далее в Docker Desktop мы можем запустить через порт наш сервис, например запустим порт 5001 и вывод будет вот таким:
```json
{
"category": "processor",
"name": "Intel Core i5",
"price": 25000,
"uuid": "comp-1"
},
{
"category": "graphics_card",
"name": "NVIDIA RTX 4070",
"price": 60000,
"uuid": "comp-2"
}
```
5. Как тестировать и пользоваться данной программой будет в пенкту Тесты.
## Какие технологии использовали
1. Docker - контейнеризация приложений
2. Docker Compose - оркестрация многоконтейнерного приложения
3. Nginx - API gateway и reverse proxy
4. Flask - веб-фреймворк для создания REST API
5. Python - основной язык программирования
6. Requests - библиотека для HTTP-запросов
7. Postman - тестирование запросов программного продукта
## Что она делает
Это веб-приложение для сборки компьютеров, построенное на микросервисной архитектуре. Оно состоит из двух основных сервисов: один управляет комплектующими (процессоры, видеокарты, память), а другой отвечает за сборки ПК.
Пользователь может создавать сборки компьютеров, добавляя в них различные компоненты по их идентификаторам. Когда запрашивается информация о конкретной сборке, система автоматически обращается к сервису комплектующих и подгружает полные данные о всех компонентах - их названия, категории и цены.
Все запросы проходят через единый шлюз на Nginx, который перенаправляет их к нужному микросервису.
## Тесты
Для тестирования программы использовался Postman
**Нам нужно проверить 5 запросов у двух сервисов: component и build. Виды запросов:**
1. GET - получить список всех компонентов или сборок ПК
2. GET /{uuid} - получить элемент списка компонентов или сборок ПК по его id (в случии вызова сборки ПК так же будет выводится подробная информация о комплектующем)
3. POST - Создать элемент компонентов или сборок ПК
4. PUT /{uuid} - обновить элемент списка компонентов или сборок ПК по его id
5. DELETE /{uuid} - удалить элемент списка компонентов или сборок ПК по его id
**Для начала тестирования нам нужно:**
1. Создать новую коллекцию(у нас их будет 2: build, component)
2. Добавить туда 5 requast и каждому из них присвоить соответствующие запросы
3. Далее в URL нужно добавить наш порт, и в зависимости он запроса, нужно добавить id в таком формате: http://localhost:5002/id
4. Если нужно изменить или создать элемент то нажимаеем на пункт Body, далее нажимаем на raw и после добавляем или изменяем запись в json формате
**Разберем на примере build все запросы:**
1. Post
* Правильный запрос
URL: http://localhost:5002/
```json
{
"name": "PC1",
"component_id": [
"comp-1"
]
}
```
Результат: 200 OK
* Неправильный запрос
URL: http://localhost:5002/
```json
{
"component_id": [
"comp-1"
]
}
```
Результат: Ошибка 500 (INTERNAL SERVER ERROR)
2. Get
* Правильный запрос
URL: http://localhost:5002/
```json
{
"components": [
"comp-1"
],
"name": "PC1",
"uuid": "e32976c4-9e9d-44c8-bcf1-81b3238d23f0"
}
```
Результат: 200 OK
3. Get /{uuid}
* Правильный запрос
URL: http://localhost:5002/e32976c4-9e9d-44c8-bcf1-81b3238d23f0
```json
{
"components": [
"comp-1"
],
"components_details": [
{
"category": "processor",
"name": "Intel Core i5",
"price": 25000,
"uuid": "comp-1"
}
],
"name": "PC1",
"uuid": "e32976c4-9e9d-44c8-bcf1-81b3238d23f0"
}
```
Результат: 200 OK
* Неправильный запрос
URL: http://localhost:5002/e32
Результат: Ошибка 404 NOT FOUND
4. PUT /{uuid}
* Правильный запрос
URL: http://localhost:5002/e32976c4-9e9d-44c8-bcf1-81b3238d23f0
```json
{
"components": [
"comp-2"
],
"name": "PC3"
}
```
Результат: 200 OK
* Неправильный запрос
URL: http://localhost:5002/e32
Результат: Ошибка 404 NOT FOUND
5. DELETE /{uuid}
* Правильный запрос
URL: http://localhost:5002/e32976c4-9e9d-44c8-bcf1-81b3238d23f0
Результат: 200 OK
* Неправильный запрос
URL: http://localhost:5002/e32
Результат: Ошибка 404 NOT FOUND
## Видеоотчет
https://rutube.ru/video/private/6e4e75bb7d1ede9f1fa45627d33fa73c/?p=QtwDp85zXK3jVJ77Tl3azw

View File

@@ -0,0 +1,26 @@
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- microservice_components
- microservice_builds
microservice_components:
build:
context: ./microservice_components
dockerfile: Dockerfile
ports:
- "5001:5001"
microservice_builds:
build:
context: ./microservice_builds
dockerfile: Dockerfile
ports:
- "5002:5002"

View File

@@ -0,0 +1,14 @@
FROM python:3.9-alpine
WORKDIR /app
RUN apk add --no-cache gcc musl-dev
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5002
CMD ["python", "app.py"]

View File

@@ -0,0 +1,73 @@
from flask import Flask, jsonify, request
import requests
import uuid
app = Flask(__name__)
builds = {}
COMPONENTS_SERVICE = "http://microservice_components:5001"
def get_component_details(component_id):
try:
response = requests.get(f"{COMPONENTS_SERVICE}/{component_id}")
if response.status_code == 200:
return response.json()
return None
except requests.exceptions.RequestException:
return None
@app.route('/', methods=['GET'])
def get_builds():
return jsonify(list(builds.values()))
@app.route('/<build_id>', methods=['GET'])
def get_build(build_id):
build = builds.get(build_id)
if not build:
return jsonify({"error": "Build not found"}), 404
build_with_details = build.copy()
build_with_details["components_details"] = []
for component_uuid in build.get("components", []):
component_details = get_component_details(component_uuid)
if component_details:
build_with_details["components_details"].append(component_details)
else:
return jsonify({"error": "Build not found"}), 404
return jsonify(build_with_details)
@app.route('/', methods=['POST'])
def create_build():
data = request.get_json()
build_id = str(uuid.uuid4())
build = {
"uuid": build_id,
"name": data['name'],
"components": data['component_id']
}
builds[build_id] = build
return jsonify(build), 201
@app.route('/<build_id>', methods=['PUT'])
def update_build(build_id):
build = builds.get(str(build_id))
if not build:
return jsonify({'error': 'Not found'}), 404
data = request.json
build['name'] = data.get('name', build['name'])
build["components"] = data.get('components', build['components'])
return jsonify(build)
@app.route('/<build_id>', methods=['DELETE'])
def delete_build(build_id):
if build_id not in builds:
return jsonify({"error": "Not found"}), 404
del builds[build_id]
return jsonify({"message": "Build deleted"}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5002, debug=True)

View File

@@ -0,0 +1,2 @@
flask==2.3.3
requests==2.31.0

View File

@@ -0,0 +1,12 @@
FROM python:3.9-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5001
CMD ["python", "app.py"]

View File

@@ -0,0 +1,72 @@
from flask import Flask, jsonify, request
import uuid
app = Flask(__name__)
components = {
"comp-1": {
"uuid": "comp-1",
"name": "Intel Core i5",
"category": "processor",
"price": 25000
},
"comp-2": {
"uuid": "comp-2",
"name": "NVIDIA RTX 4070",
"category": "graphics_card",
"price": 60000
}
}
@app.route('/', methods=['GET'])
def get_components():
return jsonify(list(components.values()))
@app.route('/<component_id>', methods=['GET'])
def get_component(component_id):
component = components.get(component_id)
if component:
return jsonify(component)
return jsonify({"error": "Not found"}), 404
@app.route('/', methods=['POST'])
def create_component():
data = request.get_json()
component_id = str(uuid.uuid4())
component = {
'uuid': component_id,
"name": data['name'],
"category": data['category'],
"price": data['price']
}
components[component_id] = component
return jsonify(component), 201
@app.route('/<component_id>', methods=['PUT'])
def update_component(component_id):
try:
if component_id not in components:
return jsonify({"error": "Not found"}), 404
data = request.get_json()
component = components[component_id]
component['name'] = data.get('name', component['name'])
component['category'] = data.get('category', component['category'])
component['price'] = data.get('price', component['price'])
return jsonify(component)
except Exception as e:
return jsonify({"error": str(e)}), 500
@app.route('/<component_id>', methods=['DELETE'])
def delete_component(component_id):
if component_id not in components:
return jsonify({"error": "Not found"}), 404
del components[component_id]
return jsonify({"message": "Component deleted"}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001, debug=True)

View File

@@ -0,0 +1,2 @@
flask==2.3.3
requests==2.31.0

View File

@@ -0,0 +1,33 @@
events {
worker_connections 1024;
}
http {
upstream components_service {
server microservice_components:5001;
}
upstream builds_service {
server microservice_builds:5002;
}
server {
listen 80;
location /components/ {
proxy_pass http://components_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /builds/ {
proxy_pass http://builds_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}