如何在AWS上用Zappa部署无服务器Django REST API

494 阅读9分钟

在AWS上用Zappa部署无服务器Django REST API

无服务器技术已经逐渐成为软件开发领域的一个关注点。之前,他们手动管理所有建立在经典网络服务器上的应用程序,直到这项技术的发展。

这种技术保证了网络服务器的自动配置和权限,使开发者可以完全专注于开发和设计网络应用,而他们的云供应商通过管理服务器来处理繁重的任务。

为此,用户不必担心手动配置服务器的问题。无服务器技术的主要目的是帮助开发者在不与服务器互动或管理服务器的情况下构建和运行应用程序。

现在,这并不意味着应用程序完全在没有服务器的情况下运行,但服务器的管理将由亚马逊网络服务(AWS)通过一个被称为无服务器应用程序模型(SAM)框架的开源项目处理。

无服务器技术的一个好处是,它是按请求付费运行的。例如,预算不足的新公司或创业公司可以将其网络应用托管在AWS Lambda上,只在用户向网络应用发送请求时才付费。

AWS Lambda是一个亚马逊无服务器计算平台,使用户能够自动运行功能和管理计算机资源。

本项目将使用的其他AWS服务包括。

  • API网关,用于管理和处理API HTTP端点。
  • S3桶。简单存储服务也被称为S3,用于存储数据,如静态文件。
  • IAM角色,用于存储角色、用户组和策略。

这个过程相当令人兴奋;尽管在Django中的实现可能具有挑战性,但Zappa使其变得简单。

Zappa是一个开源工具,用于在亚马逊网络服务(AWS)技术上开发、部署和维护无服务器的Python应用程序,包括Lambda和API网关

Zappa只需点击一下就能自动处理配置和部署,但首先,你需要通过运行Zappainit ,并使用CLI界面设置一些参数来配置Zappa。

Zappa如何工作

通过Zappa,开发者可以部署一个兼容WSGI的应用程序。网络服务器网关接口(WSGI)是一种网络服务器调用方法,用于发送请求给用Python实现的网络应用。

它描述了网络服务器与Django和Flask等应用程序的通信方式。WSGI使用亚马逊网络服务产品,如Lambda、API网关和S3。

在Django应用程序中,这就是Zappa的工作方式。

  • 当一个请求被发送到服务器时,它被处理HTTP请求的API网关所接收。这个API网关在我们的AWS lambda函数中启动一个实例,服务器在这里被管理。然后Lambda处理这个请求并将其发送到服务器。
  • 接下来,该请求被发送到服务器,Django应用程序通过WSGI层处理该请求。
  • 然后,服务器在销毁前不久将响应传送给API网关,然后为客户端提供响应。

Architecture

本项目将通过构建一个无服务器的Django REST API,并使用Zappa将应用程序部署到AWS Lambda,来研究Zappa如何在Django中实现。

先决条件

  • Python的基本知识。
  • 对[Django]的良好理解。
  • 一个[AWS账户]。

项目设置:建立一个Django REST API应用程序

在这个项目中,我们将创建一个电子书商店,用户可以获得所有书籍的列表,创建新书,编辑和删除书籍。

我们将首先在终端为我们的项目创建一个目录。

mkdir bookstore
cd bookstore

接下来,我们将创建一个虚拟环境来承载我们的项目。这个项目的所有安装包都将包含在虚拟环境中。

使用以下命令创建一个虚拟环境。

pip install virtualenv
virtual env

让我们通过运行以下命令来激活我们的虚拟环境。

对于Windows来说。

env\Scripts\activate

对于Mac/Linux。

source env/bin/activate

接下来,安装Django的依赖项。

pip install django djangorestframework zappa

现在,我们可以创建我们的Django项目并运行该应用程序,如下图所示。

django-admin startproject bookstore
cd bookstore
django-admin startapp ebook

接下来,在你的项目文件夹中,打开settings.py 文件,将rest_framework 以及创建的应用程序的名称ebook 添加到安装的应用程序列表中。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'ebook',
]

创建应用程序模型

这一步将建立一个存储图书信息的模型。模型指定了数据在数据库中出现的方式。

from django.db import models

# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=150)
    author = models.CharField(max_length=100, default='John Doe')
    isbn = models.CharField(max_length=13)
    pages = models.IntegerField()
    price = models.IntegerField()
    quantity = models.IntegerField()
    description = models.TextField()
    status = models.BooleanField()
    date_created = models.DateField(auto_now_add=True)

    class Meta:
        ordering = ['-date_created']

    def __str__(self):
        return self.title

接下来,我们使用这些命令将这些模型迁移到数据库中。

python manage.py makemigrations
python manage.py migrate

然后,我们在你的ebook/admin.py 文件中注册这些模型。

from django.contrib import admin
from .models import Book

# Register your models here.
admin.site.register(Book)

创建一个串行器文件

在你的app目录下创建一个新文件,即serializers.py 文件。

序列化器将我们的模型或queryset中的数据转换为数据类型,如JSON和XML,可以容易地理解。现在添加这几行代码来创建一个序列化器类。

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

创建视图

在你的ebook/views.py 文件中创建你的用户的视图。views 文件处理我们的API HTTP动作的逻辑,向API端点发出诸如GET,POST,UPDATE, 和DELETE 的请求。将这几行代码添加到你的views.py

from rest_framework import generics
from .serializers import BookSerializer
from .models import Book

class BookList(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

class BookDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

BookList视图显示所有书籍的列表,也允许用户创建一个新的书籍。BookDetail,另一个视图,允许用户检索、更新和删除一个特定的书。

创建一个URL处理程序

当用户提出请求时,Django控制器会接管并在urls.py 文件中搜索相应的视图,如果没有找到,则返回响应或错误。

在Django中,"urlpatterns"元组是最重要的元素。这里定义了URL到视图的映射。接下来,在你的应用目录下创建一个urls.py 文件,并添加以下代码。

from django.urls import path
from .views import BookList, BookDetail

urlpatterns = [
    path('api/books/', BookList.as_view()),
    path('api/books/{id}', BookDetail.as_view()),
]

测试API

现在我们可以测试一下API,看看我们所做的工作是否成功运行。要在本地测试,请运行python manage.py runserver ,并在你的浏览器中点击端点http://120.0.0.1:8000/api/books。

设置AWS

到此为止,你应该已经创建了一个AWS账户,并且能够访问Zappa工具的AWS IAM用户。

Zappa实用程序代表你处理一些任务,如自动创建一个s3桶进行部署,创建lambda执行IAM角色,网络流量工作的API网关,以及其他功能。

简而言之,让我们在你的控制台设置AWS,以正确利用Zappa。

  • 登录到您的AWS控制台,进入IAM部分
  • 在屏幕的左侧,点击用户。
  • 点击添加用户。对于这个项目,我们将把我们的 "用户 "命名为*"serverless",*对于访问类型,选择 "程序性访问"。这使用API与AWS互动。
  • 移动到权限上,选择*'直接附加现有政策*'。我们将访问两个政策。第一个是'IAMFullAccess',这为Lambda的执行创造了用户。第二个是*"PowerUserAccess"*,用于创建API网关和S3桶。搜索这些策略并点击它们的方框。
  • 跳过 "添加标签",转到 "审查 "并创建一个用户。

成功地创建了!我们还获得了一个访问密钥和秘密访问密钥。下载包含这些密钥的.csv文件,因为这些信息在页面关闭时将会丢失。

Deployment meme

使用Zappa进行部署

第一步是在我们的虚拟环境中安装Zappa。

pip install zappa

接下来,初始化Zappa。

zappa init

Zappa Init

这个命令初始化Zappa并创建一个zappa_settings.json 文件。一旦该命令在你的终端执行,你将得到以下输出和指示。选择一个环境名称。

我们在这个项目中使用了默认名称,'*dev'。*在这里,Zappa创建了一个用于处理上传文件的桶。我们的Django应用程序将被设置在一个私有的s3桶中。然后,我们通过运行部署。

Zappa configuration

zappa deploy dev

Zappa Deploy

这个命令部署了我们的应用程序,我们命名为'*dev',然而,由于SQLite的配置不当,出现了一个错误。为了解决这个问题,在你的settings.py ,注释掉数据库。

# Database
# <https://docs.djangoproject.com/en/3.2/ref/settings/#databases>

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': BASE_DIR / 'db.sqlite3',
#     }
# }

之后,运行这个命令。

zappa update dev

注意:这个命令更新了对部署所做的修改。因此,每当对你的项目进行修改时,使用该命令来更新部署。

在成功部署后,你应该收到一个URL来通过网络访问你的API。

<https://oitzappv43.execute-api.eu-west-2.amazonaws.com/dev>

复制为你的应用程序生成的URL,并将其粘贴到你的项目的ALLOWED_HOSTS 中。settings.py.

ALLOWED_HOSTS = ["oitzappv43.execute-api.eu-west-2.amazonaws.com"]

现在,我们可以运行这个URL并加载我们的应用程序。

Admin

我们已经成功地重新部署了该应用程序。然而,注意到样式设计没有正确工作。我们没能将我们的应用程序映射到包含样式的CSS上。让我们快速地做到这一点。

管理静态文件

必须维护静态文件,以便在部署阶段操作默认的Django样式,要做到这一点,首先要建立一个唯一的名称。此外,请确保 阻止所有公共访问在创建bucket之前不要勾选。

接下来,在你的桶的 "权限"部分,导航到跨源资源共享(CORS),允许从其他主机访问,编辑文件到这个设置。

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET"],
    "AllowedOrigins": ["*"],
    "MaxAgeSeconds": 3000
  }
]

设置Django静态文件

安装Django s3存储库以与S3协同工作。

pip install django-s3-storage

接下来,在你的settings.py 文件中,将'django_s3_storage' 添加到已安装的应用程序。

INSTALLED_APPS = [
  ...
'django_s3_storage'
]

同时,添加以下内容。

if DEBUG:
   STATICFILES_DIRS = [
   os.path.join(BASE_DIR, 'static'),
   ]
else:
   STATIC_ROOT = os.path.join(BASE_DIR,'static')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
S3_BUCKET_NAME = "Enter the name ofyour bucket"
STATICFILES_STORAGE = "django_s3_storage.storage.StaticS3Storage"
AWS_S3_BUCKET_NAME_STATIC = S3_BUCKET_NAME
# serve the static files directly from the specified s3 bucket
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % S3_BUCKET_NAME
STATIC_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN
# if you have configured a custom domain for your static files use:
#AWS_S3_PUBLIC_URL_STATIC = "<https://static.yourdomain.com/>"

之后,运行下面的命令来更新这些变化,并将静态文件上传到桶中。

zappa update dev
zappa manage dev "collectstatic --noinput"

重新运行管理页面。这时的API应该准确地呈现出所需的样式。

New Admin

正如所见,我们的应用程序正在成功运行。

总结

本文提供了一个关于创建Django REST API和使用AWS Lambda上的Zappa将API部署为无服务器应用程序的操作指南。

在进行AWS上的部署之前,我们首先建立了一个简单的REST API。现在我们对Zappa是什么以及它在Django中的工作原理有了更好的理解。这些知识也可以应用到你的其他项目中,让你轻松构建一个服务器被自动管理的应用程序。