Deploying a Serverless Flask App with Zappa and Amazon RDS

Created on Aug 23, 2022

Deploying a serverless application has become easier with Zappa. If you have a Flask application and you want to ship it quickly and host it on a public URL so that it can be accessed from the Internet, Zappa can help you with that.

Zappa is a Python library that allows you to deploy serverless applications to AWS Lambda and API Gateway. It also has a CLI that allows you to manage your deployment with the configuration set up in your zappa_settings.json file.

But What do we mean by “serverless”?

Serverless is a bit of a buzz word. Let’s break it down.

Serverless does not mean there is no server behind the scenes. It means that the application is running on AWS Lambda and API Gateway, without any permanent infrastructure.

With a traditional server, you have to deploy your application to a server that is running 24/7, and you have to pay for that server and its operating costs even when you don’t use it. With serverless using Zappa, you don’t have to pay for your infrastructure that you don’t use because you only pay for the time you use your application. This is a huge saving especially if you want to scale your app.

With traditional HTTP servers, if the queue of the incoming HTTP requests is full, the server will stop responding to new requests and will time out. With serverless Zappa, Amazon API Gateway gives each request its own virtual HTTP server. And as the documentation says, AWS handles the horizontal scaling automatically, so no requests ever time out.

Zappa is a great tool to deploy serverless applications with frameworks like Flask and Django. One of the best benefits of Zappa is that you often don’t need to change your existing applications to use it.

In this tutorial, I’ll show you how to deploy an existing Flask application to Zappa. This app is a social blogging platform that you can use to publish blog posts and communicate with other users.

Preparing your desired Flask app

I’ve forked the app and made two changes; one change which is upgrading/downgrading some libraries to solve circular dependencies. I’ve named this file: zappa_requirements.txt and added Zappa as a requirement to install.

Note that fixing the circular dependencies is unrelated to Zappa.

I’ve also made another change which is related to Zappa. I added a zappa_settings.json file to the root of the repository.

Let’s now clone the forked repository and cd into the directory:

$ git clone https://github.com/EzzEddin/flasky.git
$ cd flasky

and then install the requirements after creating a new virtual environment:

$ python3 -m venv venv
$ . venv/bin/activate
$ pip install --upgrade pip
$ pip install -r zappa_requirements.txt

Prerequisites

In this tutorial, it’s preferred to use Python 3.7.9 and pip 21.2.4 on a Linux or a Mac machine.

It’s assumed that you’ve installed AWS CLI and you have the credentials already set up. If you haven’t installed it yet, revise the AWS documentation for doing it.

Configuring your Flask app

Flasky is a social blogging application that you need to configure and set up your desired database settings. In this tutorial, let’s use MySQL as the database engine and make sure it’s running on the localhost and then we can move to Amazon RDS and host our application on AWS.

Let’s first set up the database URL which includes the database name, the database user name, password as an environment variable:

$ export DEV_DATABASE_URL=mysql+pymysql://<user_name>:<password>@<endpoint>:3306/flaskapp

where:

If you want to create a new MySQL database for your application, you can open a new terminal and run the following command:

$ mysql -u root -p
# write your password
$ create database flaskapp;

Notes:

Now, flaskapp database is created. Note I’ve used the root user name while you can use your user name that you set up already in MySQL server (if you have one).

Before running the Flask application, you need to create the tables used in the application to be in the database. To do that, let’s define first the main entry point of our Flask app using the following command:

$ export FLASK_APP=flasky.py

and then open a Flask shell using flask shell and run the following command:

>>> db
<SQLAlchemy engine=mysql+pymysql://root:***@localhost:3306/flaskapp?charset=utf8>
>>> db.create_all()

As you can see, db is the database instance that is created in the Flask app. The command db.create_all() creates all the tables in the database.

Side note: We’re able to use db here immediately and not have to worry about importing it from flasky.py file because we’ve already returned it in the dictionary that exist inside the make_shell_context() function wrapped in the decorator: @app.shell_context_processor.

Now, we’re ready to run the Flask application. Let’s run the following command:

$ flask run

You can sign up to the application and start posting your blog posts.

Feel free to populate the database with some dummy data. Let’s open a new terminal and open a Flask shell and run the following command:

>>> from app import fake
>>> fake.users(100)
>>> fake.posts(100)

Now, there are 100 fake users created and 100 fake posts are populated in the database.

Configuring Amazon RDS

The documentation for connecting MySQL instance on Amazon RDS is here.

RDS database

RDS database configuration

MySQL version and free tier RDS template

RDS db name and user name and password

RDS instance type

RDS public access

RDS port 3306

RDS database created

Let’s create a new environment variable for the new endpoint of the RDS MySQL database instance:

$ export DEV_DATABASE_URL=mysql+pymysql://<user_name>:<password>@<rds_endpoint>:3306/flaskapp

where:

Note that flaskapp is not the same as the database name that we created in the previous step when we were testing our Flask application locally.

That’s why we need to create a new database instance on RDS endpoint with the following command:

$ mysql -h ...rds.amazonaws.com -P 3306 -u admin -p
# write your password
mysql> create database flaskapp;
Query OK, 1 row affected (0.16 sec)

Configuring Zappa

Now that we have our database set up on RDS, let’s set up Zappa to deploy our Flask application on AWS.

First the Zappa package is already installed on your virtual environment. Now, you don’t need to run zappa init because it will just create a new config file and in our case it’s already there. This config file is the zappa_settings.json

So you’re ready to move on and deploy your application to dev (which is the key name of the zappa_settings.json file).

$ zappa deploy dev

But what does zappa_settings.json file contain?

This file contains the configuration for the Zappa deployment. In our case, it contains the following information:

{
    "dev": {
        "app_function": "flasky.app",
        "profile_name": "default",
        "project_name": "flasky",
        "runtime": "python3.6",
        "aws_region": "us-east-1",
        "environment_variables": {
            "DEV_DATABASE_URL": "mysql+pymysql://<user_name>:<password>@<rds_endpoint>:3306/flasky"
        }
    }
}

where the the value of the “app_function” key is “flasky.app” which is the name of the file that contains the Flask application (in our case, flasky.py) followed by the Flask instance name (in our case, app).

The other keys are self-explanatory like the environment variable DEV_DATABASE_URL that contains the database endpoint we set up for RDS instance.

When you deploy this application with Zappa, you might get an error like the following:

Error: Warning! Status check on the deployed lambda failed. A GET request to '/' yielded a 502 response code.

So to figure this out, you need to debug the application and see why the status check failed. Use zappa tail to see the logs of the application and see more verbosity that will be more helpful.

You’ll see a similar error message to “Can’t connect to MySQL server on ‘<rds_endpoint>'” which means that the database endpoint is not reachable through Zappa. You can fix this by editing the inbound rule of the security group in the VPC that you selected for your RDS instance.

So select the security group on your RDS instance and open the inbound rules tab and click on “Edit inbound rules” button. Edit the existing rule to have the type “MySQL/Aurora” and 0.0.0.0/0 for the source to allow all traffic. Then click on “Save changes” button.

RDS inbound rules

Warning: this is still not the best practice for security reasons. You might have to change this later if you’re going to use the app on prod.

Now you figured out the error and it’s fixed. Let’s update the zappa deployment with the update command:

$ zappa update dev

Congratulations! You have successfully deployed your Flask application on AWS. Here is the message returned by Zappa from the last command:

Your updated Zappa deployment is live!: https://ujw6bevk95.execute-api.us-east-1.amazonaws.com/dev

which contains the endpoint of the deployed application.

Flasky hosted by Zappa

Conclusion

We have successfully deployed our serverless Flask application on AWS using Zappa and connected it to our database on RDS.

We covered how to configure Flask locally and set up a MySQL database on Amazon RDS. We also saw common practices to use Zappa for deployment and fixed a possible bug in the deployment process.

This post is distributed under CC BY-NC-SA 4.0 license and originally published at Mattermost.