Skip to main content

Django + Docker-Compose deployment to Heroku

Setting up a docker-compose django project

header image
1. Follow the django docker-compose guide set-up here.
2. Your working directory should now contain all files listed below
  • Dockerfile docker-compose.yml manage.py requirements.txt
3. Test that you app is running locally
  • $ sudo docker-compose up 
 4. Navigate to localhost:8000 on your web browser to test if everything is working as expected.


Django production application configuration

1. Modify your Dockerfile as follows

Dockerfile
    
      FROM python:3.6.4
      ENV PYTHONUNBUFFERED 1
      ENV PORT 5000
      RUN mkdir /code
      WORKDIR /code
      ADD requirements.txt /code
      RUN pip install -r requirements
      ADD . /code
      CMD python3 manage.py runserver 0.0.0.0:$PORT 
  
2. Modify your wsgi.py file as follows
wsgi.py
    
      import os
      
      from django.core.wsgi import get_wsgi_application
      from whitenoise.django import DjangoWhiteNoise
      
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", 
      "project_name.settings")
      
      application = get_wsgi_application()
      application = DjangoWhiteNoise(application)
    
  
3. Modify your settings.py as follows
settings.py

 # Copy your secret key to  .env file

import os
from decouple import config
import dj_database_url
.............. 
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = ['.herokuapp.com/']
.......
 
INSTALLED_APPS = [
# ...
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
# ...]
 
....... 
DATABASES = { 'default': dj_database_url.config( 
      default=config('DATABASE_URL') )
     } 
.....

MIDDLEWARE_CLASSES = [.....
 'whitenoise.middleware.WhiteNoiseMiddleware',
# ...]
 
.......
STATIC_URL = '/static/'
STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'),) 
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    

  • Update your requirements.txt to include whitenoise==3.3.1
4. Create a .gitignore in your root directory

.gitignore

      *.pyc
      *.sqlite3
      *.env
 
NB: Copy the contents of this file to another file called .dockerignore
5.  Create a .env in your root directory
.env

      SECRET_KEY='pdfjsskskfiuf.............'
      DEBUG=False
    # Copy your own secret key from settings.py 
6. Finally, modify the docker-compose.yml file as follows
    
      version: '2'
       services:
        web:
         build: .
         ports:
          - "5000:5000"
         env_file: .env
         depends on:
           - db
          volumes:
             - .:/code
        db:
         image: postgres:latest
         ports:
           - "5432:5432"
    
  

 Deploy to heroku

1. Create a heroku app, together with the add-ons needed for production, e.g. postgres database:

      $ heroku login 
      $ heroku create endeesa
      $ heroku git:remote -a endeesa
      $ heroku addons: create heroku-postgresql:hobby-dev -a endeesa  
2. Configure heroku variables

3. Update your .env file
SECRET_KEY='k_^7*=x48^&f-7_mgm3$z*=-4ogj(!q+prrbi......'
DEBUG=False
DATABASE_URL='postgres://ntgdltqnyzxb1.amaz/dddie91mk0phpq'........'


4. Deploy your containerized django application to heroku




      $ heroku container:login
      $ heroku container:push web 
 

  • Run $ heroku open, to view your live site
  • You can continue with local development by running 
    • $ sudo docker-compose up --build
  • Note that to do this, you need to set DEBUG = TRUE inside your .env file.
  • It is recommended that you modify your project to use two settings such that all in all your project is structured as follows
    • settings
      • base.py
      • production.py
      • development.py
  • This way, you can import base.py in both production.py and development.py and override different variables as needed. e.g. DEBUG=False inside production.py and DEBUG=True iniside development.py.

Comments

Popular posts from this blog

Gunicorn vs NGINX Explained

Web applications typically disseminate information via three server layers: Web server   - First layer: Receives request from client(web browser) Application server - 2nd layer: Receives requests from web server if the client is requesting dynamic content Database - 3rd layer: Receives database queries from web framework's request handler methods In this example , nginx is the web server, gunicorn is the application server (interface between nginx and web framwork request handling function) and the database can be assumed to be a lightweight sqlite3 database. Example: Django architecture Alternatives to nginx : Cherokee Apache HTTP server Alternatives for gunicorn: Apache Mongoose

How to install python 3 in Ubuntu 16.04 / LIve USB

The following guide will help you get started with installing python3 and pip3 on your linux( Ubuntu 16.04 ) live USB.  1. First install python 3 from the "deadsnakes" repository from the Python Package Accesories ( PPA ) $ sudo add-apt-repository ppa:deadsnakes/ppa $ sudo apt-get update $ sudo apt-get install python3.6 This will install both python 3.5.2 and python 2.7.2 on your machine. Verify the installation by running python3 --version or python --version on the linux command line.  2. Next up, install pip3 package manager that will allow you to install other useful python libraries such as numpy,seabon ,pandas etc. $ sudo apt-get update $ sudo apt-get install python3-setuptools $ sudo easy_install3 pip  Once again, verify the installation by running pip3 --version on the command line. 3. You can now use pip3 to install non-core python libraries as follows   $ sudo pip3 install jupyter  $ sudo pip3 numpy etc.

Python packages

A python package is a collection of python module s. These modules are python scripts with *.py file extension. Typically, these scripts will contain python functions, classes, custom data types etc. Looking at the figure above, the Game package consist of an _init_.py file together with 3 other sub-packages Sound, Image and Level respectively. The _init_.py file must be included inside a directory for it to be considered a python package.In addition, the directory must be defined inside sys.path. Example usage: 1. import Game.Level.Start Suppose the start.py module consists of a function called mince() Inside your python application, you would need to call it as follows 2. Game.Level.Start.mince(<input_params>) Alternatively, you can reference it as follows 3. from Game. Level import Start     // recommended approach 4. Start.mince(<input_params>) A less common method is calling the function as if it was defined inside your curr...