FastAPI 部署與架構:Serverless 部署(Vercel / Cloud Run)
簡介
在現代的 Web 應用開發中,快速迭代與彈性伸縮已成為不可或缺的需求。FastAPI 以其高效能、易用的型別提示與自動產生 OpenAPI 文件的特性,迅速成為 Python 生態系統中最受歡迎的框架之一。當我們完成 API 開發後,如何把服務以 Serverless 方式部署,讓它只在需要時才啟動、只為實際使用的請求付費,成為下一個重要課題。
本篇文章聚焦於兩個主流的 Serverless 平台——Vercel 與 Google Cloud Run,說明如何將 FastAPI 應用無縫搬上雲端,並提供實作範例、常見陷阱與最佳實踐,協助你在開發與部署之間建立穩固的橋樑。
核心概念
1. 為什麼選擇 Serverless?
| 特性 | 傳統 VM / Container | Serverless |
|---|---|---|
| 成本 | 持續付費(CPU、記憶體) | 按請求計費,閒置不收費 |
| 伸縮 | 手動或自動調整,需設定上限 | 自動依流量彈性擴張 |
| 部署速度 | 需要建置映像檔、設定環境 | 直接推送程式碼或容器,即可上線 |
| 維運負擔 | 需要管理 OS、更新、監控 | 平台負責底層基礎設施 |
對於 API 這類「請求驅動」的服務,Serverless 能顯著降低成本,同時提供即時的彈性伸縮,特別適合 MVP、原型開發 或 流量波動大的應用。
2. FastAPI 與 ASGI
FastAPI 基於 ASGI(Asynchronous Server Gateway Interface)規範,這意味著它可以直接在支援 ASGI 的平台上執行,而不需要額外的 WSGI 包裝層。Vercel 與 Cloud Run 都支援容器化或直接執行 ASGI 應用,使得 FastAPI 的部署變得相當直接。
3. Vercel 與 Cloud Run 的差異
| 項目 | Vercel | Cloud Run |
|---|---|---|
| 部署模型 | Git‑Driven(自動建置) + Serverless Functions | Container‑Driven(Docker) + Serverless |
| 語言支援 | 原生支援 Node.js、Python(透過 vercel-python) |
任意支援 Docker 的語言 |
| 冷啟動 | 約 200‑500ms(根據函式大小) | 約 500‑1000ms(容器啟動) |
| 最大請求時限 | 60 秒(免費方案) | 60 分鐘(可自訂) |
| 計費方式 | 執行次數 + 執行時間 | 執行時間 + 記憶體配置 |
Vercel 更適合 前端與 API 同步部署,且開發者只需要撰寫簡單的 vercel.json 即可;而 Cloud Run 則提供更大的彈性(自訂容器、長時間執行、較高的 CPU 配置),適合 需要較高效能或較大規模的服務。
程式碼範例
以下示範三個常見的部署方式,分別針對 Vercel、Cloud Run(Docker)以及 同時支援兩者的通用 Dockerfile。每段程式碼都附有詳細註解,方便你直接套用。
1️⃣ 基本 FastAPI 應用 (app/main.py)
# app/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
app = FastAPI(title="Serverless FastAPI Demo")
class Item(BaseModel):
id: int
name: str
price: float
# 假資料庫
FAKE_DB = [
{"id": 1, "name": "Apple", "price": 2.5},
{"id": 2, "name": "Banana", "price": 1.2},
]
@app.get("/items", response_model=List[Item])
async def list_items():
"""取得所有商品"""
return FAKE_DB
@app.get("/items/{item_id}", response_model=Item)
async def get_item(item_id: int):
"""根據 ID 取得單一商品"""
for item in FAKE_DB:
if item["id"] == item_id:
return item
raise HTTPException(status_code=404, detail="Item not found")
@app.post("/items", response_model=Item, status_code=201)
async def create_item(item: Item):
"""新增商品"""
FAKE_DB.append(item.dict())
return item
小技巧:在開發階段使用
uvicorn app.main:app --reload,在部署時只需要把app物件暴露即可。
2️⃣ Vercel Serverless Function (api/index.py)
Vercel 會自動把 api/ 目錄下的檔案視為 Serverless Function。我們只需要把 FastAPI 包裝成 WSGI/ASGI 兼容的函式。
# api/index.py
import os
from fastapi import FastAPI
from fastapi.routing import APIRouter
from starlette.requests import Request
from starlette.responses import Response
from mangum import Mangum # 讓 FastAPI 能在 AWS Lambda / Vercel 上跑
# 直接匯入我們前面寫好的 FastAPI 應用
from app.main import app as fastapi_app
# 使用 Mangum 包裝
handler = Mangum(fastapi_app)
def handler(event, context):
"""
Vercel 會呼叫此函式,event 為 Lambda 事件格式。
Mangum 會把它轉換成 ASGI 呼叫,回傳符合 Vercel 規範的結果。
"""
return handler(event, context)
重要:Vercel 官方目前仍以
vercel-python為主,若想直接部署 FastAPI,使用 Mangrove (Mangum) 這樣的適配器最簡單。請在requirements.txt中加入fastapi,uvicorn,mangum。
vercel.json
{
"functions": {
"api/index.py": {
"runtime": "python3.11",
"maxDuration": 60
}
}
}
說明:
maxDuration設定函式最長執行時間(秒),超過會被強制終止。
3️⃣ Cloud Run Dockerfile(適用於任意平台)
Cloud Run 以容器為單位執行,因此只要把 FastAPI 包裝成一個 Docker image,然後推到 Container Registry(或 Artifact Registry)即可。
# Dockerfile
FROM python:3.11-slim
# 建立非 root 使用者,提升安全性
RUN useradd -m appuser
WORKDIR /app
# 安裝系統相依套件(如需要的話)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 複製需求檔與安裝
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 複製程式碼
COPY . .
# 以非 root 身份執行
USER appuser
# 使用 Uvicorn 作為 ASGI 伺服器,綁定 0.0.0.0:8080(Cloud Run 預設埠號)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]
requirements.txt
fastapi==0.110.0
uvicorn[standard]==0.27.0
gunicorn==21.2.0 # optional, 若想使用 gunicorn + uvicorn worker
部署步驟(概略)
# 1. 建立 Container Registry
gcloud artifacts repositories create my-repo --repository-format=docker --location=asia-east1
# 2. 建置 Docker 映像
docker build -t asia-east1-docker.pkg.dev/<PROJECT_ID>/my-repo/fastapi-serverless:latest .
# 3. 推送至 Registry
docker push asia-east1-docker.pkg.dev/<PROJECT_ID>/my-repo/fastapi-serverless:latest
# 4. 部署到 Cloud Run
gcloud run deploy fastapi-service \
--image=asia-east1-docker.pkg.dev/<PROJECT_ID>/my-repo/fastapi-serverless:latest \
--platform=managed \
--region=asia-east1 \
--allow-unauthenticated \
--cpu=1 \
--memory=512Mi \
--max-instances=10
提示:
--max-instances可以限制最大容器數量,避免突發流量產生過高費用。
4️⃣ 同時支援 Vercel 與 Cloud Run 的通用 Dockerfile
如果你想一次寫好 Dockerfile,然後在 Vercel(使用 vercel build) 與 Cloud Run 兩個平台皆能使用,只要把入口點改成 uvicorn,並在 vercel.json 設定 buildCommand 與 outputDirectory。
# Dockerfile (通用版)
FROM python:3.11-slim
WORKDIR /app
# 安裝依賴
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 複製程式碼
COPY . .
# 暴露埠口(Vercel 會自動映射 3000,Cloud Run 需要 8080)
EXPOSE 3000 8080
# 預設指令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "3000"]
注意:在 Vercel 使用 Docker 時,需要在
vercel.json裡指定buildCommand為docker build -t app .,並把outputDirectory設為/(根目錄即為容器入口點)。
常見陷阱與最佳實踐
| 陷阱 | 可能的症狀 | 解決方案/最佳實踐 |
|---|---|---|
| 冷啟動延遲 | 第一次請求回應時間 > 1 秒 | - 使用較小的容器基礎映像(python-slim)- 預熱(在 Cloud Run 設 --min-instances=1)- 在 Vercel 使用 vercel dev 本機測試,確保函式尺寸小 |
| 依賴未打包 | 部署後 500 錯誤,找不到模組 | - 確認 requirements.txt 完整- 在 Dockerfile 中使用 --no-cache-dir 減少層級錯誤 |
| 環境變數未傳遞 | 讀不到資料庫連線字串 | - Vercel:在 Dashboard → Settings → Environment Variables 設定 - Cloud Run: gcloud run services update <service> --set-env-vars KEY=VALUE |
| 請求時限超過 | 長時間的背景任務被中斷 | - 把耗時工作移到 Cloud Tasks、Pub/Sub 或 Background Worker - 若必須在 API 完成,可在 Cloud Run 調整 --timeout(最長 60 分鐘) |
| 日誌與監控不足 | 無法追蹤錯誤或效能瓶頸 | - Vercel:使用內建「Logs」或串接 Logflare - Cloud Run:透過 Stackdriver Logging 與 Tracing,並加上 uvicorn[standard] 的 --log-level info |
| 跨域(CORS)問題 | 前端呼叫失敗,出現 No 'Access-Control-Allow-Origin' header |
- 在 FastAPI 加入 from fastapi.middleware.cors import CORSMiddleware,設定允許來源 |
建議的最佳實踐
- 最小化容器大小:只安裝執行所需的套件,使用
python:*-slim或alpine(若相依套件支援)。 - 使用非 root 用戶:在 Dockerfile 中建置
appuser,提升安全性。 - 分離長時間任務:將繁重的計算或 I/O 交給 Cloud Tasks、Pub/Sub 或 Cloud Functions,保持 API 的 快速回應。
- 設定健康檢查:Cloud Run 允許自訂
/health端點,確保容器在失敗時自動重啟。 - 版本化部署:利用 Git 標籤或 Cloud Run 的 revision 功能,快速回滾至先前穩定版本。
實際應用場景
| 場景 | 為何選 Serverless FastAPI | 部署建議 |
|---|---|---|
| 行銷活動的即時報名系統 | 流量在活動期間會瞬間激增,平日幾乎為零 | 使用 Cloud Run 最小實例 0(零成本),設定自動擴展上限 100+ |
| 前端 Next.js + API | 想把前端(Next.js)與 API 同時放在 Vercel,保持同一個域名 | 在 Vercel api/ 目錄使用 Mangum 包裝 FastAPI,前端直接呼叫 /api/... |
| 機器學習模型推論 | 每筆請求需要載入模型(約 500MB),但請求頻率不高 | 把模型放在 Cloud Storage,使用 Cloud Run 高記憶體配置(2Gi)並設定 --max-instances=5 |
| 內部工具(管理介面) | 員工偶爾使用,安全性需求較高 | 在 Cloud Run 加上 IAM 授權,僅允許特定 Google 帳號存取 |
| 多租戶 SaaS API | 每個客戶都有獨立的子域名,需快速擴容 | 使用 Vercel 的 Edge Functions 搭配 FastAPI,利用 Edge 的全球快取降低延遲 |
總結
- Serverless 為 FastAPI 提供了低成本、彈性伸縮與簡化運維的優勢。
- Vercel 適合與前端緊密結合的小型或中等流量服務,部署方式以 functions 為主,透過 Mangum 可輕鬆包裝 FastAPI。
- Google Cloud Run 則以 Docker 為核心,支援更高的 CPU、記憶體配置與較長的請求時限,適合需要較大資源或自訂執行環境的情境。
- 透過 最佳實踐(最小化映像、非 root 用戶、分離長時間任務、設定健康檢查)與 常見陷阱 的避免策略,你的 FastAPI 服務將能在兩大平台上穩定運行,並在流量高峰時自動擴展。
掌握上述概念與步驟,你就能把 FastAPI API 以 Serverless 方式快速上線,讓開發者專注於業務邏輯,而不是底層基礎設施的維護。祝你部署順利,服務穩定成長! 🚀