python中的无服务器Web应用

Serverless technologies have a lot of people excited — in theory, they offer infinite scaling with no maintenance. After mostly seeing “hello-world on Lambda” tutorials, I was curious how it would work for a real application with a frontend and a database.

无服务器技术使很多人兴奋—从理论上讲,它们无需维护即可提供无限扩展。 在主要看过“ Lambda上的hello-world”教程之后,我很好奇它如何在带有前端和数据库的实际应用程序中工作。

This article reviews my experience using AWS Lambda for full-stack web applications. If you’re familiar with the theory and want to know more about how it works in practice, you’re in the right place.

本文回顾了我将AWS Lambda用于全栈Web应用程序的经验。 如果您熟悉该理论并且想更多地了解它在实践中的工作原理,那么您来对地方了。

为什么没有服务器? (Why Serverless?)

Serverless could be a good choice for anyone who doesn’t want to manage infrastructure. Specifically, it’s a great fit for bursty workloads that need to scale in short bursts (why pay for a server to idle all day?), and for functions that need to run every time an item enters a queue.

对于不想管理基础架构的任何人,无服务器都是一个不错的选择。 特别是,它非常适合需要短暂扩展的突发工作负载(为什么要为服务器全天空闲支付费用?),以及每次项目进入队列时都需要运行的功能。

A typical web app is none of the above, yet that’s what I cover in this post. I wanted to try deploying a web app with zero maintenance. For a side project, Heroku wasn’t worth the money and monitoring & maintaining a server wasn’t worth my time. So I gave Lambda a shot.

一个典型的Web应用程序并非以上所述,但这就是我在这篇文章中介绍的内容。 我想尝试部署零维护的Web应用程序。 对于附带项目,Heroku并不值得,而监视和维护服务器也不值得。 所以我给了Lambda一个机会。

I built this project using Flask, ReactJS, and Postgres, and if you squint hard enough, it looks like a production system. While I can only share my experience, I believe it can be generalized to any Python backend and perhaps beyond.

我使用Flask,ReactJS和Postgres构建了这个项目,如果您斜视一下,它看起来就像一个生产系统。 虽然我只能分享我的经验,但我相信它可以推广到任何Python后端甚至更多。

扎帕 (Zappa)

Zappa is a library that makes it easy to deploy Python applications to Lambda. Lambda expects a zip archive of your code and your Python dependencies. With a couple commands, Zappa creates the archive and much more, including the Lambda function, IAM roles, and API gateway.

Zappa是一个库,可轻松将Python应用程序部署到Lambda。 Lambda需要您的代码和Python依赖项的zip存档。 通过几个命令,Zappa可以创建存档以及更多内容,包括Lambda函数,IAM角色和API网关。

Zappa hooks into your virtualenv in order to zip up the Python dependencies. Many popular libraries, such as numpy, include compiled C code for performance. When you pip install numpy, you get compiled binaries for your current environment - MacOS in my case. These binaries likely won't work on Lambda, which runs on a Linux environment. So it's clear that naively packaging a virtualenv won't work. To remediate this, Zappa has a sister repository of precompiled binaries for popular Python packages and it swaps these in when building the archive. If you use a dependency with compiled binaries that isn't on this list, it might not work on Lambda - depends on your development environment. In this case I recommend using Docker to create the archive (see below).

Zappa挂接到您的virtualenv中,以压缩Python依赖项。 许多流行的库(例如numpy)都包含编译后的C代码以提高性能。 当您pip install numpy ,您将获得当前环境(在我的情况下为MacOS)的已编译二进制文件。 这些二进制文件可能不适用于在Linux环境下运行的Lambda。 所以很显然,天真地打包一个virtualenv是行不通的。 为了解决这个问题,Zappa为受欢迎的Python软件包提供了一个预编译二进制文件姐妹存储库,并在构建归档文件时交换了这些二进制文件。 如果将依赖项与不在此列表中的已编译二进制文件一起使用,则它可能不适用于Lambda-取决于您的开发环境。 在这种情况下,我建议使用Docker创建档案(请参见下文)。

Zappa addresses cold starts by periodically invoking the Lambda function to keep a server warm. This fixes one of the most common complaints with serverless functions wherein requests are slow after the app hasn’t been used in a while.

Zappa通过定期调用Lambda函数来保持服务器正常运行,从而解决了冷启动问题。 这解决了无服务器功能中最常见的问题之一,该功能在一段时间未使用该应用程序之后请求很慢。

Here I’ll go over how to handle a few common use cases with Zappa:

在这里,我将介绍如何使用Zappa处理一些常见用例:

部署应用程序代码 (Deploy application code)

More or less just follow the docs.

或多或少地遵循文档

  • pip install zappa in your virtualenv (if you don't use virtualenv, keep reading)

    pip install zappa在您的virtualenv中pip install zappa (如果您不使用virtualenv,请继续阅读)

  • Run zappa init to get a zappa_settings.json file. Mine looks like this for a Flask app:

    运行zappa init以获取zappa_settings.json文件。 我的Flask应用程序看起来像这样:

I recommend using exclude to keep the size of your archive down. Zappa supports large projects but don't be tricked into thinking you need this, when in reality your archive is full of non-Python code.

我建议使用exclude来减小档案的大小。 Zappa支持大型项目,但是请不要误以为您需要这样做,而实际上您的存档中充满了非Python代码。

存储秘密 (Store secrets)

Most web apps don’t exist in isolation; they need to talk to other services, such as a database, and need to store secrets to do this. If you have a small number of secrets that don’t change often, the most straightforward approach is to set them in the Lambda console.

大多数Web应用程序都不是孤立存在的。 他们需要与其他服务(例如数据库)进行对话,并且需要存储机密信息才能执行此操作。 如果您的秘密很少更改,那么最直接的方法是在Lambda控制台中设置它们

Image for post

This makes the values available in the Lambda runtime environment, so you can read them into your application like normal:

这使这些值在Lambda运行时环境中可用,因此您可以像平常一样将它们读入应用程序:

import os


DATABASE_URI = os.environ.get(
    "DATABASE_URI", "postgresql://postgres:postgres@postgres:5432"
)

If you have too many secrets and prefer to manage them programmatically, you can also write them to a file in S3 that your service reads and extracts the values from at startup.

如果您有太多机密,并且希望通过编程方式进行管理,则还可以将其写入S3中的文件中,以便服务在启动时从中读取并提取值。

初始化/迁移数据库 (Init / migrate the database)

Now that we have the DB secrets available, we want to initialize and migrate the database. I used Amazon RDS for my DB. While it’s possible to spin up an EC2 instance and run the migration commands there, that defeats the purpose of not having to manage servers. Zappa allows you to run any function in your app using zappa invoke, so let's use that.

现在我们有了可用的数据库秘密,我们想要初始化和迁移数据库。 我将Amazon RDS用于我的数据库。 虽然可以启动EC2实例并在其中运行迁移命令,但这使不必管理服务器的目的无法实现。 Zappa允许您使用zappa invoke来在应用程序中运行任何功能,因此让我们使用它。

  • First you need the function to execute in the right VPC and with the appropriate security groups that allow it to connect to the DB. I had to add this the "dev" section of my zappa_settings.json:

    首先,您需要该功能在正确的VPC上执行,并具有允许其连接到数据库的适当安全组。 我必须在zappa_settings.json"dev"部分添加它:

"vpc_config" : {
    "SubnetIds": [ "my-subnet" ], 
    "SecurityGroupIds": [ "my-security-group" ]
}
  • Next, run the script. I started with zappa invoke dev 'db_utils.create_schema_and_tables' to initialize the schema and tables, and zappa invoke dev 'db_utils.seed_db' to seed the DB with some testing data. You can run a similar command to migrate the DB. Make sure those functions connect to the DB using the environment variables mentioned above.

    接下来,运行脚本。 我从zappa invoke dev 'db_utils.create_schema_and_tables'初始化架构和表开始,然后zappa invoke dev 'db_utils.seed_db'为DB提供一些测试数据。 您可以运行类似的命令来迁移数据库。 确保使用上述环境变量将这些功能连接到数据库。

For Django projects, Zappa supports execution of management commands.

对于Django项目,Zappa支持执行管理命令。

提供静态文件 (Serving static files)

A common setup for web apps is to serve the frontend and backend on the same server. There’s a reverse proxy web server, such as nginx, that sits in front of the WSGI / ASGI Python server. The reverse proxy, which is very fast, will serve the static files itself and forward other requests to the Python server.

Web应用程序的常见设置是在同一服务器上提供前端和后端。 在WSGI / ASGI Python服务器的前面有一个反向代理Web服务器,例如nginx。 反向代理非常快,它将提供静态文件本身,并将其他请求转发到Python服务器。

Since requests for static files never hit the Python code, these files could be served from some other location.

由于对静态文件的请求从未打过Python代码,因此可以从其他位置提供这些文件。

With Lambda, you don’t have access to the underlying web server and therefore can’t give special treatment to static files. This leaves you with two options:

使用Lambda,您无权访问基础Web服务器,因此无法对静态文件进行特殊处理。 这给您两个选择:

  1. Serve the static files through Python code, which may be slow

    通过Python代码提供静态文件,这可能会很慢
  2. Serve the static files from a separate service, like S3 or CloudFront

    从单独的服务(例如S3或CloudFront)中服务静态文件

Either should work, but I went with option 2 because it’s clean, easy, and performant.

两者都应该起作用,但是我选择了选项2,因为它干净,容易且性能良好。

There are many guides on the internet for static web hosting using S3, so I won’t repeat them here. However, I’ll zoom into a couple issues that are often left out.

互联网上有许多使用S3进行静态Web托管的指南 ,因此在此不再赘述。 但是,我将放大几个经常遗漏的问题。

服务器端渲染 (Server side rendering)

Single page applications (SPAs) typically send the client a Javascript bundle that creates the HTML for the app. Since not all web crawlers can execute Javascript code, the crawlers only see a barebones HTML page that says “load App.js”. This means websites that are rendered exclusively on the client will struggle with SEO, since search engines cannot index all of their content.

单页应用程序(SPA)通常向客户端发送一个Javascript捆绑包,该捆绑包可为该应用程序创建HTML。 由于并非所有的Web搜寻器都可以执行Javascript代码,因此搜寻器仅看到标有“ load App.js”的准系统HTML页面。 这意味着,专门在客户端上呈现的网站将难以使用SEO,因为搜索引擎无法索引其所有内容。

To improve this people use server-side rendering (SSR), where some or all of the HTML is rendered on the server. This makes the site SEO-friendly and faster for the initial page load.

为了改善这一点,请使用服务器端呈现(SSR),其中一些或所有HTML都在服务器上呈现。 这使站点对SEO友好,并且可以更快地进行初始页面加载。

Server-side rendering usually means you need a Node.js backend that can execute JavaScript code. While it looks possible to do SSR with a Python backend, I’m not sure if Lambda gives you enough control to set that up. You should investigate more before committing down this path.

服务器端渲染通常意味着您需要可以执行JavaScript代码的Node.js后端。 虽然看起来可以使用Python后端进行SSR ,但我不确定Lambda是否为您提供了足够的控制权来进行设置。 您应在进行此操作之前进行更多调查。

客户端路由 (Client side routing)

SPAs use client-side routing to prevent full page reloads as the user navigates through the site. When a user clicks on a link to get a “new page”, the page itself remains the same but JS replaces the contents of it.

SPA使用客户端路由来防止在用户浏览站点时重新加载整个页面。 当用户单击链接以获取“新页面”时,页面本身保持不变,但JS替换了其中的内容。

With static hosting in S3, client-side routing works mostly as expected…until you refresh the page when you aren’t on the home page. The browser sees a URL like /foo and looks for foo.html in the S3 bucket. This file doesn't exist since the contents of the page are created by Javascript running in the browser.

在S3中使用静态托管时,客户端路由通常可以按预期工作……直到您不在主页上时刷新页面为止。 浏览器会看到/foo类的URL,并在S3存储桶中查找foo.html 。 该页面的内容是由浏览器中运行的Javascript创建的,因此该文件不存在。

There are a couple solutions: set the error document to index.html or configure the routing rules.

有两种解决方案: 将错误文档设置为index.html配置路由规则

CORS (CORS)

Since your frontend and backend live on different servers, you’ll need to enable cross-origin resource sharing on the backend server. This is straightforward with existing plugins like Flask-Cors.

由于前端和后端位于不同的服务器上,因此您需要在后端服务器上启用跨域资源共享。 使用Flask-Cors之类的现有插件,这很简单。

调试 (Debugging)

Logs are available in CloudWatch, but I recommend running zappa tail and keeping it open while developing to get the latest logs. You can also configure an exception handler function that will send unhandled exceptions to your application monitoring tool.

日志在CloudWatch中可用,但是我建议运行zappa tail并在开发时保持打开状态以获取最新日志。 您还可以配置异常处理程序功能,该功能会将未处理的异常发送到应用程序监视工具。

One word of caution: Zappa’s default is to time out if a function doesn’t return output within 30 seconds. The timeout messages are generic and easy to miss. So if you start seeing weird behavior, it’s possible something timed out. For example, I saw a post about how someone’s migration script takes >30 seconds to run, so Zappa timed it out and it didn’t finish migrating the DB. Look out for this and configure the setting accordingly.

请注意:Zappa的默认设置是:如果某个函数在30秒内未返回输出,则超时。 超时消息是通用消息,很容易丢失。 因此,如果您开始看到怪异的行为,则可能是超时。 例如,我看到了一篇关于某人的迁移脚本如何运行> 30秒才能运行的文章,因此Zappa超时了,并且迁移数据库还没有完成。 请注意这一点,并相应地配置设置。

Docker用户 (Docker users)

I like developing in Docker containers. They’re portable and I have the assurance that my development environment is exactly the same as the production environment. Related to this, I have two gripes about Lambda / Zappa:

我喜欢在Docker容器中进行开发。 它们是便携式的,我可以保证我的开发环境与生产环境完全相同。 与此相关的是,我对Lambda / Zappa有两种看法:

  1. If you aren’t developing on Linux, your development environment will be different than the runtime environment.

    如果您不是在Linux上进行开发,则开发环境将与运行时环境不同。
  2. Although Lambda allows building the package from Docker, Zappa only works with virtualenvs. This adds an extra step as I have to create a virtualenv, whereas normally I pip install directly into the container.

    尽管Lambda 允许从Docker构建软件包 ,但Zappa仅适用于virtualenvs。 这增加了一个额外的步骤,因为我必须创建一个virtualenv,而通常我会直接将其pip install到容器中。

As mentioned above, Zappa maintains a list of precompiled binary extensions and swaps out your binaries for Lambda-compatible equivalents. This is usually fine. However, you might find yourself using a dependency that ships with binary extensions but isn’t popular enough to make the list. Then you’ll wish for a better development environment.

如上所述,Zappa维护一个预编译的二进制扩展名列表,并将您的二进制文件换成与Lambda兼容的等价物。 这通常很好。 但是,您可能会发现自己使用了具有二进制扩展名的依赖项,但是依赖项不足以列出该列表。 然后,您将希望有一个更好的开发环境。

Docker to the rescue! There’s a Zappa Docker Image, which is based off of the LambCI Lambda Docker Image that provides a Lambda-like environment in Docker. You can use it as your base image.

Docker营救! 有一个Zappa Docker映像 ,它基于LambCI Lambda Docker映像 ,该映像在Docker中提供了类似Lambda的环境。 您可以将其用作基本图像。

In the future, I hope Lambda will accept an arbitary Docker image. Other clouds already do this.

希望将来Lambda能够接受任意的Docker映像。 其他云已经做到了这一点。

结论 (Conclusion)

This article was a brain dump of what I learned using Zappa, and I hope it was useful for you. We talked about when to use Zappa and how to migrate a DB, store secrets, serve a frontend, and get a reproducible dev environment.

这篇文章是我使用Zappa所学到的知识的转储,我希望它对您有用。 我们讨论了何时使用Zappa以及如何迁移数据库,存储机密信息,服务于前端以及获得可重现的开发环境。

I recommend Zappa for individuals or small teams that want to focus on application code instead of infrastructure. It was great for deploying a side project to the internet and not having to monitor it. If nobody pings my web app until a year from now, it should still be there and I’ll have paid almost nothing for compute. At scale, cost becomes a consideration and managing a cluster still makes sense.

对于那些希望专注于应用程序代码而不是基础结构的个人或小型团队,我建议使用Zappa。 非常适合将附带项目部署到Internet,而不必对其进行监视。 如果直到一年后没有人ping我的Web应用程序,它仍然应该存在,而我几乎不会为计算支付任何费用。 从规模上讲,成本成为考虑因素,并且管理集群仍然有意义。

If you have any comments, message me on Twitter! I’d love to hear about your experience using Lambda and Zappa.

如果您有任何意见,请在Twitter上给我发消息! 我很想听听您使用Lambda和Zappa的经历。

Originally published at https://www.sanjaysiddhanti.com.

最初在 https://www.sanjaysiddhanti.com上 发布

翻译自: https://medium.com/python-in-plain-english/serverless-web-apps-in-python-4efa9754c513

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值