Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする
FastAPI で書いた API バックエンドをコンテナ化し、Lambda Web Adapter と AWS CDK を使って単一の Lambda 関数へデプロイします。
API Gateway と複数の Lambda 関数を組み合わせる構成では、API が増えるにつれて管理が複雑になることがあります。Lambda Web Adapter を使うと、FastAPI で書いた API バックエンドをコンテナ化し、Lambda へデプロイできます。
Lambda Web Adapter を使えば、API Gateway のプロキシルートと 1 つの Lambda 関数でアプリケーションを構成できます。
はじめに
AWS CDK 環境のブートストラップ
AWS CDK 環境をまだブートストラップしていない場合は、次のコマンドで CDK をローカルにインストールし、環境をブートストラップします。すでに実行済みであれば、この手順は不要です。
npm i -D aws-cdknpx cdk bootstrap aws://<AWS_ACCOUNT_ID>/<AWS_REGION>CDK プロジェクトの初期化
CDK プロジェクト用のディレクトリを作成し、初期化します。
mkdir cdk && cd cdknpx cdk init app --language typescriptFastAPI のインストール
python -m venv .venvsource .venv/bin/activatepip install "fastapi[standard]"mkdir srcpip freeze > ./src/requirements.txtバックエンドの構築
API の定義
FastAPI アプリケーションの例は次のとおりです。
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")def read_root(): return {"Hello": "World"}
@app.get("/items/{item_id}")def read_item(item_id: int, q: Union[str, None] = None): return {"item_id": item_id, "q": q}FastAPI サーバーを起動します。
fastapi dev ./src/main.py任意のツールで API をテストします。
curl "http://127.0.0.1:8000/"{"Hello":"World"}
curl "http://127.0.0.1:8000/items/1?q=keyword"{"item_id":1,"q":"keyword"}コンテナ化
FastAPI バックエンドをコンテナ化するため、./docker/Dockerfile を作成します。この Dockerfile には、開発用と本番用のステージを定義します。
- ベースイメージ:
public.ecr.aws/docker/library/python:3.12-alpineを使用します(2 行目)。 - Lambda Web Adapter: AWS Lambda と連携するため、Lambda Web Adapter を追加します(22 行目)。
- ポート設定: Lambda Web Adapter のデフォルト設定に合わせ、本番環境ではバックエンドがポート 8080 で待ち受けます(25 行目)。
Lambda Web Adapter の使い方については、GitHub リポジトリ を参照してください。
# Base image: Python 3.12 AlpineFROM public.ecr.aws/docker/library/python:3.12-alpine AS baseENV APP_ROOT=/code
# Copy requirements and install dependenciesCOPY ./src/requirements.txt $APP_ROOT/RUN pip install --no-cache-dir --upgrade -r $APP_ROOT/requirements.txt
# Development stageFROM base AS devENV ENV=devEXPOSE 8000CMD ["sh", "-c", "fastapi run $APP_ROOT/main.py --port 8000"]
# Production stageFROM baseENV ENV=prodEXPOSE 8080COPY ./src $APP_ROOT
# Copy Lambda Web AdapterCOPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
# Run FastAPI backend on port 8080 for Lambda Web AdapterCMD ["sh", "-c", "fastapi run $APP_ROOT/main.py --port 8080"](オプション)Docker Compose
この記事ではデータベースを扱いませんが、実際のアプリケーションでは DynamoDB や MySQL などを利用することがあります。ローカルでの開発やテストには Docker Compose を利用できます。
- ビルドコンテキスト: プロジェクトルート(
../)を指します(4行目)。 - ビルドターゲット: Dockerfile の開発ステージ(
target: dev)を使用します(6 行目)。 - ポートマッピング: コンテナのポート
8000をホストのポート8000へ割り当てます(8 行目)。 - ボリューム: ローカルの
srcディレクトリをコンテナの/codeディレクトリへマウントし、開発中の変更をコンテナへ反映します(10 行目)。
services: api: build: context: ../ dockerfile: ./docker/Dockerfile target: dev ports: - "8000:8000" volumes: - ../src:/codeDocker Compose を使ってバックエンドサービスをローカルで起動するには、次のコマンドを実行します。
cd dockerdocker compose upサービスが正常に起動すると、次のようなログが表示されます。
api-1 | INFO: Started server process [1]api-1 | INFO: Waiting for application startup.api-1 | INFO: Application startup complete.api-1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)これで http://127.0.0.1:8000 から API にアクセスし、curl、Postman、ブラウザなどでテストできます。
AWS へのデプロイ
AWS リソースの定義
AWS CDK を使って、FastAPI バックエンドのデプロイに必要なリソースを定義します。
#!/usr/bin/env nodeimport 'source-map-support/register';import * as cdk from 'aws-cdk-lib';import { CdkStack } from '../lib/cdk-stack';
const app = new cdk.App();new CdkStack(app, 'App');- メモリサイズ: この例では 512 MB を割り当てます(20 行目)。Lambda ではメモリ量に応じて CPU も割り当てられるため、起動時間と処理内容を計測して調整してください。
- プラットフォーム設定:
Platform.LINUX_AMD64(23 行目)を指定し、Apple Silicon 上でビルドする場合も、コンテナイメージを Lambda 関数のデフォルトアーキテクチャであるx86_64に合わせます。アーキテクチャが一致しないと、Error: fork/exec /opt/extensions/lambda-adapter: exec format error Extension.LaunchErrorが発生する可能性があります。
import * as cdk from 'aws-cdk-lib';import type { Construct } from 'constructs';import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';import { DockerImageCode, DockerImageFunction, LoggingFormat,} from 'aws-cdk-lib/aws-lambda';import * as path from 'node:path';import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
export class CdkStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props);
// Dockerized Lambda Function const lambda = new DockerImageFunction(this, 'function', { functionName: 'fast-api-app-function', loggingFormat: LoggingFormat.JSON, memorySize: 512, // Tune after measuring the workload code: DockerImageCode.fromImageAsset(path.join(__dirname, '..', '..'), { file: path.join('docker', 'Dockerfile'), platform: Platform.LINUX_AMD64, // Match Lambda's default x86_64 architecture exclude: ['*', '!src', '!docker'], }), });
// API Gateway REST API new LambdaRestApi(this, 'api', { handler: lambda, deploy: true, }); }}スタックのデプロイ
CDK プロジェクトのディレクトリに移動し、次のコマンドでデプロイします。
cd cdknpx cdk deployデプロイ中にリソース作成の確認を求められた場合は、y と入力して続行します。
Do you wish to deploy these changes (y/n)? yApp: deploying... [1/1]App: creating CloudFormation changeset...
✅ App
✨ Deployment time: 52.67s
Outputs:App.apiEndpoint9349E63C = https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/Stack ARN:arn:aws:cloudformation:<AWS_REGION>:<AWS_ACCOUNT_ID>:stack/App/<UUID>
✨ Total time: 55.42sデプロイが完了すると、API Gateway のエンドポイントが出力されます。この URL を使って API をテストできます。
API のテスト
デプロイした API をテストします。
curl "https://<API_GATEWAY_ENDPOINT>/prod/"{"Hello":"World"}
curl "https://<API_GATEWAY_ENDPOINT>/prod/items/1?q=keyword"{"item_id":1,"q":"keyword"}まとめ
Lambda Web Adapter で FastAPI アプリケーションをコンテナ化し、CDK でデプロイすることで、API 全体を 1 つの Lambda 関数と API Gateway のプロキシルートで提供できました。
Lambda Web Adapter を使うと、複数の Lambda 関数と API Gateway のルートマッピングを、FastAPI 自身のルーティングに置き換えられます。アプリケーション全体を 1 つのコンテナとしてプロキシルートの背後に配置するため、エンドポイントの追加は主にアプリケーションコードの変更で対応できます。
CDK の 2 つの設定は、普遍的な必須値ではなく、明示的に選択する項目です。512 MB のメモリは計測を始めるための初期値です。Platform.LINUX_AMD64 は、Apple Silicon 上でビルドしたイメージも Lambda 関数のデフォルトである x86_64 に合わせます。2024 年当時の Lambda Web Adapter は arm64 イメージにも対応していたため、コンテナイメージと Lambda 関数の両方を arm64 に設定する構成も可能です。
Related posts
Cognito User Pools と OIDC で Slack サインインを実装する
Cognito user pool を OIDC 経由で Slack と連携させ、"Sign in with Slack" を Amplify で Next.js アプリケーションに組み込みます。

AWS Amplify と Eclipse Mosquitto を連携した MQTT メッセージング
AWS Amplify の PubSub モジュールを AWS IoT Core に接続する前に、ローカルの Eclipse Mosquitto ブローカーでテストする方法を紹介します。
API Gateway WebSocket:モック統合の実装
バックエンドの Lambda を使わず、モック統合のみで API Gateway WebSocket API を構築し、あらかじめ用意したレスポンスを返します。
CloudFront 署名付き URL 経由で S3 にアップロードする
CloudFront の署名付き URL を使い、独自ドメイン経由で S3 にアップロードする方法を紹介します。S3 の署名付き URL を直接使えない場合に有用です。
AWS EventBridge Scheduler:スケジュールに沿って EC2 を起動・停止する
Lambda を介さず、EventBridge Scheduler から EC2 API を直接呼び出し、cron スケジュールに従って EC2 インスタンスを起動・停止します。
