Рубрики
Без рубрики

Добавление базы данных в ваше приложение с помощью Okteto Стеки

В этой статье мы объясняем процесс добавления базы данных в ваше приложение с помощью стеков Okteto. Tagged с Python, Mongodb, Kubernetes, Fastapi.

Временные базы данных в приложении не идеальны для веб-приложений. Любое неудачное событие, такое как резкое отключение или перезапуск приложения, приведет к общей потере сохраненных данных.

Это третий пост в нашей серии о том, как разработать приложение Fastapi с Okteto. В предыдущих постах вы узнали, как развертывать приложения непосредственно из вашей консоли, используя стеки Okteto и как развернуть их непосредственно из пользовательского интерфейса Okteto.

В этом уроке вы будете добавлять базу данных для лучшего хранения данных о вашем приложении, а затем вы развернете обновленную версию в свое пространство имен Okteto непосредственно из вашей командной строки.

Начальная настройка

Начните с создания Вилка приложения от GitHub а затем клонировать его на местном уровне.

git clone https://github.com/okteto/fastapi-crud

В вашем локальном клоне установите его, используя следующие команды:

$ cd fastapi-crud
$ python3 -m venv venv && source venv/bin/activate
(venv)$ pip install -r requirements.txt

Убедитесь, что настройка завершена путем запуска:

python3 main.py

После проверки установки обновите Dockerhubusername переменная в вашем файле стека в okteto.dev Анкет Развернуть приложение с помощью команды:

(venv)$ okteto stack deploy --build

Создание нового филиала

Для этой статьи мы создадим новую филиал. Это позволяет вам дифференцировать первый пост в серии от этого.

Из вашей консоли запустите команду:

git checkout -b mongo-crud

Команда выше создает новую филиал Монго-крик С происхождением, указывающим на Главный Анкет

Добавление базы данных

Прежде чем продолжить, убедитесь, что у вас установлен MongoDB или перейдите к Страница установки Mongodb Чтобы установить MongoDB.

Чтобы избежать потери данных, вы собираетесь переписать логику приложения, чтобы использовать базу данных MongoDB. Позже в посте вы развернете базу данных в вашем пространстве имен Okteto, но сначала давайте запустим ее локально, чтобы убедиться, что код работает отлично.

Начните с установки Pimongo , драйвер MongoDB для приложения Python, Python-Decouple Для чтения секретов среды и обновить Требования.txt файл:

(venv)$ pip install pymongo

Обновите свой Требования.txt файл:

...
pymongo
python-decouple

В API Папка, создайте новый файл, Database.py , где вы напишите функции базы данных CRUD.

Начните с импорта МОГОКЛИЕНТ , ObjectId и конфигурация :

from pymongo import MongoClient
from bson import ObjectId
from decouple import config

Mongoclient отвечает за соединение из нашего приложения к базе данных, ObjectId, с другой стороны, используется для передачи id Значения в MongoDB должным образом и конфигурация отвечает за чтение секретов приложения от .env файлы

Далее определите сведения об соединении, базе данных и базе данных:

connection_details = config("DB_HOST")

client = MongoClient(connection_details)

database = client.recipes

recipe_collection = database.get_collection('recipes_collection')

На первой строке выше вы используете Декупль Библиотека для чтения переменной среды Db_host . Создать .env Файл в корневой папке, содержащей деталь подключения:

DB_HOST=mongodb://localhost:27017

Документы в MongoDB хранятся в формате JSON и _id в ObjectId формат. Напишите функцию, чтобы анализировать результат по запросу:

def parse_recipe_data(recipe) -> dict:
    return {
        "id": str(recipe["_id"]),
        "name": recipe["name"],
        "ingredients": recipe["ingredients"]
    }

CRUD функции

Следующим шагом является написание функций, ответственных за сохранение, удаление, обновление и удаление рецептов. Начните с реализации save_recipe :

def save_recipe(recipe_data: dict) -> dict:
    recipe = recipe_collection.insert_one(recipe_data).inserted_id
    return {
        "id": str(recipe)
    }

Приведенная выше функция вставляет данные рецепта в базу данных и возвращает недавно созданный идентификатор рецепта.

Далее функция получения одного рецепта и всех рецептов из базы данных:

def get_single_recipe(id: str) -> dict:
    recipe = recipe_collection.find_one({"_id": ObjectId(id)})
    if recipe:
        return parse_recipe_data(recipe)

def get_all_recipes() -> list:
    recipes = []
    for recipe in recipe_collection.find():
        recipes.append(parse_recipe_data(recipe))

    return recipes

Первая функция выше возвращает один рецепт, идентификатор которого соответствует предоставленному и сообщению об ошибке, если он не существует, в то время как вторая функция возвращает все содержащиеся рецепты в базе данных.

Далее напишите update_recipe_data Функция ответственности за обновление данных рецепта:

def update_recipe_data(id: str, data: dict):
    recipe = recipe_collection.find_one({"_id": ObjectId(id)})
    if recipe:
        recipe_collection.update_one({"_id": ObjectId(id)}, {"$set": data})
        return True

Наконец, напишите функцию для удаления рецепта:

def remove_recipe(id: str):
    recipe = recipe_collection.find_one({"_id": ObjectId(id)})
    if recipe:
        recipe_collection.delete_one({"_id": ObjectId(id)})
        return True

С помощью функций CRUD базы данных замените содержание app/api.py с:

from fastapi import FastAPI, Body
from fastapi.encoders import jsonable_encoder

from app.model import RecipeSchema, UpdateRecipeSchema
from app.database import save_recipe, get_all_recipes, get_single_recipe, update_recipe_data, remove_recipe

app = FastAPI()

@app.get("/", tags=["Root"])
def get_root() -> dict:
    return {
        "message": "Welcome to the okteto's app.",
    }

@app.get("/recipe", tags=["Recipe"])
def get_recipes() -> dict:
    recipes = get_all_recipes()
    return {
        "data": recipes
    }

@app.get("/recipe/{id}", tags=["Recipe"])
def get_recipe(id: str) -> dict:
    recipe = get_single_recipe(id)
    if recipe:
        return {
            "data": recipe
        }
    return {
        "error": "No such recipe with ID {} exist".format(id)
    }

@app.post("/recipe", tags=["Recipe"])
def add_recipe(recipe: RecipeSchema = Body(...)) -> dict:
    new_recipe = save_recipe(recipe.dict())
    return new_recipe

@app.put("/recipe", tags=["Recipe"])
def update_recipe(id: str, recipe_data: UpdateRecipeSchema)  -> dict:
    if not get_single_recipe(id):
        return {
            "error": "No such recipe exist"
        }

    update_recipe_data(id, recipe_data.dict())

    return {
        "message": "Recipe updated successfully."
    }

@app.delete("/recipe/{id}", tags=["Recipe"])
def delete_recipe(id: str) -> dict:
    if not get_single_recipe(id):
        return {
            "error": "Invalid ID passed"
        }


    remove_recipe(id)
    return {
        "message": "Recipe deleted successfully."
    }

Обновите api/model.py Удалив id Поле в Рецептхема модельный класс:

class RecipeSchema(BaseModel):
    name: str = Field(...)
    ingredients: List[str] = Field(...)

    class Config:
        schema_extra = {
            "example": {
                "name": "Donuts",
                "ingredients": ["Flour", "Milk", "Sugar", "Vegetable Oil"]
            }
        }

Тестирование базы данных

С подключением к базе данных запустите монгод сервер, чтобы разрешить взаимодействие с базой данных:

mongod --port 27017

Далее, протестируйте маршрут почты:

(venv)$ curl -X POST http://localhost:8080/recipe -d \
'{"name": "Donut", "ingredients": ["Flour", "Milk", "Butter"]}' \
-H 'Content-Type: application/json'

Ответ:

{
  "id": "601fdcd82fbbf462d33a6e34"
}

Проверьте маршруты получить:

  1. Вернуть все рецепты
(venv)$  curl -X GET http://localhost:8080/recipe/2 -H 'Content-Type: application/json'

Ответ:

{
  "data": [
    {
      "id": "601fdcd82fbbf462d33a6e34",
      "name": "Donut",
      "ingredients": [
        "Flour",
        "Milk",
        "Butter"
      ]
    }
  ]
}
  1. Вернуть один рецепт
(venv)$ curl -X GET http://localhost:8080/recipe/601fdcd82fbbf462d33a6e34 -H 'Content-Type: application/json'

Ответ:

{
  "data": {
    "id": "601fdcd82fbbf462d33a6e34",
    "name": "Donut",
    "ingredients": [
      "Flour",
      "Milk",
      "Butter"
    ]
  }
}

Проверьте маршрут обновления:

(venv)$ curl -X PUT "http://0.0.0.0:8080/recipe?id=601fdcd82fbbf462d33a6e34" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{\"name\":\"Buns\",\"ingredients\":[\"Flour\",\"Milk\",\"Sugar\",\"Vegetable Oil\"]}"

Ответ:

{
  "message": "Recipe updated successfully."
}

Наконец, проверьте маршрут удаления:

(venv)$ curl -X DELETE "http://0.0.0.0:8080/recipe/601fdcd82fbbf462d33a6e34" -H  "accept: application/json"

Ответ:

{
  "message": "Recipe deleted successfully."
}

Перераспределение в Октето

Okteto облегчает напряжение развертывания и последующего перераспределения, позволяя нам обновлять и обновлять существующие приложения из файла стека. В предыдущем посте мы создали манифест стека Okteto для развертывания нашего сервиса Fastapi. Теперь мы собираемся обновить его, также включают mongodb экземпляр как часть развертывания:

name: fastapi-crud
services:
  fastapi:
    public: true
    image: okteto.dev/fastapi-crud:latest
    build: .
    replicas: 1
    ports:
      - 8080
    resources:
      cpu: 100m
      memory: 128Mi
  mongodb:
    image: bitnami/mongodb:latest
    ports:
      - 27017
    resources:
      cpu: 100m
      memory: 128Mi
    volumes:
      - /bitnami/mongodb

В приведенном выше коде вы добавили другую службу, Mongodb , чтобы разместить контейнер MongoDB от Bitnami. Он настроен на разоблачение порта по умолчанию MongoDB 27017 выставлен. Этот контейнер будет доступен только в вашем пространстве имен, и он настроен с постоянным томом /bitnami/mongodb Чтобы гарантировать, что данные могут быть получены при перезапуске приложения.

Под FASTAPI Сервис, добавьте заголовок среды, содержащую Db_host Файл базы данных читается, используя Декупль библиотека:

environment:
  - DB_HOST=mongodb://mongodb:27017
  - secret=dev 

С обновлением файла стека, разверните его, используя команду:

(venv)$ okteto stack deploy --build

Войдите в свой Приборная панель Okteto Анкет Обратите внимание, что ваше заявление теперь включает экземпляр MongoDB вместе с вашим заявлением:

Проверьте Рецепт Маршрут, заменив DeployedApp Из предыдущих запросов с помощью URL -адреса приложения живого приложения. Из вашего терминала запустите команду:

(venv)$ curl -X POST "https://fastapi-youngestdev.cloud.okteto.net/recipe" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{\"name\":\"Donuts\",\"ingredients\":[\"Flour\",\"Milk\",\"Sugar\",\"Vegetable Oil\"]}"

Отправленный ответ:

{
  "id": "601fe6deaa1a27fbcb9a60fb"
}

Совершение изменений в git

С помощью подтвержденных и проверенных изменений совершите все изменения в применении в филиал:

git add .
git commit -m "Added MongoDB to the recipe application"

Протолкнуть совершенные изменения:

git push -u origin mongo-crud

Вывод

В этой статье вы изменили свою службу FastAPI, чтобы использовать реальную базу данных. Затем вы добавили службу базы данных в свой Октето Стек Манифест и развернул изменения с одной командой. Наконец, вы проверили изменения в конце концов, гарантируя, что они работают, как и ожидалось. Окончательная версия кода доступна На нашем репозитории GitHub Анкет

Создать Ваша бесплатная учетная запись Okteto Сегодня и начните разрабатывать новое приложение одним щелчком.

Оригинал: “https://dev.to/okteto/adding-a-database-to-your-application-using-okteto-stacks-5b79”