How to Publish Your First Python App on Heroku
Heroku is one of the most popular Platforms as a Service (PaaS) which allows developers to develop and deploy their applications to the cloud.
So, let’s get started. We will quickly sign up for an account on the Heroku homepage.
Heroku has a Heroku CLI to interact with its services which can be installed on MacOS, Linux and Windows.
For Mac, use brew install heroku
For Windows, Download the installer from here.
For linux, use sudo snap install — classic heroku
Once the Heroku CLI is installed, make sure to sign in into the CLI using “heroku login”.
To start a Python application, we need to first set up the Python virtual environment using:
pip install virtualenv
Once virtualenv is installed, we can create a virtual environment, with a path to python 3 binary, for example:
➜ ~ virtualenv -p /usr/local/Cellar/python\@3.8/3.8.2/bin/python3 ~/python33
created virtual environment CPython3.8.2.final.0-64 in 3309ms
creator CPython3Posix(dest=/Users/m0a04y6/python33, clear=False, global=False)
seeder FromAppData(download=False, pip=bundle, wheel=bundle, setuptools=bundle, via=copy, app_data_dir=/Users/m0a04y6/Library/Application Support/virtualenv)
added seed packages: pip==20.1.1, setuptools==47.3.1, wheel==0.34.2
activators PythonActivator,FishActivator,XonshActivator,CShellActivator,PowerShellActivator,BashActivator
Once the virtual environment is created, it can be activated using:
~ source ~/python33/bin/activate
We will now install the flask and gunicorn dependencies, which are required to create our Python application.
(python33) ➜ ~ pip install flask
Collecting flask
Using cached Flask-1.1.2-py2.py3-none-any.whl (94 kB)
Collecting itsdangerous>=0.24
Using cached itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting Jinja2>=2.10.1
Using cached Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
Collecting click>=5.1
Using cached click-7.1.2-py2.py3-none-any.whl (82 kB)
Collecting Werkzeug>=0.15
Using cached Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)
Collecting MarkupSafe>=0.23
Using cached MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl (16 kB)
Installing collected packages: itsdangerous, MarkupSafe, Jinja2, click, Werkzeug, flask
Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.2 flask-1.1.2 itsdangerous-1.1.0
WARNING: You are using pip version 20.1.1; however, version 20.2.2 is available.
You should consider upgrading via the '/Users/m0a04y6/python33/bin/python -m pip install --upgrade pip' command.(python33) ➜ ~ pip install gunicorn
Collecting gunicorn
Using cached gunicorn-20.0.4-py2.py3-none-any.whl (77 kB)
Requirement already satisfied: setuptools>=3.0 in ./python33/lib/python3.8/site-packages (from gunicorn) (47.3.1)
Installing collected packages: gunicorn
Successfully installed gunicorn-20.0.4
WARNING: You are using pip version 20.1.1; however, version 20.2.2 is available.
You should consider upgrading via the '/Users/m0a04y6/python33/bin/python -m pip install --upgrade pip' command.
(python33) ➜ ~
Now that our Python setup is completed and we are ready to create a simple Python Flask API and publish it on Heroku.
First, let’s create a simple app.py which defines a route and the content to be returned when that route is accessed.
We’ll create wsgi.py, which will be the entry point of our application.
Create the file requirements.txt as follows:
pip freeze > requirements.txt
And a file called Procfile with contents:
web: gunicorn app.app:app
Now, we are ready to publish this on Heroku. We’ll use the Heroku CLI to create the application and publish the source code to the application.
Create the Heroku application — heroku create our-first-python-app (Note that this name must be unique).
Publish the application — git push heroku master
This application can now be accessed here.
Congrats!! We have our first Python application running on Heroku cloud.
Scaling the Heroku Application
The application which we just developed is fine for a very low traffic application. However, in the real world, there will be multiple users accessing the application and hence the application should be able to handle the load which all these users would generate.
This is where Heroku allows you to seamlessly scale your application using a simple command such as:
heroku ps:scale web=5
Running this command will ensure that Heroku will run five instances of the application resulting in extra requests to be distributed uniformly over these multiple instances.
However, the question arises how many instances do you need at a particular time? To answer this question, we need to estimate how many requests a single instance can handle.
For this, we need to perform load testing. Load testing is an activity where we send a large amount of requests to an application and estimate at what number of requests / sec does the application’s performance start to degrade.
One of the tools to perform such load testing that I have used in the past is Loadmill.
With Loadmill, I can quickly create a load test to perform the real world load testing simulating traffic from various locations and across devices as shown below:
I can define the duration of the test, concurrency (no. of users), geography and various other parameters to run the load test.
The results of the test will give us a fair idea if the application needs additional scaling depending on our current number of users and the estimated growth.
And there you have it, a quick guide to deploying your first Python app on Heroku.