When writing a Proof of Concept or sharing an idea on an application with a web interface, you usually don’t want to put much time and effort into the application itself. For such instances, building an AWS Serverless Python Web app based on Docker will help you to quickly develop a lightweight demo which, after sign-off, you can easily move to a more appropriate production environment. What’s more if it doesn’t go to materialization, you won’t be charged by your cloud provider if the application is not running. Here are the tools and technologies involved:
- Serverless refers to a framework for building web apps without going into the configuration or provisioning of servers. The servers are managed by a cloud provider. This makes the application to run in a stateless compute containers that are ephemeral and event-triggered. That means infinite scaling, zero downtime, zero maintenance – and at a fraction of the cost of your current deployments!
- Python is simple programming, easy to use, flexible and has a well-structured syntax makes it a top choice for companies.
- Flask is a web microframework python library. It helps develop web applications fast using templates technologies as Jinja2.
- AWS is the most popular cloud service, and it has great python SDK libraries like boto3.
- AWS lambda is a function service, which is used only when executed and has access to all AWS resources like S3, database services, etc. But it has a limitation of 250Mb of space. When we load python libraries on it, it can have a space limitation, but when lambda pulls a docker image to run as an ephemeral container, the storage limitation is 10Gb! Besides this lambda space enhancement when using docker, a docker image is portable across different OS and cloud providers , making it a top choice in agile environments.
Now let’s bring all these wonderful technologies together using Python and Zappa!
Prerequisites – Ingredients for the Zappa recipe
- Windows / Linux or Macos with python >=3.6 already installed
- AWSprogrammatic account (is a different account than the one used to login via GUI , link to roles of this account are below in the document, as api gateway, lambda and s3 are needed)
- Flask and Zappa libraries on a virtual environment
- A small flask web app is handy or you can use the hello world from flask
- Docker installed
Zappa is a great open-source Python library that can help build a serverless Flask/Django/Bottle (WSGI) web app in AWS. It does a lot of the heavy lifting regarding the AWS configuration:
- Creates a package zip, the lambda function, the api gateway, configures the lambda with a keepalive to keep it warm and avoid cold starts, etc.
All you need to do to run your first Flask app, is to run 2 commands: Zappa init and Zappa deploy. But before we can run those commands let’s create a quick virtual environment with Flask and Zappa.
The clock starts now! 00:00
</p>
Python3 -m venv venv
Source venv/bin/activate
Pip3 install zappa Flask
<p>
That’s it! Now that we are in a virtual environment with the python libraries Flask and Zappa installed, let’s create a ‘Hello World’ Flask web app.
Create an app.py with this text in it:
</p>
from flask import Flask
app = Flask(__name__)
@app.route(\"/\")
def hello_world():
return \"<p>Hello, World!</p>\"
<p>
Test it with the command flask run, usually runs on http://localhost:5000. Once you checked it\’s working, hit control-c to go back into the virtual environment terminal.
Let’s go ahead and create the zappa_settings.json via the Zappa init command.
Zappa init will automatically detect your Flask or Django app, it will ask some questions and as a result will create a similar zappa_settings.json for WSGI apps:
{ // The name of your stage \"dev\": { // The name of your S3 bucket \"s3_bucket\": \"lambda-zappa-1234\", // The modular python path to your WSGI application function. // In Flask and Bottle, this is your \'app\' object. // Flask (your_module.py): // app = Flask() \"app_function\": \"app.app\" } }
Once created you can deploy the web app using: Zappa deploy dev. In order to be able to run this command, your aws programmatic user needs to be already configured in your local .aws directory credentials file. Check this page for users\’ and roles\’ setup of this programmatic user.
Once Zappa completes successfully it will result in a web endpoint that you can directly use or configure via api gateway and route53 to point to a domain or subdomain.
Congratulations! You first Zappa Python AWS web up is Live!
There is also a Docker way. The latest Zappa version allows to use an ECR registry docker image. In the future it might also upload the image, but for now the image needs to exist in the registry.
It is called the same way but with a -d :
zappa deploy dev -d –docker-image-uri
After Zappa deploys the Docker image on lambda, configuring also the API gateway, you will be able to see the web url after the “Deploy Complete” message. You can copy and paste this url on any browser with internet connection, your web application is up on AWS!
This is an example of a Dockerfile for the purpose, it is important for the handler path:
FROM amazon/aws-lambda-python:3.8 ARG FUNCTION_DIR=\"/var/task/\" COPY ./ ${FUNCTION_DIR} # Setup Python environment RUN pip install poetry RUN POETRY_VIRTUALENVS_CREATE=false poetry install --no-root # Grab the zappa handler.py and put it in the working directory RUN ZAPPA_HANDLER_PATH=$( \\ python -c \"from zappa import handler; print (handler.__file__)\" \\ ) \\ && echo $ZAPPA_HANDLER_PATH \\ && cp $ZAPPA_HANDLER_PATH ${FUNCTION_DIR} CMD [ \"handler.lambda_handler\" ]
With our Dockerfile ready, we can now build it in two steps. From the root of the repository, you can run:
zappa save-python-settings-file lambda_docker_flask
docker build -t lambda-docker-flask:latest .
Now you can make this docker image live as an aws web via:
zappa deploy dev -d –docker-image-uri
As promised, a docker serverless container was setup in 3 minutes and is ready to run on AWS!
In the future, Zappa might upload/update the image on ECR directly, stay tuned on https://pypi.org/project/zappa/ !