【问题标题】:Deploying Flask sqlalchemy apps in AWS lambda and API gateway在 AWS lambda 和 API 网关中部署 Flask sqlalchemy 应用程序
【发布时间】:2019-10-11 23:30:16
【问题描述】:

我找不到好的资源来帮助我了解如何将我的 Flask 和 sqlalchemy 应用程序迁移到 AWS lambda 和 API 网关并使其无服务器。例如下面是从 flask_sqlalchemy 文档中获取的示例代码:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

现在如何将此代码迁移到 AWS lambda。有没有可能。例如app = Flask(__name__) 这条线不应该在那里吗?如果没有 app 变量,我将如何初始化 db 变量?

请有人给我一些介绍或链接到一个很好的教程,这将清除这些概念?

非常感谢。

【问题讨论】:

  • 它没有回答您的问题,但您可能需要考虑使用chalice 作为类似 Flask 的框架,为您提供 Lambda+APIGW 应用程序的解决方案。
  • 感谢一百万以上的建议。

标签: python amazon-web-services flask flask-sqlalchemy


【解决方案1】:

要将 Flask/sqlalchemy 应用程序与 Lambda 一起使用,您需要将 Flask 包装在 Lambda 调度模型中,并确保 sqlalchemy 可以访问其数据库。

向 Flask 发送 Lambda 请求

您可以像这样将Chalice 与 Flask 集成:

class ChaliceWithFlask(chalice.Chalice):
    """
    Subclasses Chalice to host a Flask app, route and proxy requests to it.
    """
    def __init__(self, flask_app, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.flask_app = flask_app
        self.trailing_slash_routes = []
        routes = collections.defaultdict(list)
        for rule in self.flask_app.url_map.iter_rules():
            route = re.sub(r"<(.+?)(:.+?)?>", r"{\1}", rule.rule)
            if route.endswith("/"):
                self.trailing_slash_routes.append(route.rstrip("/"))
            routes[route.rstrip("/")] += rule.methods
        for route, methods in routes.items():
            self.route(route, methods=list(set(methods) - {"OPTIONS"}), cors=True)(self.dispatch)

    def dispatch(self, *args, **kwargs):
        uri_params = self.current_request.uri_params or {}
        path = self.current_request.context["resourcePath"].format(**uri_params)
        if self.current_request.context["resourcePath"] in self.trailing_slash_routes:
            if self.current_request.context["path"].endswith("/"):
                path += "/"
            else:
                return chalice.Response(status_code=requests.codes.found, headers={"Location": path + "/"}, body="")
        req_body = self.current_request.raw_body if self.current_request._body is not None else None
        base_url = "https://{}".format(self.current_request.headers["host"])
        query_string = self.current_request.query_params or {}
        with self.flask_app.test_request_context(path=path,
                                                 base_url=base_url,
                                                 query_string=list(query_string.items()),
                                                 method=self.current_request.method,
                                                 headers=list(self.current_request.headers.items()),
                                                 data=req_body,
                                                 environ_base=self.current_request.stage_vars):
            flask_res = self.flask_app.full_dispatch_request()
        res_headers = dict(flask_res.headers)
        res_headers.pop("Content-Length", None)
        res_body = b"".join([c for c in flask_res.response])
        return chalice.Response(status_code=flask_res._status_code, headers=res_headers, body=res_body)

flask_app = flask.Flask(app_name)
# add routes, etc. to your Flask app here
app = ChaliceWithFlask(app_name, flask_app=flask_app)

将 sqlalchemy 连接到数据库

您可以直接访问数据库,但这意味着将数据库端口打开到 Internet 或将您的 Lambda 放置在 VPC 中(这使得 Lambda 无法通过 Internet 访问)。此外,传统的数据库驱动程序对其连接的持久性做出了 Lambda 不满足的假设。

AWS 最近为此推出了完美的解决方案 - AWS Aurora RDS 数据 API。它基本上是一个 AWS 认证的 SQL-over-HTTP 隧道。我为它写了一个 SQLAlchemy 适配器:sqlalchemy-aurora-data-api。安装后,你可以这样做:

from sqlalchemy import create_engine

cluster_arn = "arn:aws:rds:us-east-1:123456789012:cluster:my-aurora-serverless-cluster"
secret_arn = "arn:aws:secretsmanager:us-east-1:123456789012:secret:MY_DB_CREDENTIALS"

app = Flask(app_name)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+auroradataapi://:@/my_db_name'
engine_options=dict(connect_args=dict(aurora_cluster_arn=cluster_arn, secret_arn=secret_arn))
db = flask_sqlalchemy.SQLAlchemy(app, engine_options=engine_options)

【讨论】:

  • 此代码不适用于在 chalice/lambda 函数中运行的我,因为无法安装 sqlalchemy(没有 whl),因此我必须手动包含 sqlalchemy。你是如何让它发挥作用的?
  • 请参阅chalice.readthedocs.io/en/latest/topics/…,了解没有轮子的包装的包装说明。
【解决方案2】:

首先,在 AWS Lambda 中,您不再使用 Flask 进行路由。而是使用 AWS API Gateway 进行路由。路由示例如下所示,来自https://apievangelist.com/2017/10/23/a-simple-api-with-aws-dynamodb-lambda-and-api-gateway/

正如您在图片的右端看到的那样,“Lambda”框显示了您已上传的 Lambda 函数的名称。对于 Python 中的 Lambda,请参阅https://docs.aws.amazon.com/lambda/latest/dg/python-programming-model-handler-types.html

基本上,Python lambda 的主要内容是:

def handler_name(event, context): 
   ...
   return some_value

从事件和上下文中,您可以获得所有内容:路径、HTTP 方法、标头、参数、正文等(如flask.request)。您可能还需要知道 两种 的 Lambda 方法,即 LAMBDALAMBDA_PROXY(请参见第一张图片中的集成请求框)。

短版区别是:

  • LAMBDA 模式将自动预处理请求正文,并在event 中为您的 Lambda 函数提供一个 Python 对象。
  • LAMBDA_PROXY 将为您提供原始 HTTP 请求,您需要自己在 Lambda 函数中转换内容。

对于 SQL Alchemy,您只需将 SQL Alchemy 库代码及其依赖项连同您的 Lambda 函数一起压缩并上传到 Lambda 控制台,无需任何操作即可修改。

请注意,SQLite 在 Lambda 中不起作用,因为 Lambda 函数没有文件系统访问权限。您应该将数据放在其他地方,例如Amazon RDS(使用 MySQL、PostgreSQL,无论你喜欢什么),然后确保 Lambda 连接到与 RDS 数据库相同的 VPC(Amazon 内部路由器)。

【讨论】:

    猜你喜欢
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 2020-04-29
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 2017-08-16
    相关资源
    最近更新 更多