前言
AWS Lambda 本身是一个以事件驱动的 Serverless 服务, 最简单的应用就是在入口函数中对接收到的事件/请求进行处理并返回响应. 对于像 Flask 这样的 Web 框架, 并不能直接在 Lambda 上提供服务, 不过我们可以借助 AWS Lambda Web Adapter 实现一个基于 Flask 框架的 Web 后端服务. Lambda 前面再放上一个 API Gateway 即可完成一套完整的 Serverless Web 应用服务.
- 官方文档
https://github.com/awslabs/aws-lambda-web-adapter/tree/main - 官方 Flask Demo
https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examples/flask-zip - 架构实例
随便写个 Flask 应用
requirements.txt
Flask==3.0.3
gunicorn==22.0.0
app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.get("/<username>")
def index(username):
return render_template("index.html", username=username)
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Flask</title>
</head>
<body>
<h1>Hello {{username}}!</h1>
</body>
</html>
继续添加个 Shell 脚本用于 Lambda 启动 Flask 应用
run.sh
#!/bin/bash
PATH=$PATH:$LAMBDA_TASK_ROOT/bin \
PYTHONPATH=$PYTHONPATH:/opt/python:$LAMBDA_RUNTIME_DIR \
exec python -m gunicorn -b=:$PORT -w=1 app:app
手动在本地跑一下测试 OK
gunicorn -b=:8080 -w=1 app:app
部署到 Lambda
先将本地开发好的 Flask 应用包含依赖一并打包成 ZIP 文件:
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo$ mkdir package
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo$ pip install --target ./package/ -r requirements.txt
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo$ cd package/
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo/package$ zip -r ../flask-demo.zip .
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo/package$ cd ..
lpwm@Beijing:/mnt/c/Users/lpwm/Desktop/flask-demo$ zip -ur flask-demo.zip app.py run.sh templates/
打包完成后的 ZIP 压缩包内部长这样, 即所有的依赖会放在项目的根路径(app.py
所在位置)中:
在 Lambda 控制台创建一个新的 Function, Runtime 选择 Python, Architecture 注意选择 x86_64, 目前中国区的 AWS Lambda Web Adapter 还不支持 arm64 架构.
创建好的 Function 点击 Upload from > .zip file 选择本地准备好的 ZIP 压缩包进行上传.
划重点 添加 Layer. 中国区 AWS 对应的 Layer ARN 目前还仅支持 x86_64 架构的环境
- cn-north-1 (Beijing)
x86_64:arn:aws-cn:lambda:cn-north-1:041581134020:layer:LambdaAdapterLayerX86:22
- cn-northwest-1 (Ningxia)
x86_64:arn:aws-cn:lambda:cn-northwest-1:069767869989:layer:LambdaAdapterLayerX86:22
配置两个环境变量:
AWS_LAMBDA_EXEC_WRAPPER
: /opt/bootstrap
固定内容, 用于初始化 AWS Lambda Web Adapter Layer
PORT
: 8080
gunicorn 启动内部 Flask server 时监听的端口, 也是 AWS Lambda Web Adapter 用来访问内部 Web 服务的端口, 可以修改为其他.
修改 Function 的入口函数
测试 Function 没有报错:
配置 API Gateway
在 Function overview 界面点击 + Add trigger
建议使用 REST API
点击 API endpoint 访问测试
填坑
直接测试访问是成功了, 但是当修改 URL 中的 flask-demo
为其他内容时, 会出现 Missing Authentication Token
错误:
打开 API Gateway 控制台检查自动创建的 API Resources
通过 Lambda 添加 Trigger 创建的 API 会默认添加和 Lambda function 相同名称的一个路由, 接受 ANY 方法请求集成给 Lambda, 结合上面测试的情况来看, 后端的 Flask 会将这个 flask-demo
判定为是要接收的参数. 这种情况显然不是我们想要的.
手动将 /flask-demo
这个路由删掉, 我们手动重新创建
测试一下
重新 Deploy
再次从浏览器访问