Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする

Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする

FastAPI で書いた API バックエンドをコンテナ化し、Lambda Web Adapter と AWS CDK を使って単一の Lambda 関数へデプロイします。

Takahiro Iwasa
8 min read

API Gateway と複数の Lambda 関数を組み合わせる構成では、API が増えるにつれて管理が複雑になることがあります。Lambda Web Adapter を使うと、FastAPI で書いた API バックエンドをコンテナ化し、Lambda へデプロイできます。

Lambda Web Adapter を使えば、API Gateway のプロキシルートと 1 つの Lambda 関数でアプリケーションを構成できます。

はじめに

AWS CDK 環境のブートストラップ

AWS CDK 環境をまだブートストラップしていない場合は、次のコマンドで CDK をローカルにインストールし、環境をブートストラップします。すでに実行済みであれば、この手順は不要です。

Terminal window
npm i -D aws-cdk
npx cdk bootstrap aws://<AWS_ACCOUNT_ID>/<AWS_REGION>

CDK プロジェクトの初期化

CDK プロジェクト用のディレクトリを作成し、初期化します。

Terminal window
mkdir cdk && cd cdk
npx cdk init app --language typescript

FastAPI のインストール

Terminal window
python -m venv .venv
source .venv/bin/activate
pip install "fastapi[standard]"
mkdir src
pip freeze > ./src/requirements.txt

バックエンドの構築

API の定義

FastAPI アプリケーションの例は次のとおりです。

src/main.py
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 サーバーを起動します。

Terminal window
fastapi dev ./src/main.py

任意のツールで API をテストします。

Terminal window
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 リポジトリ を参照してください。

docker/Dockerfile
# Base image: Python 3.12 Alpine
FROM public.ecr.aws/docker/library/python:3.12-alpine AS base
ENV APP_ROOT=/code
# Copy requirements and install dependencies
COPY ./src/requirements.txt $APP_ROOT/
RUN pip install --no-cache-dir --upgrade -r $APP_ROOT/requirements.txt
# Development stage
FROM base AS dev
ENV ENV=dev
EXPOSE 8000
CMD ["sh", "-c", "fastapi run $APP_ROOT/main.py --port 8000"]
# Production stage
FROM base
ENV ENV=prod
EXPOSE 8080
COPY ./src $APP_ROOT
# Copy Lambda Web Adapter
COPY --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 Adapter
CMD ["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 行目)。
docker/compose.yaml
services:
api:
build:
context: ../
dockerfile: ./docker/Dockerfile
target: dev
ports:
- "8000:8000"
volumes:
- ../src:/code

Docker Compose を使ってバックエンドサービスをローカルで起動するには、次のコマンドを実行します。

Terminal window
cd docker
docker 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 バックエンドのデプロイに必要なリソースを定義します。

cdk/bin/cdk.ts
#!/usr/bin/env node
import '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 が発生する可能性があります。
cdk/lib/cdk-stack.ts
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 プロジェクトのディレクトリに移動し、次のコマンドでデプロイします。

Terminal window
cd cdk
npx cdk deploy

デプロイ中にリソース作成の確認を求められた場合は、y と入力して続行します。

Do you wish to deploy these changes (y/n)? y
App: 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 をテストします。

Terminal window
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 に設定する構成も可能です。

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.