繁体   English   中英

在AWS Lambda和API网关中部署Flask sqlalchemy应用程序

[英]Deploying Flask sqlalchemy apps in AWS lambda and API gateway

我找不到很好的资源来帮助我理解如何将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__)应该不正确吗? 如果没有应用程序变量,我该如何初始化数据库变量?

请有人能给我一些介绍或指向可以清除这些概念的优秀教程的链接吗?

提前谢谢了。

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

将Lambda请求分派到Flask

您可以将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 Data API。 它基本上是一个AWS认证的HTTP 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)

首先,在AWS Lambda中,您不再使用Flask进行路由。 而是使用AWS API Gateway进行路由。 下面显示了路由示例, 网址https://apievangelist.com/2017/10/23/a-simple-api-with-aws-dynamodb-lambda-and-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的 两种方法(请参见第一张图片中的Integration Request框)。

简短的版本差异是:

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

对于SQL Alchemy,您所需要做的就是将所有 SQL Alchemy库代码及其依赖项与Lambda函数一起压缩,然后将其上传到Lambda控制台,它无需任何修改即可工作。

请注意,由于Lambda函数无法访问文件系统,因此SQLite 无法在Lambda中运行。 您应该将数据放在其他地方,例如Amazon RDS(使用MySQL,PostgreSQL,随便使用什么),然后确保Lambda与RDS数据库连接到同一VPC(Amazon内部路由器)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM