It’s easy to launch a web application on a local machine when all that is required is to be good at a programming language. However, it takes a lot of trial and error to deploy a web application, especially when more tools are involved, and you now have to worry about the deployment environment, scalability, and other concerns. If you’re looking to deploy a Python web application (i.e. Flask/Django), this article is for you! You can skip the first three sections if you already have some knowledge of Heroku and Docker.
Update: This article is part of a series. Check out other "in 10 Minutes" topics here!
Table of Contents
Why Heroku?
Heroku is a cloud platform as a service (PaaS) that allows applications to be hosted on the cloud. For people looking for a free hosting platform for Python applications, Heroku is one of the top 10 choices (although there are paid tiers as well).
For the free tier, Heroku offers integration with GitHub and the use of Heroku Containers for deployment, referred to as dyno
. I would also mention some of the caveats of using the free tier that I find cumbersome.
- It is not possible to choose a custom domain, so applications will be hosted with
<app-name>.herokuapp.com
domain - There is no SSL certificate, but a workaround is to manually type in
https://
to get the same secure lock icon - Free
dynos
will sleep after some period of inactivity, therefore relaunching the application will take some time (~ 1 minute) for the container to start up - The repository will be compiled into a
slug
, and the performance will start degrading if the slug size exceeds 500 MB. This would severely limit the repository size. A workaround is to compile your application into a Docker image and bypass the slug size requirement
Update: Heroku has removed its free tier as of Nov 2022, an alternative would be to use Google Cloud or Fly. If you are using the paid version of Heroku, feel free to read on!
Why Docker?
Docker helps deliver the web application in packages called containers. Using containers is a best practice for Deployment since each container has its software, libraries, and configuration files, and is easy to scale your web application up or down. However, in Heroku free tier, I don’t think there is an option to scale the web application up.
The last caveat in the previous section was also the reason why I chose to switch from using Heroku containers to Docker containers. I was expanding my web application and realized my repository has grown too big and my web application is increasingly slow. After the switch to Docker containers, my web application runs even faster than on my local computer!
I would recommend using Heroku with Docker to future-proof your web application so you don’t have to perform the switch as I did.
Docker Crash Course
The instructions on how to create a container are usually written in a Dockerfile
, and the files to ignore from the compilation are found in .dockerignore
. Below is a sample of what .dockerignore
file looks like, but this file is optional if you want Docker to compile everything in the repository.
__pycache__
*.pyc
env/
db.sqlite3
docs/
*.log
For Dockerfile
, there are some commands that are commonly used,
FROM
is used once at the start ofDockerfile
to indicate which base image to use, for our case we would want to use a base image that supports PythonARG
defines variables that users pass in at build-time. In the example below,port
is an argument to be passed in when building a Docker imageUSER
sets username or user group when running Docker imageCOPY
copies files and directories to the containerWORKDIR
sets the working directory of the containerENV
sets environment variableRUN
runs shell command, which calls/bin/sh -c
on LinuxEXPOSE
informs Docker that the container listens on the specified network ports at runtime, used for testing Docker applications locallyCMD
is used once at the end ofDockerfile
and contains the final command to run execute the container
Information on the full list of Docker commands can be found on the Docker documentation. Below is a sample of what the Dockerfile
looks like,
FROM python:3.8-slim
ARG port
USER root
COPY . /<your-app>
WORKDIR /<your-app>
ENV PORT=$port
RUN apt-get update && apt-get install -y --no-install-recommends apt-utils
&& apt-get -y install curl
&& apt-get install libgomp1
RUN chgrp -R 0 /<your-app>
&& chmod -R g=u /<your-app>
&& pip install pip --upgrade
&& pip install -r requirements.txt
EXPOSE $PORT
CMD gunicorn app:server --bind 0.0.0.0:$PORT --preload
It is best to test if the Dockerfile
is able to compile locally before deployment, which requires building the Docker image and running it.
- To build Docker image: The following command passes in the
port
argument and the image name istmp_image
,docker build --no-cache --build-arg port=8060 -t tmp_image .
- To run Docker image: The following command maps port of Docker image to local port so the web application can be viewed locally,
docker run --rm -p 8060:8060 tmp_image
Deploy Docker on Heroku
Assuming you already have your folder structure for your web application, you only require 3 additional files for deployment to Heroku. Two of these files are instructions for Docker as explained in the previous section, and the last file heroku.yml
contains deployment instructions for Heroku. Below is the sample project folder structure,
your-app
|-- .dockerignore
|-- app.py
|-- Dockerfile
|-- heroku.yml
|-- requirements.txt
For heroku.yml
file, you only need to indicate that deployment is using Docker and the file looks like this,
build:
docker:
web: Dockerfile
And it’s completed! All that’s left is to follow the on-screen instructions to link Heroku to your codebase, and your web application will be ready after the build!
Hope you have learnt how to deploy Python applications on Heroku using Docker. If you’re interested to view my web application which is deployed the same way, the link is below!
Thank you for reading! If you liked this article, feel free to share it.
Related Links
Heroku Deployment Documentation: https://devcenter.heroku.com/categories/deploying-with-docker
Dockerfile
Documentation: https://docs.docker.com/engine/reference/builder/
heroku.yml
Documentation: https://devcenter.heroku.com/articles/build-docker-images-heroku-yml