This is a short hands-on introduction to docker-compose. If you want to know what docker is, check this link out. This is simply a commented version of the official django with docker-compose.

Tested Configuration:
MacOS: Sierra 10.12.06
Docker: 18.09.2 CE
Docker-compose: 1.23.2

1. Requirements

Make sure you have docker and docker-compose installed on your machine. To do this, simply type

docker --version

and make sure you have something like Docker version 18.09.2-ce, build 6247962

Then type

docker-compose --version

and make sure you have something like docker-compose version 1.23.2, build 1110ad01

2. Dockerfile

First, create your Dockerfile, please type :

mkdir docker_folder
cd docker_folder
touch Dockerfile

Edit your Dockerfile

You are still in the /docker_folder, type

sudo nano Dockerfile

It will open your Dockerfile. Now copy the following code in your Dockerfile :

FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/

What is happening in the Dockerfile:

FROM python:3 will import the python 3 image from the docker hub
ENV PYTHONUNBUFFERED 1 define an environment variable. Later in the script, it will tell python to print STDOUT without buffering anything. that’s useful when you want to print something before the machine crashes
RUN mkdir /code will create a folder on the Image
WORKDIR /code will set the current directory as /code -> acts like a ` cd /code` on the image
COPY requirements.txt /code/ copies the file requirements.txt to the image at the location /code/requirements.txt
RUN pip install -r requirements.txt install all python packages on the image
COPY . /code/ copy the rest of the folder to the folder code

3. Create your requirements

Create your requirements.txt in your folder /docker_folder and then edit it:

sudo nano requirements.txt

Inside, you can write this:

Django>=2.0,<3.0
psycopg2>=2.7,<3.0

This will tell Docker to install Django and psycopg2 on the image

4. Create docker-compose.yaml

Create a file called docker-compose.yaml in your project directory /docker_folder and then edit it:

sudo nano docker-compose.yaml

Inside, you can write this:

version: "3"

services:
  db:
    image: postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
From the documentation:

The docker-compose.yml file describes the services that make your app. In this example those services are a web server and database.
The compose file also describes which Docker images these services use, how they link together, any volumes they might need mounted inside the containers.
Finally, the docker-compose.yml file describes which ports these services expose.

Short analysis:

Note: we don’t have any access to the database, exept through the docker network. It means only the service web can access the database, because this docker network is restricted to db and web (type docker network inspect testdjango_default). Even you, if you want to use a GUI in order to manipulate the Postgres data, you will need to add a line in the db configuration:

    expose:
      - 5432

5. Create a Django project

in your terminal type:

sudo docker-compose run web django-admin startproject composeexample .

Explanations:

compose will run django-admin startproject composeexample in a container, using the web service’s image and configuration. This command instructs Django to create a set of files and directories representing a Django project.

Now, if you look at the files in the /docker_folder, you have:
Dockerfile (was here before)
composeexample
docker-compose.yaml (was here before)
manage.py
requirements.txt (was here before)

6. Connect the database

In the composeexample/settings.py file, replace DATABASES = ... with:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'HOST': 'db',
        'PORT': 5432,
    }
}

To know more about the database: docker & postgres

7. Run

Simply run your docker project using

docker-compose up

and see you server working by clicking http://localhost:8000

Monitor

Prints all the running containers

docker container ls
Stop

Two method:

  1. Ctrl-C in the same shell in where you started it

  2. open a new shell, go to /docker_folder directory, and run docker-compose down

Notes:

docker-compose.yaml VS docker-compose.yml

Shall we use the extension .yml or .yaml ? IT DOESN’T MATTER
Everyone could use .yaml but some Windows developer are afraid of using more than 3 letters extensions…

file ownership

After runnig sudo docker-compose run web django-admin startproject composeexample . several files were created. Running ls -l will show who is owning the files. You may need to change their ownership back to you (espcially Linux users) using sudo chown -R $USER:$USER .

Other docker-compose.yaml proposition

This can be interesting for two reasons:

version: "3"

services:
  db:
    image: postgres
    environment:
      PGDATA: /var/lib/postgresql/data/django_test_pgdata
      POSTGRES_USER: yourusername
      POSTGRES_PASSWORD: yourpassword
      POSTGRES_DB: test
    volumes:
      - /usr/local/var/postgres/data/django_test_pgdata:/var/lib/postgresql/data/django_test_pgdata
    ports:
      - "8002:5432"

  web: [SAME CONFIG]

First you may have port 5432 already in use on another Postgres container, or because you already run postgres on your laptop.

Second, you have control on the data. instead of staying inside your postgres container (and beiing deleted when the container stops) you can have persistent data.

Run only one docker

If you want to launch only the database for instance, you can write down:
docker-compose run --service-ports postgres

With --service-ports meaning you attach the docker to the host network (usually what you want when you don’t launch docker together)

if you have Volumes

Let’s say you have decided to inculde the volume option, like so (probably to cache your node_modules folder):

version: "3"

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - node_modules:/code/node_modules
    ports:
      - "8000:8000"

Then, if you need to “clean the cache” (because you want to reinstall the dependancies for instance), use this command: docker-compose down --volumes

Ressources:

docker-compose.yaml VS docker-compose.yml: stackoverflow link
More about PYTHONUNBUFFERED
the official docker-compose tuto