Deploying Django on Docker to Heroku with OpenCV
By Justin

Are you new to...
- Django? Start here
- Docker? Start here
- Python? Start here
Requirements
-
Docker/Docker Desktop installed. Do you not? Check out the post on simple docker
-
Heroku CLI Installed from here
System Requirements
- Windows 10 Professional docs (seriously; you need Virtual Machine support and Windows 10 Pro has it)
- macOS docs (you might need to install XCode as well.)
Final Project & Structure
simple_dj_docker
| .env
| db.sqlite3
| deploy.ps1
| deploy.sh
| Dockerfile
| Dockerfile-local
│ manage.py
│ Pipfile
│ Pipfile.lock
│
└───cfehome
│ │ __init__.py
│ │ settings.py
│ │ urls.py
│ │ wsgi.py
Get Django Working Locally
1. Clone/Copy the project from this post.
Open up terminal (Mac) or PowerShell (Windows)
cd path/to/your/dev/folder/
mkdir dj_docker_to_heroku
cd dj_docker_to_heroku
Clone or Copy the repo
git clone https://github.com/codingforentrepreneurs/Django-on-Docker .
Don't know how to use git? Watch the video to see how we download it. It's easy. The starter code is here.
2. Run pipenv install
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ ls
Dockerfile Pipfile README.md manage.py
LICENSE Pipfile.lock cfehome
pipenv install
3. Verify Django is working
pipenv run gunicorn cfehome.wsgi:application --bind 0.0.0.0:8888
Open http://localhost:8888 in your web browser. Do you see the Django starter page? Sweet. You're good to go.
Above is our final container command, you can also run pipenv run python manage.py runserver
Hit control + c to cancel the server out.
Get Django on Docker working Locally
Don't have docker installed? Go through this post.
1. Verify Docker Install
Open up terminal (Mac) or PowerShell (Windows)
$ docker --version
Docker version 19.03.2, build 6a30dfc
2. Build your project's image.
Navigate to your project
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ ls
Dockerfile Pipfile README.md manage.py
LICENSE Pipfile.lock cfehome
Run the docker build command
docker build -t dj-docker-to-heroku -f Dockerfile .
Of course the line dj-docker-to-heroku is custom. Change yours if you want.
3. Run a container
docker run -it -p 8888:8888 dj-docker-to-heroku
Is your project still running? Sweet. Let's do the fun part.
Deploy Django with Docker & Heroku
Pre-Steps
- Sign up for Heroku
- Download and install the Heroku CLI
1. Login to heroku
Open up Terminal (Mac/Linux) or PowerShell (Windows) and login to Heroku.
Verify
$ heroku --version
heroku/7.29.0 darwin-x64 node-v11.14.0
Login
heroku login
3. Create a Heroku App
Navigate to your project
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
Use the heroku create command to make your app.
heroku create dj-docker
Take note, my heroku app name is dj-docker
4. Login to the Heroku Container Registry
heroku container:login
I haven't convered what a 'container registry' is yet but think of it like a version-control for your deployed containers. Whenver you push your project via Docker to heroku, it's going to use an instance of your docker image. That instance of course is called a container. A container registry (there are many) holds a copy of this instance for machines to use. If that's confusing, please ask questions below.
5. Provision your Add-ons
PostgreSQL Database for Production
I'll make this simple. Don't use databases in a container. A container is like an ice cube. Once it melts, it's gone. You can easily make another one by using an ice tray but the old ice cube's contents are gone forever.
Databases need to live forever. Let's use heroku's managed database service for free:
heroku addons:create heroku-postgresql:hobby-dev -a dj-docker
Replace dj-docker with your Heroku project's name
6. Update Django Database Settings
In settings.py uncomment the following lines:
"""
Heroku database settings.
"""
import dj_database_url
db_from_env = dj_database_url.config()
DATABASES['default'].update(db_from_env)
DATABASES['default']['CONN_MAX_AGE'] = 500
7. Update our pipenv environment with new depedancies
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ pipenv install dj-database-url psycopg2
Mac users: I had to open XCode and accept permissions for psycopg2 to install.
8. Change our Dockerfile to be Heroku Ready
Docker images on heroku need to be slightly different than what we can do locally. Heroku has specific parameters for containers as you can read about here.
We're going to create a Dockerfile specifically for Heroku deployments.
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ mv Dockerfile Dockerfile-local
$ touch Dockerfile
Windows users: use echo $null >> Dockerfile-Heroku instead of touch
Dockerfile-localIn your new Dockerfile
# Base Image
FROM python:3.6
# create and set working directory
RUN mkdir /app
WORKDIR /app
# Add current directory code to working directory
ADD . /app/
# set default environment variables
ENV PYTHONUNBUFFERED 1
ENV LANG C.UTF-8
ENV DEBIAN_FRONTEND=noninteractive
# set project environment variables
# grab these via the Python os.environ
# these are 100% optional here
# $PORT is set by Heroku
ENV PORT=8888
# Install system dependencies with OpenCV
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata \
python3-setuptools \
python3-pip \
python3-dev \
python3-venv \
git \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# install environment dependencies
RUN pip3 install --upgrade pip
RUN pip3 install pipenv
# Install project dependencies
RUN pipenv install --skip-lock --system --dev
# Expose is NOT supported by Heroku
# EXPOSE 8888
CMD gunicorn cfehome.wsgi:application --bind 0.0.0.0:$PORT
9. Build Docker Image
Whenever you make changes to your code or virtual environment, it's important to build another image.
docker build -t dj-docker-to-heroku -f Dockerfile .
10. Push & Release
Now we need to push an instance (container) of our image to heroku.
Push
heroku container:push web -a dj-docker
Replace dj-docker with your Heroku project's name
Release
If all went well with the push, you can release it:
heroku container:release web -a dj-docker
11. Run migrate & createsuperuser
These are very important when you do a push with Django. Be sure to replace dj-docker with your Heroku's project name.
With heroku you can just simply run:
Migrate
heroku run python3 manage.py migrate -a dj-docker
Replace dj-docker with your project name
Create super user
heroku run python3 manage.py createsuperuser -a dj-docker
Bash
heroku run bash -a dj-docker
12. Create a deploy script.
The purpose of this is so we don't have to remember all the steps to deploy our code. I love making these for my production projects.
Mac/Linux users
Navigate to your project
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ nano deploy.sh
$ sudo chmod +x deploy.sh
In deploy.sh
# build our heroku-ready local Docker image
docker build -t dj-docker-to-heroku -f Dockerfile .
# push your directory container for the web process to heroku
heroku container:push web -a dj-docker
# promote the web process with your container
heroku container:release web -a dj-docker
# run migrations
heroku run python3 manage.py migrate -a dj-docker
Naturally my tagged Docker image is named dj-docker-to-heroku and my Heroku app is dj-docker. Your names will be different.
Test
$ cd path/to/your/dev/folder/
$ cd dj_docker_to_heroku
$ ./deploy.sh
Windows users
Navigate to your project
> cd path/to/your/dev/folder/
> cd dj_docker_to_heroku
> echo $null >> deploy.ps1
In deploy.ps1
# build our local Docker image
docker build -t dj-docker-to-heroku -f Dockerfile .
# push a container to heroku
heroku container:push web -a dj-docker
# promote the container
heroku container:release web-a dj-docker
# run migrations
heroku run python3 manage.py migrate -a dj-docker
Test
> cd path/to/your/dev/folder/
> cd dj_docker_to_heroku
> ./deploy.sh
BONUS: OpenCV in Production, on Heroku, with Django on Docker
Keep in mind that the final code will be on our repo for this post.
In your Dockerfile within your project path/to/your/dev/folder/dj_docker_to_heroku/, we need to update a few required installations.
From
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata \
python3-setuptools \
python3-pip \
python3-dev \
python3-venv \
git \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# install environment dependencies
RUN pip3 install --upgrade pip
RUN pip3 install pipenv
Run your deploy scripts from above.
To
# Install system dependencies with OpenCV
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata \
libopencv-dev \
build-essential \
libssl-dev \
libpq-dev \
libcurl4-gnutls-dev \
libexpat1-dev \
python3-setuptools \
python3-pip \
python3-dev \
python3-venv \
git \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# install environment dependencies
RUN pip3 install --upgrade pip
RUN pip3 install pipenv
RUN pip3 install opencv-contrib-python
If you're having issues remember that OpenCV is a large program; it might take up a good amount of space on your system. Also, you might have to reference our repo for this post to ensure your code/Dockerfile matches ours.
Test OpenCV in Production
heroku run python3 -c "import cv2; print(cv2.__version__)" -a dj-docker