Setting up Postgres DB backend

Installing dependencies in Dockerfile and keeping the Docker container small

1) To use postgres, we need the following python dependency

psycopg2>=2.7.5,<2.8.0

2) Before installing psycopg2, we have to run the dependency installs in Dockerfile.

3) We should also remove the unwanted dependencies to keep the docker container small. For eg, if we need gcc only for compiling and do not need it afterwards, gcc should be removed after installation.

Structure of Dockerfile

1) Install permanant and temporary dependencies in separate lines

2) Delete temporary dependencies after the required build is complete

Dockerfile
# PERMANANT dependences
# apk is the package manager that comes with alpine
# --update : update registry before we add it
# --no-cache: Do not store index locally. Used to keep container small
RUN apk add --update --no-cache postgresql-client
# TEMPORARY dependencies. Needed only for installing
# --virtual: an alias which can be used to remove dependencies later
# Eg. We need gcc to compile the program but do not need it later
RUN apk add --update --no-cache --virtual .tmp-build-deps \
      gcc libc-dev linux-headers postgresql-dev

RUN pip install -r /requirements.txt

# Delete temporary dependencies
RUN apk del .tmp-build-deps

Running postgres in a separate container and adding its dependency to main container

We have to make the following changes in the docker-compose.yml and settings.py

1) Set up separate postgres service with image postgres:10-alpine

2) Set the environment variable to use postgres:10-alpine as specified in documentation

3) Map the database volume in a level above the docker-compose.yml file. Otherwise, build fails because of recusive search done by docker in child folders

yml
      #database served as separate service
      db:
        image: postgres:10-alpine
        volumes:
          # dont have db in same level as docker-compose. otherwise build fails because of recursive search
          - ../postgres:/var/lib/postgresql/data
        environment:
          - POSTGRES_DB=app
          - POSTGRES_USER=uname
          - POSTGRES_PASSWORD=password

3) Link the main service (app) to the database service using depends_on keyword

4) Set up environment variables in main service, so that it can be passed on to settings.py to reflect changes

yml

    # These environments will be used in settings.py
    environment:
      - DB_HOST=db
      - DB_NAME=app
      - DB_USER=uname
      - DB_PASS=password
    depends_on:
      - db

5) In settings.py under DATABASES

# Database
    # https://docs.djangoproject.com/en/2.1/ref/settings/#databases

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'HOST': os.environ.get('DB_HOST'),
            'NAME': os.environ.get('DB_NAME'),
            'USER': os.environ.get('DB_USER'),
            'PASS': os.environ.get('DB_PASS'),
        }
    }