How to deploy containerized Python and Django application on Heroku
Tags: python, django, docker, heroku
Published: 2021-07-31 12:22:26

This is the first time I have launched my python and django application(as a containerized application) on **Heroku**. First impression with **Heroku** is really great 🤩, because it provides lots of services and you can use the free services as well✌️. It did not ask me any credit card details like other cloud providers.

I will be covering here that how you can make your application as a containerized application to deploy on **Heroku**.

If you have any application which you have created, you can take that. I will be using my [Converter Site](https://github.com/PayalSasmal10/pdf2docxConverter-PayalSasmal) application which can help me to deploy. Now we can dive into the steps

1.I have created Dockerfile which are mandatory instructions(which are not mandatory, I mentioned that this is for my application and you can skip) for any kind of web application created using Python and Django.

```
#Pull the base image
FROM python:3.7-slim

# who is the maintainer/author of this file
LABEL org.opencontainers.image.authors="PAYALSASMAL, sasmalpayal@gmail.com"

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG 0

#upgrading pip for python
RUN python -m pip install --upgrade pip

#install tkinter for my application requirement, you can skip this for your application
RUN apt-get update && apt-get install -y tcl tk

#creating this dir for my application, you can skip this for your application
RUN mkdir -p /usr/share/man/man1

#installing libreoffice for my application, you can skip this for your application
RUN apt-get update && apt-get install -y \
    libreoffice-base default-jre

#copying requirements.txt file
COPY ./requirements.txt /app/requirements.txt

#install those requirements before copying the project
RUN pip install -r /app/requirements.txt

#copy the project
COPY . .

#run gunicorn. here pdfconverter is the project name
CMD gunicorn -b 0.0.0.0:$PORT pdfconverter.wsgi:application

```
  **PYTHONDONTWRITEBYTECODE:** It prevents python from writing [.pyc](https://www.python.org/dev/peps/pep-3147/#case-4-legacy-pyc-files-and-source-less-imports) files to disc.

  **PYTHONUNBUFFERED:** It prevents python from writing stdout and stderr stream. check this [document](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED) for more info.

  **$PORT:** This variable value will be set by *Heroku* at runtime.

2.Update the allow_host at *settings.py.* for your application.

```
ALLOWED_HOSTS = ['127.0.0.1']
```

3.Now test this application as a containerized application locally. So build the image using below command 👇🏻.

```
docker build -t pdfconverter:latest .
```

4.Now run that image using below command 👇🏻.

```
docker run --name pdfconverter -e "PORT=8000" -p 8007:8000 pdfconverter:latest
```
*-e*: I passed *PORT* as env variable. even though it will work without passing the env variable as well.

Here is an example 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46lnz2vvxxp865zehf61.png)

Make sure that your containerized application is working properly to the local at http://127.0.0.1:8007/ host.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7a1j7i5t1q3zt6phni8v.png)

5.As per requirements, I have added my below 👇🏻 requirements at *requirements.txt* file. 
```
Django==3.2
djangoconvertvdoctopdf==1.0.1
gunicorn==20.1.0
pdf2docx==0.5.2
whitenoise==5.2.0  
```
* [djangoconvertvdoctopdf](https://github.com/seferaua/django-convert-doc-to-pdf): This module helps to convert from docx to pdf.
* [pdf2docx](https://github.com/dothinking/pdf2docx): This module helps to convert from pdf to docx
* [whitenoise](https://whitenoise.evans.io/en/stable/): This module helps to manage the static media for your application. This need to be added as a middleware in Django settings.py
* [Django](https://github.com/django/django): This will install the django
* [gunicorn](https://github.com/benoitc/gunicorn): This will install the gunicorn

6.We can add **whitenoise** middleware at *settings.py*.This middleware should be added after securityMiddleware.
```
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
7.Configure staticfiles related stuffs at *settings.py*
```
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'pdfconverter/static')
]
```
8.Let's create heroku application through *Heroku Dashboard*. Click on *Create new app*.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w10u4neyfur5bta5x6l7.png)

9.Provide a name of the app. As I have given *pdfconverter-by-payal*(as I created the app already with this name so it is showing that this name is not available). Then click on *Create app* button.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11s0zx4fusvknr2f2j90.png)

10.Click on *Open app* tab. This URL will be your application URL. It is **https://pdfconverter-by-payal.herokuapp.com/** for my application.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnlbfauie729ybr67f9p.png)

11.We have to add the domain to *settings.py* without https.
```
ALLOWED_HOSTS = ['127.0.0.1','pdfconverter-by-payal.herokuapp.com']
```

12.Now we will be creating [heroku.yml manifest](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml) file.
```
build:
  docker:
    web: Dockerfile
run:
  web: gunicorn pdfconverter.wsgi:application --bind 0.0.0.0:$PORT
```
As per manifest file document, [heroku.yml manifest](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml) has 4 top-level sections:

* **setup** - Specifies the add-ons and config vars to create during app provisioning
* **build** - Specifies the Dockerfile to build
* **release** - Specifies the [release phase](https://devcenter.heroku.com/articles/release-phase) tasks to execute
* **run** - Specifies process types and the commands to run for each

13.Now push your code to *GitHub*. 
```
git push repo master
```
14.Install *heroku cli* in your local and then go to *Heroku Dashboard* under setting tab. check what is the [stack](https://devcenter.heroku.com/articles/stack) here, [stack](https://devcenter.heroku.com/articles/stack) should be **heroku-20**( which means ubuntu-20.04) by default.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xitb2dmqt643tlzj75dn.png)

15.Set the [stack](https://devcenter.heroku.com/articles/stack) as container using below command 👇🏻.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z5zlhmhmfyyao3pbaasl.png)

16.Go to *heroku dashboard*. Click on *Deploy* tab. Click on *GitHub* under *Deployment method*. Authorized with your GitHub account and provide the repository name to connect.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bx7ekf19dz363na3a8c3.png)
 
17.Either you can choose *automatic deployment*(deploy application automatically on heroku after making changes on github) by click on [**Enable Automatic Deploys**](https://blog.heroku.com/automated-continuous-deployment-at-heroku) option or choose **Manual Deploy** by click on *Deploy Branch*. I have done **Manual Deploy** for my application.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vw9q2thgqlwjj45pcna6.png)

18.You can see the logs if there is an issue while deploying, it will be failed.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5j17a4xckr1wrpyt38jf.png)

19.I am able to see my application to https://pdfconverter-by-payal.herokuapp.com/ site and It is working as expected. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a4kydrcoq6x24s9kl89z.png)


Note: You might not see the website,you might see the below error 👇🏻. so check the logs of application using heroku cli in your local.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jel4ryzg10crbpfvuc7z.png)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipob2051puek48csmfhc.png)


Hope It will help someone 🤗.

`Please note few things for my website:-`
* My [website](https://pdfconverter-by-payal.herokuapp.com/) is not storing data inside the database so there is no data exposure, please feel free to use it.
* This [Converter Site](https://github.com/PayalSasmal10/pdf2docxConverter-PayalSasmal) is an open source. If you are an open source enthusiast, please feel free to contribute.




Let's connect on [Twitter](https://twitter.com/payalsasmal), [LinkedIn](https://www.linkedin.com/in/payal-sasmal-64204311a/) and [GitHub](https://github.com/PayalSasmal10)