In this post, I’m going to explore 5 ways to deploy a Flask application. In all examples I’m going to use a simple app from Flask docs:
app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
Local machine
This option is used when you need to test your application on a local machine.
By simply running app.py
you spin up a server and can call the endpoints locally, but
this particular scenario help when you need to integrate your app with external service.
Think of a service that sends notifications on the progress of sending an email - you send an email and your email provider calls your API asynchronously to notify you when the email was delivered and opened.
For that use ngrok - the install is pretty easy - https://ngrok.com/download. Now you can run Flask:
➜ python3 app.py
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
In a separate terminal session run:
➜ ./ngrok http 5000
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account Alex Smirnov (Plan: Free)
Version 2.3.35
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://473b0854.ngrok.io -> http://localhost:5000
Forwarding https://473b0854.ngrok.io -> http://localhost:5000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
In the last to lines - Forwarding
- there are 2 URLs (secured and plain) that are accessible form the internet.
Bare metal Linux
In that example you will need:
- nginx - it will proxy incoming requests to uwsgi gateway
- uwsgi - runs Python interpreter in some workers executing app code
- systemd - Linux system that allows to (auto-)start, stop and monitor background processes
Dependencies
On a Debian based system with python3 run these commands
➜ sudo apt-get update
➜ sudo apt-get install python3-pip python3-dev nginx
➜ pip install flask uwsgi
Virtual environment
Create a virtual environment with
➜ mkdir ~/flask_app
➜ cd ~/flask_app
➜ virtualenv env
➜ source env/bin/activate
uwsgi
Create a uwgi.ini
file in the same directory with the following content:
[uwsgi]
module = app:app
master = true
processes = 5
socket = flask.sock
chmod-socket = 660
vacuum = true
die-on-term = true
In the module configuration you need to specify a module (a single app.py
file in this case) and
Flask application variable name with a semicolon in between.
Next, processes = 5
will run 5 simultaneous instances of uwsgi workers, thus allowing 5 simultaneous requests to the app. You will need to experiment with that number to find a balance between
memory consumption and a load you expect on your app.
Then, there is a socket creation section - socket = flask.sock
. It will create a socket file.
This is a mechanism for nginx to communicate with uwsgi. There is an option to communicate over HTTP.
With the socket option, the file will be created in the same directory.
nginx
Create a file in this path /etc/nginx/sites-available/flask
with the following content
It will instruct nginx to proxy requests to a socket file created by uwsgi
server {
listen 80;
server_name server_domain_or_IP;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/as/flask_all/flask.sock;
}
}
You can restart nginx by sudo systemctl restart nginx
to apply this config.
Background service
Create this file in this path /etc/systemd/system/flask.service
[Unit]
Description=uWSGI instance to serve flask
After=network.target
[Service]
User=as
Group=www-data
WorkingDirectory=/home/as/flask_app
Environment="PATH=/home/as/flask_app/env/bin"
ExecStart=/home/as/flask_app/venv/bin/uwsgi --ini uwsgi.ini
[Install]
WantedBy=multi-user.target
Check the path - in this example, it points to an absolute path on my machine. So change is appropriately. Now we can start a service and enable it to start at boot:
➜ sudo systemctl start flask
➜ sudo systemctl enable flask
Flask app is accesible now in a browser on HTTP port 80
Docker
For that, you’ll need 3 things
- docker image with Flask app
- container image repository
- container orchestration (K8s, AWS ECS)
I’ve covered that scenario in these posts
- https://smirnov-am.github.io/running-flask-in-production-with-docker/
- https://smirnov-am.github.io/run-flask-on-aws-ecs/
PaaS
There are several PaaS platforms that you can run Flask on. They include AWS Elastic Beanstalk, GCP App Engine. The nice thing about them is that you don’t need to worry about OS, loadbalancing and autoscaling - platforms will to it for you.
I’m going to cover AWS Elastic Beanstalk here. First, get an AWS account and an install eb
CLI tool
locally - see the docs here
AWS EB needs a requirements.txt
file listing all the required dependencies. Generate it from
local virtual environment with:
➜ pip freeze > requirements.txt
Now in the folder with app.py
and requirements.txt
(we don’t need any files from the examples
above), create EB repository with:
➜ eb init -p python-3.6 flask-app-helloworld-as --region eu-west-1
Application flask-app-helloworld-as has been created.
and later deploy it with:
➜ eb create flask-app-helloworld-as
It will take some time (~10 minutes) and will create a bunch of resources - don’t forget to
clean up if you don’t need it later with eb terminate flask-app-helloworld-as
command.
You can reach your deployed app from CLI by eb open flask-app-helloworld-as
.
Serverless
Serverless is the most modern way to deploy web apps. I’m using this one for all my pet projects as AWS gives 1M free requests per month allowing me to run my apps at no cost.
In order to deploy Flask as an AWS Lambda I’m using a Zappa project. All you need is 3 commands:
➜ pip install zappa
➜ zappa init
➜ zappa deploy
The second command asks a bunch of question interactively about the environments and some configuration. The last command shows an URL where the app is available now:
Your updated Zappa deployment is live!: https://l17c5t2uhe.execute-api.us-east-1.amazonaws.com/dev