Готовая лабораторная работа 3
This commit is contained in:
173
shanygin_alexandr_lab_3/README.md
Normal file
173
shanygin_alexandr_lab_3/README.md
Normal 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
|
||||||
26
shanygin_alexandr_lab_3/docker-compose.yml
Normal file
26
shanygin_alexandr_lab_3/docker-compose.yml
Normal 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"
|
||||||
14
shanygin_alexandr_lab_3/microservice_builds/Dockerfile
Normal file
14
shanygin_alexandr_lab_3/microservice_builds/Dockerfile
Normal 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"]
|
||||||
73
shanygin_alexandr_lab_3/microservice_builds/app.py
Normal file
73
shanygin_alexandr_lab_3/microservice_builds/app.py
Normal 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)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
flask==2.3.3
|
||||||
|
requests==2.31.0
|
||||||
12
shanygin_alexandr_lab_3/microservice_components/Dockerfile
Normal file
12
shanygin_alexandr_lab_3/microservice_components/Dockerfile
Normal 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"]
|
||||||
72
shanygin_alexandr_lab_3/microservice_components/app.py
Normal file
72
shanygin_alexandr_lab_3/microservice_components/app.py
Normal 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)
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
flask==2.3.3
|
||||||
|
requests==2.31.0
|
||||||
33
shanygin_alexandr_lab_3/nginx.conf
Normal file
33
shanygin_alexandr_lab_3/nginx.conf
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user