Deploying Django Apps in Serverless Using Zappa – Part Two

In the previous article, we discussed the basic concepts of Serverless Architecture. Serverless is the type of architecture in which your apps are hosted on a cloud platform without all the work related to server management. It means that all the developers can focus entirely on writing the code without having to worry about managing servers that including scaling, provisioning, upgrading, and applying security patches. 

In this article, we will discuss how we can deploy a Django application on AWS using serverless architecture. This guide requires you to have basic knowledge about how Django works. And you should have knowledge about some AWS services like Lambda and AWS Aurora Serverless.

We will deploy a Django application on AWS Serverless using a package called Zappa.

What is Zappa

When discussing deploying Django applications on serverless, the first thing that comes to my mind is Zappa. Zappa is a wholesome package that includes every possible utility that you need to deploy your application serverless. From Global app deployment to free SSL certificates, from API access management to automatic security policy generation and then keeping the server warm, Zappa has it all. The best thing about Zappa is that it wraps your whole Django application into a Lambda function which can be easily hosted and deployed on AWS.

Let’s discuss some advantages of using Zappa (serverless):

Scalability

Serverless comes with some important advantages over traditional web servers. The first one is Scalability, Zappa deploys your application in AWS Lambda and Lambda has the power to handle as many parallel requests as you need by scaling up to executing 100 Lambda functions in 1 second. If you think this is not enough for you, you can ask AWS to raise your limit.

Maintenance

Zappa is also very easy to configure and then the deployment of your whole application is just a command away. Just run Zappa deploy production and your code will be deployed on your production environment after the deployment, you will not have to worry about its scalability, provisioning, or updating the servers, AWS does it all! 

Availability

AWS ensures all its services are available all the time with the lowest possible downtime, including Lambda. This ensures that our server will be available all the time and you don’t have to worry about power cut-off or other server downtimes. Additionally, if more power is needed for your server, AWS will automatically provision more Lambda functions to meet your needs.

Let’s start working with Zappa and see its glory:

Configuring Environment

Configuring AWS

Before using AWS, we have to set up an AWS environment in our local machine for Zappa to work properly. Firstly, you have to make a directory in the root called .aws

 $ mkdir .aws

Now we have to store our credentials aws_access_key_id and aws_secret_access_key. In order to do this, we have to create a credentials file. To get the credentials you have to follow these steps:

  • In AWS Console, go to IAM Dashboard
  • Click on Users
  • Then click on your username
  • Go to the security credentials tab
  • Scroll down to Access Keys
  • Note down the access_key_id. Remember, the secret_key will only be visible if you are creating the user for the first time or creating new access credentials. You have to note it down before closing the tab.
  • Now in the ~/.aws/credentials file write down these credentials
[default]
aws_access_key_id=XXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXX

Default here is the profile name. If you are using multiple profiles you can add its access_key_id and secret_access_key_id in the same file.

[default]
aws_access_key_id=XXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXX

[other-profi]
aws_access_key_id=XXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXX

Configuring Zappa in Django Application

After configuring AWS credentials we have to configure the Zappa package in our Django application. In order to do this, go to your Django app and run the following commands.

$ pip install zappa

After installing Zappa, let’s configure it

$ zappa init

After running this command, you will be prompted for some configurations, let’s start with that

  1. First of all, you will be asked for the name of your environment. We are setting it up for staging first, so we will pass staging
  2. Next, Zappa will ask about the name of the S3 bucket in which the code will be deployed. If the bucket with this name does not exist, Zappa will automatically create that. You probably are wondering why using an S3 bucket when you are using serverless and all the code will be deployed on AWS Lambda. Zappa temporarily holds the package in the S3 bucket while deploying, after the deployment is completed, the package is automatically removed from the bucket.
  3. Next Zappa will ask you about the path of your Django settings file

Zappa will automatically detect your python runtime and will set the configuration accordingly.

After completing the configuration, you will see that a file named zappa_settings.json is created at the root of your project. This file holds all the configurations related to the deployment of your application. The file will look like this:

{
  "staging": {
    "django_settings": "mysite.settings",
    "profile_name": "default",
    "project_name": "mysite",
    "runtime": "python3.6",
    "s3_bucket": "zappa-s3"
  }
}

After this, before we deploy, we have to mention the aws_region in which we want to deploy our code. Remember, if you are creating the S3 bucket manually then the bucket should be in the same region.

{
  "staging": {
    "django_settings": "mysite.settings",
    "profile_name": "default",
    "project_name": "mysite",
    "runtime": "python3.6",
    "s3_bucket": "zappa-s3",

    "aws_regions": "us-east-2"
  }
}

This is the final configuration for Zappa deployment. Now let’s deploy our code. The deployment of the command is “Zappa deploy <environment-name”. So in our example, our command will be:

$ zappa deploy staging

After the deployment has finished, Zappa will display a link (https://jshrtslaksfj.execute-api.us-east-2.amazonaws.com/staging) to open your application in the browser. After you open the link you can see an error page that shows that the link from which you are trying to access your application is not allowed. So you can just copy your link (jshrtslaksfj.execute-api.us-east-2.amazonaws.com) and add it to the ALLOWED_HOSTS in your settings.py file.

ALLOWED_HOSTS = [127.0.0.1, 'jshrtslaksfj.execute-api.us-east-2.amazonaws.com']

After updating the settings.py file, you have to update your deployment:

$ zappa update staging

After updating your deployment, if you re-open that link you can see your homepage.

Moving Your Static Files to Serverless

When you visit your application, the first thing you will notice is that there are no styles or images displayed. This is because our code is running on Lambda function and there is no way we can store our static files to Lambda or serve them from there. So we will have to serve our static files from somewhere else.

S3 to The Rescue

We will be using our S3 bucket to serve our static files for us. We will upload all the static files to the S3 bucket and use S3 links in our application. Don’t worry we can use the same bucket for our deployment and hosting our static files. As our deployment package is deleted after deployment is complete so we can use that bucket to store our static files. In order to do this, we have to use a third-party package called Django Storages. Django storages provide storage libraries for multiple storage providers like Amazon S3, Azure Storage, DigitalOcean, Dropbox, Google Cloud Storage, etc. we will use its S3 storage class.

To install Django storage using pip you have to run the following commands:

pip install django-storages

After this we have to add storage to our INSTALLED_APPS:

INSTALLED_APPS = [
 ...
 'storages'
]

After this, we have to create a python file called storages.py at the same level as our settings.py file or you can create it anywhere else.

# storages.py

from storages.backends.s3boto3 import S3Boto3Storage

class StaticStorage(S3Boto3Storage):
    location = 'static'

After creating the file, we have to add some configurations in our settings.py file:

# settings.py

AWS_ACCESS_KEY_ID = XXXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY = XXXXXXXXXXXXXXXXXXXXXXXXXXx
AWS_STORAGE_BUCKET_NAME = 'zappa-s3'
AWS_S3_REGION_NAME = 'us-east-2'
AWS_S3_SIGNATURE_VERSION = 's3v4'

STATICFILES_STORAGE = 'mysite.storage.StaticStorage'
STATIC_URL = 'https://' + AWS_S3_CUSTOM_DOMAIN + '/static/'

This is it! Now Django will use S3 storage for our static files storage and will generate all links for static files from the S3 bucket. Now to upload static files in the S3 bucket you have to run the following command:

python manage.py collectstatic

This will upload all your static files to your bucket. After that, you can update your deployment using Zappa update staging.

Now when you will revisit your application, you will see all your styles and images are back and your application is working properly.

Looking for a Development Team?

Share the details of your request and we will provide you with a full-cycle team under one roof.

Get an Estimate

Integrating The Database With Your Application

No application is complete without a database. So to use a database in our application we will be using AWS Aurora Serverless v2 which is a PostgreSQL-compatible database management system provided by AWS for Serverless.

Now we will create an AWS Aurora cluster that is PostgreSQL-compatible and we will use that in our application. For a detailed guide on How to create an AWS Aurora cluster, you can follow this guide. Just in the VPCs and Subnet Groups section, select to create new VPC and Subnet groups.

Select PostgreSQL as the Edition and fill in the Master username and password and remember them so we can use them for connecting.

After the cluster is created, we have to configure our Lambda function to access our cluster. To do this, follow the following steps:

  • Go to the Lambda console and click on our deployed Lambda function
  • Click on the Configurations tab, under the Network section, in VPC, and select the VPC that your cluster is using. This is important because Lambda and RDS clusters should be in the same VPC to access each other.
  • Select the same Subnets as the RDS cluster.
  • And for security groups, select a different security group than your RDS cluster. 

After following the above steps you still won’t be able to connect Lambda with your cluster because of the security issues. To resolve these issues, go to the Security groups console and select the Security group used by your cluster. To find which security group is being used in a cluster you can check it from the RDS console, by selecting your cluster, AWS will display all the details including the security group id. 

After selecting the security group, go to the Inbound Rules tab, click on Edit Inbound Rules and add a new Rule. In the ‘type’ column, select ‘PostgreSQL’ then in the ‘Source’ column, select the security group used by your Lambda function and click on Save.

After saving this, select the Security Group used by your Lambda function and follow the same procedure to add a new Rule to allow access from the RDS cluster security group.

After completing all the configurations, we have to prepare our application to use the PostgreSQL database. Change your DATABASES configuration in your settings.py file to this:

DATABASES = {
    'default': {
        'ENGINE': 'django_db_cascade.backends.postgresql_psycopg2',
        'NAME': 'your-database-name',
        'USER': 'your-master-username',
        'PASSWORD': 'your-master-password',
        'HOST': 'cluster-endpoint-url',
        'PORT': 5432, # default for PostgreSQL
    }
}

After this, you have to create a database in your cluster for your application to work. For this, you have to write a management command in any of your apps named create_db.py.

from django.core.management.base import BaseCommand
import psycopg2

class Command(BaseCommand):
      def handle(self, *args, **kwargs):
          conn = psycopg2.connect(host='your-cluster-endpoint', user='master-username', password='master-password')
          c = conn.cursor()
          c.execute('create database <your-database-name-from-settings-file>;')
          c.close()

Now let’s update Zappa:

$ zappa update staging

After the update, run the management command:

$ zappa manage staging create_db

After running the management command, you can run all the migrations on your database:

$ zappa manage staging migrate

When the migrations are done, you will have a working Django application with full compatibility with Serverless Architecture.

Share this article

Leave a comment