Последнее обновление: 16 November, 2022
Сначала я хотел написать, как развернуть FastAPI приложение с использованием Fargate, но на Fargate нету free tier, поэтому я решил использовать бесплатность Amazon Lambda 😊
Для примера я взял вот это приложение, сделанное на FastAPI фреймворке: https://github.com/nsidnev/fastapi-realworld-example-app.
Для того, чтобы начать работать с aws, я скачал и установил себе aws-cli
. Это приложение для коммандной строки, которое будет помогать нам работать с сервисами амазона.
Для разработки я создал себе отдельного пользователя в учетной записи Amazon. Я всячески отговариваю вас разрабатывать из-под root юзера. После этого мы должны настроить наше приложение Амазона в терминале.
aws configure
Если у вас уже есть пользователь – например, вы залогинены с рабочей учетной записи – то вам нужно сделать новый профиль, используя свой личный аккаунт. Между профилями можно переключаться вот так.
aws configure --profile my_personal_profile
Потом я установил себе aws sam cli
. AWS SAM – это фреймворк от Амазона для разворачивания бессерверных приложений. Его можно скачать из открытых репозиториев, с помощью Homebrew или на сайте Amazon.
Так как приложение использует пакетный менеджер poetry, то я использовал следующие две команды, чтобы установить локально необходимые зависимости. Первая – говорит poetry о том, что папку с зависимостями нужно расположить в папке с проектом, а вторая, что нужно их установить.
poetry config virtualenvs.in-project true && poetry install
Если мы посмотрим в проект, который мы склонили, то можно будет увидеть, что там используется постгрес и есть env.example
файл. Этот файл мы копируем и переименовываем в .env
. А базу мы попробуем использовать другую так, как мы не планируем разворачивать свой постгрес в Амазоне.
На первый взгляд из того, что нам предлагает Амазон, мы можем взять попробовать Amazon RDS. Я сделал там маленький тестовый postgres с базовыми настройками и паролем, который сгенерировал Амазон. Это все я добавляю в свой .env
.
SECRET_KEY=secret
DEBUG=True
DATABASE_URL=postgresql://<master user name>:<master password>@<your host>:<your port, usually 5432>/<your db name>
Можно username и password разнести на две отдельные переменные и с помощью них собирать connection string для базы данных. Уверен, с этим вы справитесь без моей помощи.
Для того, чтобы сделать базу, вы сможете подключиться локально с помощью psql и сделать ее. База с именем postgres
уже есть в нашем маленьком RDS постгресе.
Для того, чтобы смочь достучаться до этого экземпляра постгреса, мне нужно сделать новую Security Group, где я разрешу трафик, исходящий с моего IP адреса.
Это можно сделать в настройках VPC - virtual private cloud – моей приватной сети.
Чтобы посмотреть на наш свежесозданный постгрес можно использовать команду:
aws rds describe-db-engine-versions ––default-only ––engine postgres
Внимательно: при создании инстанса постгреса убедитесь, что вы выбрали его настройки доступа Publicly accessible.
Чтобы протестировать подключение локально, я использовал команду psql
psql \
--host=<my amazon host> \
--port=5432 \
--username=postgres \
--password
После этого я ввел пароль и меня подключило.
В приложении, которое мы скопировали, нам нужно сделать дополнительно еще файл prod.env
, куда мы скопируем содержимое .env
пока что.
Чтобы подключить приложение к базе, надо вписать connection string
в оба эти файла. После этого исполняем команды
poetry run alembic upgrade head
poetry run uvicorn app.main:app --reload
Если перейти по адресу http://127.0.0.1:8000/docs
, то мы увидим, что приложение успешно подключилось локально к постгресу с Амазона и документация сгенерирована.
Так же мы можем смело удалить docker-compose.yml
файл из нашего тестового приложения, он нам здесь не понадобится.
Для того, чтобы развернуть ASGI на AWS Lambda & API Gateway мы используем адаптер, который называется mangum
. Мы завернем в него наше приложение, вот так
# app/main.py
from mangum import Mangum
...
app = get_application()
handler = Mangum(app)
Для того, чтобы развернуть наш проект, нам нужно его сбилдить в ZIP файл и положить в S3 бакет.
У меня уже есть бакет под эти дела, поэтому я не буду делать новый. Вы можете сделать себе бакет с помощью команды
aws s3api create-bucket \
--bucket <your bucket name> \
--region eu-west-1 \
--create-bucket-configuration LocationConstraint=eu-west-1
Только установите другой регион, тот, который вам нравится больше.
Для того, чтобы запустить билд проекта локально, вам нужно будет заставить poetry сгенерировать стандартный requirements.txt
файл так, как poetry.lock
файлы не считываются sam aws cli
.
poetry export -f requirements.txt --without-hashes > requirements.txt
После этого я запускаю команду sam build
. Эта команда сбилдид мой проект в ZIP архив, который будет потом загружен в S3 бакет и использован для разворачивания лямбды.
Для того, чтобы запустить деплой, нам нужно сделать файл template.yaml
, в котором мы опишем ресурсы необходимые нам для деплоя.
Я не могу сказать, что я отлично разобрался в том, как писать эти темплэйты, но для образца прикладываю мой файл. Он простой, но работает.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
FastAPI aws lambda example
Resources:
FastapiExampleLambda:
Type: AWS::Serverless::Function
Properties:
Events:
ApiEvent:
Properties:
RestApiId:
Ref: FastapiExampleGateway
Path: /{proxy+}
Method: ANY
Type: Api
FunctionName: FastAPI-lambda-example
CodeUri: ./
Handler: app.main.handler
Runtime: python3.9
Timeout: 300 # timeout of your lambda function
MemorySize: 128 # memory size of your lambda function
Description: FastAPI aws lambda example
# other options, see ->
# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html#sam-specification-template-anatomy-globals-supported-resources-and-properties
FastapiExampleGateway:
Type: AWS::Serverless::Api
Properties:
StageName: dev
OpenApiVersion: '3.0.0'
После этого надо запустить sam deploy --guided
.
В процессе вы выбираете варианты в консоли, которые считаете подходящими для себя. В итоге сгенерируется новый файл samconfig.toml
.
У меня он выглядит так
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "sample-fast-api-app"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-mpkd10372eoi"
s3_prefix = "sample-fast-api-app"
region = "us-west-2"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
Если все произошло хорошо, то в вашей консоли начнут отображаться ресурсы, которые создаются для вас, и их статус.
Каждый раз, когда вы будете менять манифест файт template.yaml
или что-то другое в проекте, вам понадобится команда sam build
. sam build
можно запускать с докером, используя аргумент --use-container
. Используя его на маке, я столкнулся с тем, что билд зависает на половине пути, поэтому я не использую этот флаг.
Для тестирования локально я рекомендую использовать sam local start-api
. Эта команда запускает имитатор Amazon API Gateway и вашего приложения в лямбда функции. Имитатор сделан отлично. Это совсем не то, с чем я столкнулся, работая с Google Cloud Functions.
Если у вас произошло все корректно, то в интерфейсе лямбды в вашем Амазон дашборде, вы сможете найти хост и по адресу <host name>/dev/docs
достучаться до вашего приложения.
Но, скорее всего, у вас это не получится так, как вас выбросит по таймауту. Если вы заставите отработать тот же эндпоинт локально, то у вас, как и у меня, скорее всего, отобразится, что он отрабатывает более 10000ms.
Судя по всему, лямбды не предназначены для таких проектов, как этот. Каждый раз, когда лямбда запускается, она с нуля поднимает проект, коннектится к базе, активирует необходимый эндпоинт, потом дисконнектится от базы и делает graceful shutdown.
О том, как оптимизировать проект под запуск на лямбде, я поисследую в своем следующем посте.
Трой Кёлер - программист, живущий в Берлине, Германия. У него более 6 лет опыта работы в IT. Ранее он работал в одном из крупнейших интернет-магазинов Украины, а сейчас работает в Zalando. Он специализируется на языке программирования Rust, сложных бекенд системах, разработке продуктов и инженерных платформах.