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

Создание и развертывание приложения FASTAPI в Okteto Cloud

В этой статье мы объясняем процесс создания и развертывания приложений FASTAPI в Октето. Tagged с Python, Fastapi, Cloud, Kubernetes.

В этом уроке вы узнаете, как разрабатывать API CRUD с FASTAPI и развернуть приложение к Okteto Cloud Анкет

Вы начнете с создания кода приложения, затем мы определим приложение со стеком Okteto, и, наконец, вы развернете его в Okteto Cloud.

Что такое Fastapi

Fastapi – это современная веб -структура Python, предназначенная для построения быстрых и эффективных бэкэнд. Он поставляется со встроенной поддержкой проверки данных, аутентификации и интерактивной документации API, основанной на OpenAPI и Swagger.

Что такое Okteto?

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

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

Начните с создания новой папки, чтобы держать свой проект под названием «Fastapi-Crud»:

$ mkdir fastapi-crud
$ cd fastapi-crud

Затем создайте и активируйте виртуальную среду в папке проекта:

$ python3.9 -m venv venv
$ source venv/bin/activate
$ export PYTHONPATH=$PWD

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

Далее создайте следующие файлы и папку:

├── app
│       ├── __init__.py
│       ├── model.py
│       ├── api.py
├──main.py
└── requirements.txt

В вашем Требования.txt Файл, добавьте следующие зависимости:

fastapi==0.62.0
uvicorn==0.13.1

Первая зависимость, FASTAPI, это структура, на которой будет построено ваше приложение. Вторая зависимость, Uivorn , является асинхронным интерфейсом сервера шлюза (ASGI), который позволяет нам запустить наше приложение FastAPI.

Установите зависимости:

(venv)$ pip install -r requirements.txt

С завершением установки определите базовый маршрут в app/api.py :

from fastapi import FastAPI

app = FastAPI()

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

Вы начали с импорта класса Fastapi из FASTAPI Пакет в блоке кода выше. Затем вы создали экземпляр класса в переменной приложение Анкет

Далее вы определили ПОЛУЧИТЬ маршрут на “/” который обрабатывается get_root () функция

В main.py Файл, определите точку входа для запуска приложения:

import uvicorn

if __name__ == "__main__":
    uvicorn.run("app.api:app", host="0.0.0.0", port=8080, reload=True)

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

В этом приложении расположение экземпляра Fastapi, app () находится в файле app/api.py Анкет Значение хоста может быть установлено на действительный IP -адрес в рамках настроенной области локальной машины, его также можно оставить пустым. Аналогично значение порта и перезагрузки. Порт 8080 Выбирается, поскольку приложения Okteto работают по порту 8080 по умолчанию, значение перезагрузки установлено в True, чтобы избежать перезапуска приложения при каждом внесении изменения.

Далее, запустите приложение:

$ python main.py

Вы должны получить такой ответ:

INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
INFO:     Started reloader process [24513] using statreload
INFO:     Started server process [24515]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Перейдите к http://localhost: 8080 в вашем браузере. Тебе следует увидеть:

{
    "message": "Welcome to the okteto's app."
}

Маршруты

Вы будете создавать приложение рецепта, где вы можете хранить, удалять, обновлять и удалять рецепты, отправив HTTP -запросы.

Прежде чем начать писать маршруты, определите схему модели для приложения:

В app/model.py Напишите следующее:

from pydantic import BaseModel, Field
from typing import Optional, List


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

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


class UpdateRecipeSchema(BaseModel):
    name: Optional[str]
    ingredients: Optional[List[str]]

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


В блоке кода, выше, вы определили, как будет представлен рецепт, отправлен и получен в базу данных в приложении. В реалистичном сценарии вы должны использовать отдельную базу данных, такую как MySQL, Postgres или MongoDB.

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

Рецептхема имеет подкласс Конфигурация . Подкласс содержит переменную объекта, schema_extra , который включает в себя ключ Пример используется в качестве макетных данных в интерактивной документации.

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

С моделью, давайте напишем код для маршрутов приложения. В app/api.py , добавьте базу данных рецептов перед базовым маршрутом “/” :

recipes = [
    {
        "id": 1,
        "name": "Donuts",
        "ingredients": ["Flour", "Milk", "Sugar", "Vegetable Oil"]
    }
]

Под базовым маршрутом добавьте маршруты Get:

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

@app.get("/recipe/{id}", tags=["Recipe"])
def get_recipe(id: int) -> dict:
    if id > len(recipes) or id < 1:
        return {
            "error": "Invalid ID passed."
        }

    for recipe in recipes:
        if recipe['id'] == id:
            return {
                "data": [
                    recipe
                ]
            }

    return {
        "error": "No such recipe with ID {} exist".format(id)
    }

Вы определили, получите маршруты для получения всех рецептов и одного рецепта, используя свой идентификатор в блоке кода выше. Сообщение об ошибке возвращается, если неверный идентификатор передается как параметр в /рецепт/{id} маршрут. Проверьте маршруты, посетив http://localhost: 8080/рецепт:

И http://localhost: 8080/рецепт/1:

Определите маршрут Post для добавления новых рецептов. Начните с обновления импорта:

from fastapi import FastAPI, Body

from app.model import RecipeSchema, UpdateRecipeSchema
from fastapi.encoders import jsonable_encoder

Далее добавьте маршрут Post под маршрутами Get:

@app.post("/recipe", tags=["Recipe"])
def add_recipe(recipe: RecipeSchema = Body(...)) -> dict:
    recipe.id = len(recipes) + 1
    recipes.append(recipe.dict())
    return {
        "message": "Recipe added successfully."
    }

В приведенном выше блоке кода мы убедились, что тело запроса моделируется в нашем Рецептхема установив тип Рецепт к Рецептхема в add_recipe функция Тело(...) Импортирован из Fastapi гарантирует, что тело запроса будет передано. В случае, когда содержимое запроса не соответствует указанному типу схемы, сообщение об ошибке, созданное автоматически из Pydantic, будет сгенерировано и затем возвращено.

В add_recipe Функция, идентификатор рецепта вычисляется путем увеличения длины базы данных рецептов на 1. Протестируйте маршрут Post, используя Curl:

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

Вы получите ответ:

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

Чтобы убедиться, что рецепт был добавлен, извлеките все рецепты:

$ curl -X GET http://localhost:8080/recipe/2 -H 'Content-Type: application/json'

Вы получите этот ответ:

{
    "data": [
                {"id":1,"name":"Donuts","ingredients":["Flour","Milk","Sugar","Vegetable Oil"]},
                {"id":2,"name":"Donut","ingredients":["Flour","Milk","Butter"]},
            ]
}

Вы также можете получить рецепт из его идентификатора:

$ curl -X GET http://localhost:8080/recipe/2 -H 'Content-Type: application/json'

Вы получите ответ:

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

С помощью маршрута POST определите маршрут обновления:

@app.put("/recipe", tags=["Recipe"])
def update_recipe(id: int, recipe_data: UpdateRecipeSchema) -> dict:
    stored_recipe = {}
    for recipe in recipes:
        if recipe["id"] == id:
            stored_recipe = recipe

    if not stored_recipe:
        return {
                "error": "No such recipe exists."
            }

    stored_recipe_model = RecipeSchema(**stored_recipe)
    update_recipe = recipe_data.dict(exclude_unset=True)
    updated_recipe = stored_recipe_model.copy(update=update_recipe)
    recipes[recipes.index(stored_recipe_model)] = jsonable_encoder(updated_recipe)

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

В приведенном выше блоке кода вы найдете рецепт по предоставленному идентификатору и выполняете частичное или полное обновление в зависимости от содержания принятого тела запроса. Если такой идентификатор не существует, он возвращает сообщение об ошибке.

Проверьте маршрут обновления, изменив заголовок первого рецепта на Булочки Используя Curl:

$ curl -X PUT "http://0.0.0.0:8080/recipe?id=1" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{  \"name\": \"Buns\",}"

Запрос на обновление возвращает этот ответ:

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

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

@app.delete("/recipe/{id}", tags=["Recipe"])
def delete_recipe(id: int) -> dict:
    if id > len(recipes) or id < 1:
        return {
            "error": "Invalid ID passed"
        }

    for recipe in recipes:
        if recipe['id'] == id:
            recipes.remove(recipe)
            return {
                "message": "Recipe deleted successfully."
            }

    return {
        "error": "No such recipe with ID {} exist".format(id)
    }

В блоке кода вы сначала проверяете, существует ли рецепт, идентификатор которого пройден. Если это так, рецепт удаляется. В противном случае возвращается сообщение об ошибке. Проверьте маршрут удаления:

$ curl -X DELETE "http://0.0.0.0:8080/recipe/1" -H  "accept: application/json"

Приведенный выше запрос вернет этот ответ:

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

Вы успешно создали приложение CRUD.

Развертывание в Okteto Cloud

В этом разделе вы будете развертывать приложение в Okteto Cloud.

Почему развертывание?

Когда вы разрабатываете локально, ваше приложение недоступно другими людьми, поскольку оно работает только на локальном доме вашей машины. Развертывание его в облачном сервисе, как Okteto, позволяет вам и вашим сотрудникам получить к нему доступ через свой уникальный адрес URL -адреса, как и ваши клиенты. Кроме того, любое приложение, развернутое в Okteto Cloud, автоматически получает бесплатную конечную точку HTTPS.

Создайте бесплатную учетную запись разработчика на Okteto Если у вас нет одной настройки. Кроме того, Установите okteto cli на вашей машине.

Прежде чем продолжить, создайте .gitignore Файл в папке проекта, чтобы предотвратить проверку в папке “venv” в git:

$ touch .gitignore

Добавьте следующее:

venv
__pycache__

Затем войдите в свою учетную запись Docker Hub из консоли:

$ docker login

Если у вас нет учетной записи Docker Hub, посетите Веб -сайт Dockerhub создать один. Учетная запись Docker Hub необходима для хранения изображений, созданных при запуске команды Deploy.

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

$ okteto login

Следующим шагом является создание файла манифеста стека для Okteto. Манифестный файл устраняет необходимость справляться со сложностями Kubernetes.

$ touch okteto-stack.yaml

В okteto-stack.yaml Файл, определите приложение, используя формат, который очень похож на Docker-Compose:

name: fastapi-crud
services:
  fastapi:
    public: true
    image: DOCKERHUBUSERNAME/fastapi-crud:latest
    build: .
    replicas: 1
    ports:
      - 8080
    resources:
      cpu: 100m
      memory: 128Mi

В приведенном выше файле Manifest вы определили имя вашего приложения и услуги, из которых представлено ваше приложение, FastApi. Служба FASTAPI раскрывает ваше приложение через порт 8080 в общедоступную конечную точку HTTPS с действительным сертификатом. Служба также выделяется 100 процессорами MILI и 128mi памяти. Заменить Dockerhubusername В приведенном выше файле с вашим именем пользователя Docker Hub.

Вы можете узнать больше о манифестном формате стеков Okteto.

С манифестом на месте создайте Dockerfile, чтобы разместить инструкцию по сборке для приложения. DockerFile содержит инструкции по сборке для развертывания изображений на Okteto.

$ touch Dockerfile

Добавьте следующее:

FROM python:3.8
ADD requirements.txt /requirements.txt
ADD main.py /main.py
ADD okteto-stack.yaml /okteto-stack.yaml
RUN pip install -r requirements.txt
EXPOSE 8080
COPY ./app app
CMD ["python3", "main.py"]

Давайте развернем ваше приложение в Okteto. Начните с запуска команды:

$ okteto namespace

Команда выше устанавливает пространство имен в облаке Okteto. Далее запустите команду для развертывания приложения:

$ okteto stack deploy --build

Команда выше строит услугу, которую вы указали в okteto-stack.yml Файл, а затем развертывает приложение. Эта команда облегчает напряжение необходимости создавать, а затем вручную настройку приложения после развертывания.

Приведенная выше команда запускает приложение. Перейдите к панели панели и нажмите на ссылку под заголовком «Конечные точки»:

Продолжайте и протестируйте конечные точки.

Вывод

В этой статье вы создали приложение Crud рецепта и развернули его в Okteto.

Вы стали свидетелями простоты и простоты развертывания заявки с использованием Okteto и насколько быстро и просто создавать приложения FastAPI.

Приложение также может быть развернуто непосредственно в Okteto из репозитория GitHub, следуя этому пошаговому руководству.

Код, используемый в этой статье, можно найти в GitHub Анкет

Оригинал: “https://dev.to/okteto/building-and-deploying-a-fastapi-application-in-okteto-cloud-15d5”