ããã¯ããªã«ããããã¦æ¸ãããã®ï¼
AWS Lambdaã§é常ã®Webã¢ããªã±ã¼ã·ã§ã³ãã¬ã¼ã ã¯ã¼ã¯ã使ããã¨ãããAWS Lambda Web Adapterã1度試ãã¦ãããããªã¨
æãã¾ãã¦ã
ä»åã¯FastAPIã§è©¦ãã¦ã¿ããã¨æãã¾ããåä½ç¢ºèªãããã®ã¯ãã¼ã«ã«ç°å¢ã§ãã
AWS Lambda Web Adapter
AWS Lambda Web Adapterã®GitHubãªãã¸ããªã¼ã¯ãã¡ãã
GitHub - awslabs/aws-lambda-web-adapter: Run web applications on AWS Lambda
AWS Lambda Web Adapterã使ãã¨ãAWS Lambda颿°ãHTTP 1.1ï¼1.0ããµãã¼ãããWebã¢ããªã±ã¼ã·ã§ã³ãã¬ã¼ã ã¯ã¼ã¯ã使ã£ã¦
éçºã§ããã¨ããã¦ãã¾ãããªã¼ãã¼ããããå°ããããã§ãã
ç¹å¾´ã¯ãã¡ãã
- AWS Lambdaã§Webã¢ããªã±ã¼ã·ã§ã³ãå®è¡ãã
- Amazon API Gatewayã®Rest APIããã³Http APIã®ã¨ã³ããã¤ã³ããLambda颿°URLãALBããµãã¼ã
- Lambdaããã¼ã¸ãã©ã³ã¿ã¤ã ãã«ã¹ã¿ã ã©ã³ã¿ã¤ã ãDocker OCIã¤ã¡ã¼ã¸ããµãã¼ã
- ä»»æã®Webãã¬ã¼ã ã¯ã¼ã¯ã¨è¨èªããµãã¼ãããã³ã¼ãã®ä¾åãæ°ãã追å ããå¿ è¦ã¯ãªã
- èªåã§ãã¤ããªã¬ã¹ãã³ã¹ã«ã¨ã³ã³ã¼ã
- Gracefulã·ã£ãããã¦ã³ã®ãµãã¼ã
- ã¬ã¹ãã³ã¹ã®ãã¤ãã¼ãå§ç¸®ããµãã¼ã
- ã¬ã¹ãã³ã¹ã®ã¹ããªã¼ãã³ã°ããµãã¼ã
- éHTTPããªã¬ã¼ã¤ãã³ãããµãã¼ã
AWS Lambda Web Adapter / Features
Lambda颿°URLã¨ããã®ã¯ãAWS Lambda颿°ã®ããã®HTTPã¨ã³ããã¤ã³ãã§ããããã¡ãã使ãã¨ãAWS Lambda颿°ãHTTPã§
ç´æ¥å¼ã³åºããã¨ãã§ãã¾ãã
Lambda 関数 URL の作成と管理 - AWS Lambda
HTTP以å¤ã®ã¤ãã³ãããµãã¼ããããã§ããã
ä½¿ãæ¹ã¯ãã¡ãã
AWS Lambda Web Adapter / Usage
ã¾ããå°å ¥æ¹æ³ã«ã¤ãã¦è¦ã¦ããã¾ãããã
Dockerã¤ã¡ã¼ã¸ãããã¯OCIã¤ã¡ã¼ã¸ã«AWS Lambda Web Adapterã追å ããæ¹æ³ã¨ãZipããã±ã¼ã¸ã®å ´åã¯Lambdaã¬ã¤ã¤ã¼ã¨ãã¦
å°å
¥ããæ¹æ³ãããããã§ãã
- AWS Lambda Web Adapter / Usage / Lambda functions packaged as Docker Images or OCI Images
- AWS Lambda Web Adapter / Usage / Lambda functions packaged as Zip package for AWS managed runtimes
èµ·åé ã¨ãã¦ã¯AWS Lambda Web Adapterãæ¡å¼µæ©è½ã¨ãã¦èµ·åããå¾ã«ãAWS Lambdaä¸ã§æ§ç¯ãããWebã¢ããªã±ã¼ã·ã§ã³ãèµ·åãã
ã¨ããæµãã«ãªãããã§ãã
èµ·åãããã©ããã¯ãã«ã¹ãã§ãã¯ã§ç¢ºèªããããã§ããï¼ç°å¢å¤æ°ã§ãã¼ãã¨ãã¹ã夿´å¯è½ï¼ã
AWS Lambda Web Adapter / Readiness Check
ããã©ã«ãã§ã¯GET /
ã«å¯¾ãã¦å¿çãããã¼ã8080ã§ãªãã¹ã³ããããã«æ§æããæ¹ãããã§ãããã
ãã®ä»ãè¨å®ã¯ç°å¢å¤æ°ã§è¡ãããã§ãã
AWS Lambda Web Adapter / Configurations
AWS Lambdaã§ã®ã³ã³ããã¹ãã«ã¤ãã¦ã
- AWS Lambda Web Adapter / Request Context
- AWS Lambda Web Adapter / Lambda Context
- AWS Lambdaã颿°ãã³ãã©ã¼ã«æ¸¡ããªãã¸ã§ã¯ã
- Using the Lambda context object to retrieve Python function information - AWS Lambda
- AWS Lambda Web Adapterã§ã¯ããã®æ
å ±ã
x-amzn-lambda-context
ã¨ããHTTPãããã¼ã§Webã¢ããªã±ã¼ã·ã§ã³ã«éä¿¡ãã
ã·ã£ãããã¦ã³æã«ã¯SIGTERM
ã·ã°ãã«ãéä¿¡ããããããªã®ã§ãWebã¢ããªã±ã¼ã·ã§ã³å´ã§ã·ã°ãã«ããã³ããªã³ã°ãããã¨ã§å®å
¨ã«
ã·ã£ãããã¦ã³ãã§ããã¨ããã¦ãã¾ãã
AWS Lambda Web Adapter / Graceful Shutdown
ãã¼ã«ã«ã§ã®å®è¡ã¯ãAWS SAMã®å©ç¨ãæãããã¦ãã¾ããã
AWS Lambda Web Adapter / Local Debugging
éHTTPã¤ãã³ãï¼Amazon SQSãAmazon SNSãAmazon DynamoDBãAmazon KinesisãAmazon Managed Streaming for Apache Kafkaã
Amazon EventBridgeãAmazon Bedrock Agentãªã©ï¼ããµãã¼ããã¦ãããã¨ã¯ããã¡ãã«æ¸ããã¦ãã¾ãã
AWS Lambda Web Adapter / Non-HTTP Event Triggers
ãã¹/events
ã«å¯¾ãã¦ãHTTP POSTã§ãªã¯ã¨ã¹ãã転éããããã§ããã¤ãã³ãã®å
容ã¯HTTPããã£ã¨ãã¦éãããã¬ã¹ãã³ã¹ã¯JSONã¨
ãããã¨ã«ãªãããã§ãã
ãã¨ã¯åè¨èªããã¬ã¼ã ã¯ã¼ã¯åãã®ãµã³ãã«ãããã¾ãã
AWS Lambda Web Adapter / Examples
ä»å使ãããFastAPIã¯ãã¡ãã§ããã
https://github.com/awslabs/aws-lambda-web-adapter/tree/v0.8.4/examples/fastapi
ã¡ãªã¿ã«ãAWS Lambda Web Adapterèªä½ã¯Rustã§æ¸ããã¦ããããã§ãã
https://github.com/awslabs/aws-lambda-web-adapter/tree/v0.8.4/src
確ãã«å®è£ å 容ã¨ãã¦ã¯ãHTTP 1.1ï¼1.0åãã®Webã¢ããªã±ã¼ã·ã§ã³ã§ããã°ãªãã§ãåãããã§ããã
åèï¼
AWS Lambda Web Adapterを活用する新しいサーバーレスの実装パターン - Speaker Deck
Lambda Web Adapter でウェブアプリを (ほぼ) そのままサーバーレス化する Lambda Web Adapter - 変化を求めるデベロッパーを応援するウェブマガジン | AWS
ã§ã¯ãä»åã¯FastAPIã使ã£ã¦AWS Lambda Web Adapterã試ãã¦ã¿ã¾ãã
ç°å¢
ä»åã®ç°å¢ã¯ãã¡ãã
$ python3 --version Python 3.12.3 $ pip3 --version pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)
Dockerã
$ docker version Client: Docker Engine - Community Version: 27.4.1 API version: 1.47 Go version: go1.22.10 Git commit: b9d17ea Built: Tue Dec 17 15:45:46 2024 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 27.4.1 API version: 1.47 (minimum version 1.24) Go version: go1.22.10 Git commit: c710b88 Built: Tue Dec 17 15:45:46 2024 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.7.24 GitCommit: 88bf19b2105c8b17560993bee28a01ddc2f97182 runc: Version: 1.2.2 GitCommit: v1.2.2-0-g7cb3632 docker-init: Version: 0.19.0 GitCommit: de40ad0
AWS SAMã
$ sam --version SAM CLI, version 1.132.0
FastAPIã使ã£ã¦ã¢ããªã±ã¼ã·ã§ã³ã使ãã
ã¾ãã¯FastAPIã使ã£ã¦ã¢ããªã±ã¼ã·ã§ã³ã使ãã¾ãããã
FastAPIã®ã¤ã³ã¹ãã¼ã«ãåãã§ãã¯ç¨ã®mypyããã¹ãç¨ã«pytestã¨httpxãã¤ã³ã¹ãã¼ã«ãã¦ããã¾ãã
$ pip3 install fastapi[standard] $ pip3 install mypy pytest httpx
ã¤ã³ã¹ãã¼ã«ããã©ã¤ãã©ãªã¼ã®ä¸è¦§ã
$ pip3 list Package Version ----------------- ---------- annotated-types 0.7.0 anyio 4.7.0 certifi 2024.12.14 click 8.1.7 dnspython 2.7.0 email_validator 2.2.0 fastapi 0.115.6 fastapi-cli 0.0.7 h11 0.14.0 httpcore 1.0.7 httptools 0.6.4 httpx 0.28.1 idna 3.10 iniconfig 2.0.0 Jinja2 3.1.4 markdown-it-py 3.0.0 MarkupSafe 3.0.2 mdurl 0.1.2 mypy 1.14.0 mypy-extensions 1.0.0 packaging 24.2 pip 24.0 pluggy 1.5.0 pydantic 2.10.4 pydantic_core 2.27.2 Pygments 2.18.0 pytest 8.3.4 python-dotenv 1.0.1 python-multipart 0.0.20 PyYAML 6.0.2 rich 13.9.4 rich-toolkit 0.12.0 shellingham 1.5.4 sniffio 1.3.1 starlette 0.41.3 typer 0.15.1 typing_extensions 4.12.2 uvicorn 0.34.0 uvloop 0.21.0 watchfiles 1.0.3 websockets 14.1
requirements.txt
ã使ãã¦ããã¾ãã
$ pip3 freeze > requirements.txt
ç°¡åãªã½ã¼ã¹ã³ã¼ãã使ã
main.py
from typing import Union from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class MessageRequest(BaseModel): message: str @app.get("/") def health_check() -> str: return "OK!" @app.get("/hello") def get_hello(message: Union[str, None] = None) -> dict: if message is None: msg = "Hello FastAPI" else: msg = message return {"messageFromGet": msg} @app.post("/hello") def post_hello(message: MessageRequest) -> dict: return {"messageFromPost": message.message}
éçºãµã¼ãã¼ãèµ·åã
$ fastapi dev main.py
確èªã
$ curl localhost:8000 "OK!" $ curl localhost:8000/hello {"messageFromGet":"Hello FastAPI"} $ curl localhost:8000/hello?message=test {"messageFromGet":"test"} $ curl -XPOST -H 'Content-Type: application/json' localhost:8000/hello -d '{"message": "Hello"}' {"messageFromPost":"Hello"}
OKã§ããã
ãã¹ãã使ãã¦ããã¾ãããã
__init__.py
ã使ã
$ touch __init__.py
ãã¹ãã³ã¼ãã
test_main.py
from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_healch_check() -> None: response = client.get("/") assert response.status_code == 200 assert response.text == '"OK!"' def test_get_hello() -> None: response = client.get("/hello") assert response.status_code == 200 assert response.json() == {"messageFromGet": "Hello FastAPI"} response = client.get("/hello", params={"message": "Hello Test FastAPI"}) assert response.status_code == 200 assert response.json() == {"messageFromGet": "Hello Test FastAPI"} def test_post_hello() -> None: response = client.post("/hello", json={"message": "Hello Test FastAPI"}) assert response.status_code == 200 assert response.json() == {"messageFromPost": "Hello Test FastAPI"}
ããã§æºåã¯å®äºã§ãã
AWS Lambda Web Adapterãå«ãã Dockerã¤ã¡ã¼ã¸ã使ãã
ããã§ã¯ããã¡ããåèã«ãã¦ä½æããã¢ããªã±ã¼ã·ã§ã³ã«å¯¾ããDockerfile
ã使ãã¾ãã
https://github.com/awslabs/aws-lambda-web-adapter/blob/v0.8.4/examples/fastapi/app/Dockerfile
ãããªæãã«ãã¾ããããªããå®éã«AWS Lambda Web Adapterã使ã£ãDockerfile
ãæ¸ãæã¯ãå¾è¿°ã®AWS SAMã§ä½¿ãç¨ã«æ¸ãç´ãããã®ã
è¦ãæ¹ããããã¨æãã¾ãã
Dockerfile
FROM public.ecr.aws/docker/library/python:3.12-slim COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter COPY requirements.txt ${LAMBDA_TASK_ROOT} COPY main.py ${LAMBDA_TASK_ROOT} RUN pip install -r requirements.txt --no-cache-dir ENTRYPOINT ["uvicorn"] CMD ["--host=0.0.0.0", "--port=8000", "main:app"]
AWS Lambda Web Adapterãå ãã¦ããã®ã¯ããã§ãã
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
Dockerã¤ã¡ã¼ã¸ããã«ãã
$ docker image build --platform linux/amd64 -t kazuhira/hello-web-adapter:0.0.1 .
èµ·åã
$ docker container run -it --rm --platform linux/amd64 -p 8000:8000 kazuhira/hello-web-adapter:0.0.1
ããã§ã®åä½ç¢ºèªçµæã¯ãcurlã®æã¨åããªã®ã§çç¥ãã¾ãã
ã¡ãªã¿ã«ããããªæãã§ã¢ã¯ã»ã¹ãã¦ãNot Foundã«ãªãã¾ãã
$ curl localhost:8000/2015-03-31/functions/function/invocations -d '{"message": "Hello"}' {"detail":"Not Found"}
ã¾ãDockerfile
ã§ãã¤ã³ãããã¢ãã¬ã¹ã0.0.0.0
ã«ãã¦ãã¾ãããããããåé¤ããã¨ï¼ãã¼ã«ã«ã®ã¿ããã¢ã¯ã»ã¹å¯ã¨ããã¨ï¼
docker container run
ã§ã¯ã¢ã¯ã»ã¹ã§ããªããªãã¾ãã
ENTRYPOINT ["uvicorn"] CMD ["--host=0.0.0.0", "--port=8000", "main:app"]
ãã®å ´åã¯é常ã®Webã¢ããªã±ã¼ã·ã§ã³ã¨ãã¦ä½¿ãã¾ããããã¨ãããã¨ã§ããã
AWS SAMã§è©¦ã
ç¶ãã¦ã¯ãAWS SAMã§è©¦ãã¦ã¿ã¾ãããããã¡ãããã¼ã«ã«ã§åããã¾ãã
AWS SAMããã¸ã§ã¯ãã使ã
$ sam init --name hello-sam-lambda-adapter --base-image amazon/python3.12-base --app-template hello-world-lambda-image --package-type Image --no-tracing --no-application-insights --structured-logging $ cd hello-sam-lambda-adapter
ããã©ã«ãã§çæããã¦ããã³ã¼ãã¯åé¤ãã¦ããã¾ãã
$ rm -rf hello_world events tests
FastAPIç¨ã®ãã£ã¬ã¯ããªã使ããããã§å
ã»ã©ä½æããPythonã³ã¼ãã¨requirements.txt
ãDockerfile
ãã³ãã¼ã
$ mkdir fastapi $ cp /path/to/{main.py,requirements.txt,Dockerfile} fastapi
ãã¹ãã³ã¼ãã¯ããã§ã¯é¤å¤ãã¾ãã
Pythonã³ã¼ãã¯ç¹ã«å¤ãã¦ãã¾ããããDockerfile
ã¯ä»¥ä¸ã®ããã«æ¸ãç´ãã¾ããã
fastapi/Dockerfile
FROM public.ecr.aws/docker/library/python:3.12-slim COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter COPY requirements.txt ${LAMBDA_TASK_ROOT} COPY main.py ${LAMBDA_TASK_ROOT} ENV AWS_LWA_PORT=8000 # 以ä¸ã§ãæå³ã¯åã # ENV PORT=8000 RUN pip install -r requirements.txt --no-cache-dir CMD exec uvicorn --port=${AWS_LWA_PORT} main:app
ãã¤ã³ãã¯ããã¨
ENV AWS_LWA_PORT=8000 # 以ä¸ã§ãæå³ã¯åã # ENV PORT=8000
ããã§ããã
CMD exec uvicorn --port=${AWS_LWA_PORT} main:app
AWS SAMããã¼ã«ã«ã§åä½ãããæã¯Lambda Runtimeã¤ã³ã¿ã¼ãã§ã¼ã¹ãåä½ããã®ã§ãããããã8080ãã¼ãã使ãã®ã§
AWS Lambda Web Adapterãæå¾
ããããã©ã«ãã®ãã¼ãï¼8080ï¼ãã夿´ããæ¹ãç¡é£ã§ãã
AWS Lambda Web Adapter / Local Debugging
ããã§ç°å¢å¤æ°AWS_LWA_PORT
ã使ã£ã¦ãã¾ãã
ENV AWS_LWA_PORT=8000 # 以ä¸ã§ãæå³ã¯åã # ENV PORT=8000
ãªããAWS_LWA_PORT
ã¯PORT
ã§ã代æ¿ãããã¨ãã§ãã¾ãã
AWS Lambda Web Adapter / Configurations
ããã«æ°ã¥ããå¾ã«ããµã³ãã«ã®Dockerfile
ããã¼ããç°å¢å¤æ°PORT
ã§æå®ãã¦ããæå³ããããã¾ããã
https://github.com/awslabs/aws-lambda-web-adapter/blob/v0.8.4/examples/fastapi/app/Dockerfile
ããã¦CMD
ã§ç°å¢å¤æ°ã使ããã¨æãã¨ããããªãã¾ãã
CMD exec uvicorn --port=${AWS_LWA_PORT} main:app
Dockerfile
çã«ã¯ãã¾ããããããªãæ¸ãæ¹ãªæ°ããã¾ããã仿¹ãªãã§ãããâ¦ã
ã¾ãdocker container run
ã§ä½¿ã£ã¦ããæã¨ã¯ç°ãªãã0.0.0.0
ã¸ã®ãã¤ã³ãã¯ä¸è¦ã«ãªãã¾ãã
AWS SAMã®ãã³ãã¬ã¼ããã¡ã¤ã«ã¯ãã®ããã«ãã¾ããã
template.yaml
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > python3.12 Sample SAM Template for hello-sam-lambda-adapter Globals: Function: Timeout: 3 LoggingConfig: LogFormat: JSON Resources: FastApiFunction: Type: AWS::Serverless::Function Properties: PackageType: Image Architectures: - x86_64 Events: GetHello: Type: Api Properties: Path: /hello Method: get PostHello: Type: Api Properties: Path: /hello Method: post Metadata: Dockerfile: Dockerfile DockerContext: ./fastapi DockerTag: 0.0.1 Outputs: FastApi: Description: API Gateway endpoint URL for Prod stage for FastApi function Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" FastApiFunction: Description: FastApi Lambda Function ARN Value: !GetAtt FastApiFunction.Arn FastApiFunctionIamRole: Description: Implicit IAM Role created for FastApi function Value: !GetAtt FastApiFunctionRole.Arn
ã²ã¨ã¤ã®AWS Lambda颿°ã«ãè¤æ°ã®Amazon API Gatewayã®ã¤ãã³ããå²ãå½ã¦ãæãã§ããã
FastApiFunction: Type: AWS::Serverless::Function Properties: PackageType: Image Architectures: - x86_64 Events: GetHello: Type: Api Properties: Path: /hello Method: get PostHello: Type: Api Properties: Path: /hello Method: post Metadata: Dockerfile: Dockerfile DockerContext: ./fastapi DockerTag: 0.0.1
ã§ã¯ãã«ãã
$ sam build
Dockerã¤ã¡ã¼ã¸ãã§ãã¾ããã
Successfully tagged fastapifunction:0.0.1
Amazon API Gatewayã®ã¨ãã¥ã¬ã¼ã¿ã¼ãèµ·åãã¾ãã
$ sam local start-api
確èªã
$ curl localhost:3000/hello {"messageFromGet":"Hello FastAPI"} $ curl localhost:3000/hello?message=test {"messageFromGet":"test"} $ curl -XPOST -H 'Content-Type: application/json' localhost:3000/hello -d '{"message": "Hello"}' {"messageFromPost":"Hello"}
OKã§ããã
Amazon API Gatewayï¼ã®ã¨ãã¥ã¬ã¼ã¿ã¼ã§ããï¼çµç±ã§ããFastAPIã使ã£ã¦ä½æããAWS Lambda颿°ãå¼ã³åºãããã¨ã確èªã§ãã¾ããã
ãããã«
AWS Lambda Web AdapterãFastAPIã使ã£ã¦è©¦ãã¦ã¿ã¾ããã
1度試ãã¦ãããããªã¨æã£ã¦ããã®ã§ãä»åã©ããããã®ããã£ããææ¡ã§ããã®ã§è¯ãã£ãã§ãã
ã©ã¡ããã¨ããã¨Dockerfile
ã®æ¸ãæ¹ã§è¦å´ããããã¾ãããã©ï¼ç¬ï¼ã