今回は、AWS LambdaとCloud FunctionsにFastAPIをシームレスにデプロイする方法を紹介します。
OSSの開発などでどちらでも動作する機能を同一コードで管理する時などに便利です。
作成する機能
SentryというApplication Monitoring PlatformのアラートをAWS Lambda, Cloud Functions経由でSlackに通知できる機能を作成します。
Integration機能を使用してSlackに通知する事ができますが、Free planでは直接通知する事ができないため、Webhookを使用して通知するものです。
OSSはこちらで公開しています。
使用するライブラリ
今回使用するライブラリはAgraffeというものです。
AWS LambdaやCloud Functionsで使用できるEntrypointをFastAPIのアプリケーションを使用して簡単に作成する事ができます。
開発
パッケージのインストール
poetryを使用してパッケージ管理を行います。
poetryをインストールし、初期化を行います。
pip install poetry
poetry init
初期化が完了したら、今回使用するパッケージをインストールします。
poetry add fastapi
poetry add agraffe
poetry add requests
requirements.txtの作成
パッケージのインストールが完了したら、requirements.txtを作成します。
デプロイする際に必要になるため、パッケージを追加した際はこの作業を必ず実施する必要が有ります。
poetry export -f requirements.txt > requirements.txt
コーディング
実際の処理を書いていきます。
AWS LambdaとCloud Functionsの切り替えを環境変数で行うことで、コードを変えずに処理を変更しています。
import os
from typing import Dict
from agraffe import Agraffe, Service
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/printf")
async def printf(request: Request) -> Dict[str, str]:
body = await request.json()
print(body)
return {}
platform = os.environ.get("PLATFORM", "GCP")
if platform == "GCP":
entry_point = Agraffe.entry_point(app, Service.google_cloud_functions)
elif platform == "AWS":
entry_point = Agraffe.entry_point(app, Service.aws_lambda)
else:
Exception(f"Unsupported platform of {platform}")
FastAPIのインスタンスをAgraffeに渡す事で柔軟にコード切り替えを行っています。
環境変数はデプロイ時に設定し、その値を使用して切り替えを行っています。
- クラウド環境の切り替えコード抜粋
platform = os.environ.get("PLATFORM", "GCP")
if platform == "GCP":
entry_point = Agraffe.entry_point(app, Service.google_cloud_functions)
elif platform == "AWS":
entry_point = Agraffe.entry_point(app, Service.aws_lambda)
else:
Exception(f"Unsupported platform of {platform}")
デプロイ
Cloud Functionsへのデプロイ
gcloudコマンドを使用してデプロイします。
gcloudコマンドのインストール方法はこちらを参照してください。
gcloud functions deploy sentry-alert-to-slack-with-functions \
--runtime python37 \
--trigger-http \
--entry-point entry_point \
--region {region} \
--set-env-vars SLACK_ENDPOINT={SLACK_WEBHOOK_ENDPOINT} \
--set-env-vars PLATFORM=GCP
AWS Lambdaへのデプロイ
zipにパッケージ化した後、awsコマンドを使用してデプロイします。
awsコマンドのインストール方法はこちらを参照してください。
- パッケージ化
mkdir dist \
&& cp main.py dist/ \
&& pip install -r requirements.txt -t dist/ \
&& cd dist \
&& zip -r ../dist.zip * \
&& cd ../ \
&& rm -rf dist
- デプロイ
aws lambda create-function \
--function-name sentry-alert-to-slack-with-functions \
--runtime python3.7 \
--role {LambdaExecuteRole} \
--handler entry_point \
--zip-file fileb://dist.zip \
--environment "Variables={SLACK_ENDPOINT={SLACK_WEBHOOK_ENDPOINT},PLATFORM=AWS}"
デプロイ後、Lambdaを開きAPI Gatewayの設定を行います。
AgraffeはREST APIのみ対応しているので、REST APIを選択します。
おわりに
以上でAWS LambdaとCloud Functionsを同一コードでシームレスにデプロイする事ができます。
今回は公式のデプロイツールを使用していますが、より便利なツールを使用すると保守/運用性が上がると思います。