Deploy FastAPI to AWS in 60 Seconds

Deploy FastAPI to AWS in 60 Seconds

在 60 秒内将 FastAPI 部署到 AWS

Deploy a standard FastAPI app to AWS Lambda serverlessly in two commands. No Docker. No handler code. No code changes. 只需两条命令,即可将标准的 FastAPI 应用以无服务器(Serverless)方式部署到 AWS Lambda。无需 Docker,无需编写处理程序(handler)代码,无需修改任何代码。

How do I deploy FastAPI to AWS Lambda without code changes? You add Lambda Web Adapter as a Lambda Layer, and your FastAPI app deploys to AWS Lambda with sam build && sam deploy. The same code you run locally with uvicorn goes straight to production without any modifications. No handler wrapper, no Mangum, no Dockerfile. 如何做到在不修改代码的情况下将 FastAPI 部署到 AWS Lambda?你只需添加 Lambda Web Adapter 作为 Lambda 层(Layer),然后使用 sam build && sam deploy 即可完成部署。你在本地使用 uvicorn 运行的代码无需任何改动即可直接上线。无需处理程序包装器,无需 Mangum,也无需 Dockerfile。

Lambda scales to zero, so you pay nothing when idle, and your app never knows it’s running on Lambda. In this post, I walk through how to set this up from scratch, explain the architecture, and deploy a working API in about 60 seconds of actual commands. Lambda 支持缩容至零,因此在空闲时无需付费,且你的应用完全感知不到它正运行在 Lambda 上。在这篇文章中,我将演示如何从零开始配置,解释其架构,并在约 60 秒的实际操作时间内部署一个可用的 API。

What is Lambda Web Adapter and how does it work with FastAPI? If you’ve ever deployed a FastAPI app to Lambda the traditional way, you know the drill: install Mangum, wrap your app in a handler function, build a Docker image, push to ECR, configure API Gateway. It works, but now your app has Lambda-specific code baked in. 什么是 Lambda Web Adapter,它如何与 FastAPI 协同工作?如果你曾以传统方式将 FastAPI 应用部署到 Lambda,你一定很熟悉这些流程:安装 Mangum,将应用包装在处理函数中,构建 Docker 镜像,推送到 ECR,配置 API Gateway。这种方法可行,但你的应用中会掺杂 Lambda 特有的代码。

Lambda Web Adapter takes a completely different approach. It’s an open-source Lambda Layer maintained by AWS. You add it to a function, and it handles all the translation between Lambda’s event format and plain HTTP. When a request comes in, the adapter intercepts the Lambda invocation and forwards it as a normal HTTP request to a local web server. In this case, uvicorn running your FastAPI app on port 8080. Lambda Web Adapter 采用了完全不同的方法。它是由 AWS 维护的一个开源 Lambda 层。将其添加到函数后,它会处理 Lambda 事件格式与普通 HTTP 之间的所有转换。当请求到来时,适配器会拦截 Lambda 调用,并将其作为普通的 HTTP 请求转发给本地 Web 服务器。在本例中,即运行在 8080 端口上的 uvicorn FastAPI 应用。

The flow looks like this: Your app receives normal HTTP requests and returns normal HTTP responses. It has no idea it’s running inside a Lambda function. This means the same FastAPI app runs on Lambda, in a Docker container on ECS, or on your laptop with uvicorn. Zero changes between environments. With that in mind, let’s look at what the actual code looks like. 流程如下:你的应用接收正常的 HTTP 请求并返回正常的 HTTP 响应。它完全不知道自己运行在 Lambda 函数中。这意味着同一个 FastAPI 应用既可以运行在 Lambda 上,也可以运行在 ECS 的 Docker 容器中,或者在你笔记本电脑的 uvicorn 上。环境之间无需任何更改。考虑到这一点,让我们看看实际的代码是什么样的。

Can I use my existing FastAPI app on Lambda without changes? Yes. And that’s the whole point. Here’s the complete application. Take a look and notice what’s not there: no Lambda imports, no handler function, no Mangum wrapper. This is a standard FastAPI app you could run anywhere. 我可以在不修改的情况下将现有的 FastAPI 应用部署到 Lambda 吗?可以。这正是核心所在。以下是完整的应用程序。请注意其中缺少的内容:没有 Lambda 导入,没有处理函数,没有 Mangum 包装器。这是一个可以在任何地方运行的标准 FastAPI 应用。

# main.py
import asyncio
from typing import Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="Items API")
_items: dict[int, dict] = {}
_next_id = 1

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float

class ItemResponse(Item):
    id: int

@app.get("/health")
def health():
    return {"status": "ok"}

@app.get("/items", response_model=list[ItemResponse])
def list_items():
    return [{"id": k, **v} for k, v in _items.items()]

@app.post("/items", response_model=ItemResponse, status_code=201)
def create_item(item: Item):
    global _next_id
    item_id = _next_id
    _next_id += 1
    _items[item_id] = item.model_dump()
    return {"id": item_id, **_items[item_id]}

@app.get("/items/{item_id}", response_model=ItemResponse)
def get_item(item_id: int):
    if item_id not in _items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"id": item_id, **_items[item_id]}

@app.delete("/items/{item_id}", status_code=204)
def delete_item(item_id: int):
    if item_id not in _items:
        raise HTTPException(status_code=404, detail="Item not found")
    del _items[item_id]

@app.get("/async-demo")
async def async_demo():
    await asyncio.sleep(1)
    return {"message": "done", "waited_seconds": 1}

A CRUD API with an async endpoint. Nothing special. That’s the point. The only other piece is run.sh, a tiny shell script that starts uvicorn. This is the entrypoint Lambda will call: 一个带有异步端点的 CRUD API。没什么特别的,这正是重点。剩下的唯一部分是 run.sh,这是一个启动 uvicorn 的小型 shell 脚本。这是 Lambda 将调用的入口点:

#!/bin/bash
export PYTHONPATH=/var/task:$PYTHONPATH
exec python -m uvicorn main:app --host 0.0.0.0 --port 8080

And requirements.txt with three dependencies: 以及包含三个依赖项的 requirements.txt

fastapi
uvicorn[standard]
pydantic

That’s the entire application. You can run it locally right now with uvicorn main:app --reload --port 8080 and get the same behavior you’ll get on Lambda. No adapter, no layer, no SAM. Locally, it’s a normal FastAPI app. So where does the Lambda configuration actually go? That brings us to the one file that makes the deployment work. What does the SAM template look like? 这就是整个应用程序。你现在就可以使用 uvicorn main:app --reload --port 8080 在本地运行它,并获得与 Lambda 上相同的行为。没有适配器,没有层,没有 SAM。在本地,它就是一个普通的 FastAPI 应用。那么 Lambda 的配置到底放在哪里呢?这就引出了使部署生效的那个文件。SAM 模板长什么样?

All the Lambda-specific configuration lives in a single file, and it’s not your application code. It’s the AWS SAM template. SAM (Serverless Application Model) is an open-source framework that extends CloudFormation to make serverless deployments simpler. Here’s the complete template: 所有 Lambda 特有的配置都位于一个文件中,而且它不是你的应用程序代码,而是 AWS SAM 模板。SAM (Serverless Application Model) 是一个开源框架,它扩展了 CloudFormation,使无服务器部署变得更简单。以下是完整的模板:

# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: FastAPI on AWS Lambda using Lambda Web Adapter (zip, no Docker)

Resources:
  FastApiFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Handler: run.sh
      Runtime: python3.12
      Architectures:
        - arm64
      MemorySize: 512
      Timeout: 30
      Layers:
        - !Sub arn:aws:lambda:${AWS::Region}:753240598075:layer:LambdaAdapterLayerArm64:24
      Environment:
        Variables:
          AWS_LWA_PORT: '8080'
          AWS_LAMBDA_EXEC_WRAPPER: /opt/bootstrap
      Events:
        Api:
          Type: HttpApi

Outputs:
  ApiUrl:
    Description: API Gateway endpoint URL
    Value: !Sub https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com

Let’s take a look at the important parts: 让我们看看其中的关键部分:

  • Handler: run.sh means the entrypoint is a shell script that starts uvicorn, not a Python handler function. That’s what makes this work. Handler: run.sh 表示入口点是一个启动 uvicorn 的 shell 脚本,而不是 Python 处理函数。这就是它能生效的原因。
  • Layers is the Lambda Web Adapter layer ARN. This is the arm64 version (layer 24, v0.8.4). The layer provides the /opt/bootstrap wrapper that intercepts invocations and proxies them to your server. Layers 是 Lambda Web Adapter 层的 ARN。这是 arm64 版本(第 24 层,v0.8.4)。该层提供了 /opt/bootstrap 包装器,用于拦截调用并将其代理到你的服务器。
  • AWS_LWA_PORT: ‘8080’ tells the adapter which port your app listens on. AWS_LWA_PORT: ‘8080’ 告诉适配器你的应用监听哪个端口。
  • AWS_LAMBDA_EXEC_WRAPPER: /opt/bootstrap tells Lambda to use the adapter’s bootstrap wrapper instead of invoking your handler directly. AWS_LAMBDA_EXEC_WRAPPER: /opt/bootstrap 告诉 Lambda 使用适配器的 bootstrap 包装器,而不是直接调用你的处理程序。
  • Architectures: arm64 runs on Graviton2, AWS’s Arm-based processor. Better price-performance than x86. No code changes needed since Python is architecture-independent. Architectures: arm64 运行在 AWS 基于 Arm 的处理器 Graviton2 上。比 x86 具有更好的性价比。由于 Python 与架构无关,因此无需更改代码。
  • Events: HttpApi creates an Amazon API Gateway HTTP API (v2). This one line gives you a lot: a publicly accessible URL, automatic stage deployment, built-in CORS support, and more. Events: HttpApi 创建了一个 Amazon API Gateway HTTP API (v2)。这一行配置为你提供了很多功能:可公开访问的 URL、自动阶段部署、内置 CORS 支持等。