Docker Config

Chapter 4


Let's containerize the Django app.


Start by ensuring that you have Docker and Docker Compose:

$ docker -v
Docker version 19.03.4, build 9013bf5

$ docker-compose -v
docker-compose version 1.24.1, build 4667896b

Make sure to install or upgrade them if necessary.

Add a Dockerfile to the "app" directory, making sure to review the code comments:

# pull official base image
FROM python:3.8.0-alpine

# set work directory
WORKDIR /usr/src/app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt

# copy project
COPY . /usr/src/app/

Here, we used an Alpine-based, Python image to keep our final image slim. Alpine Linux is a lightweight Linux distro. It's a good practice to use Alpine-based images, whenever possible, as your base images in your Dockerfiles.

Benefits of using Alpine:

  1. Decreased hosting costs since less disk space is used
  2. Quicker build, download, and run times
  3. More secure (since less packages and libraries are available)
  4. Faster deployments

Take note of the following environment variables:

  1. PYTHONDONTWRITEBYTECODE: Prevents Python from writing pyc files to disc (equivalent to python -B option)
  2. PYTHONUNBUFFERED: Prevents Python from buffering stdout and stderr (equivalent to python -u option)

Finally, we updated Pip, copied over the requirements.txt file, installed the dependencies, and copied over the Django project itself.

Depending on your environment, you may need to add RUN mkdir -p /usr/src/app just before you set the working directory:

# set working directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

Add a .dockerignore file to the "app" directory as well:

env
.dockerignore
Dockerfile
Dockerfile.prod

Like the .gitignore file, the .dockerignore file lets you exclude specific files and folders from being copied over to the image.

Review Docker for Python Developers for more on structuring Dockerfiles as well as some best practices for configuring Docker for Python-based development.

Then add a docker-compose.yml file to the project root:

version: '3.7'

services:
  movies:
    build: ./app
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./app/:/usr/src/app/
    ports:
      - 8000:8000
    env_file:
      - ./app/.env.dev

This config will create a service called movies from the Dockerfile.

The volume is used to mount the code into the container. This is a must for a development environment in order to update the container whenever a change to the source code is made. Without this, you would have to re-build the image each time you make a change to the code.

Take note of the Docker compose file version used -- 3.7. Keep in mind that this version does not directly relate back to the version of Docker Compose installed; it simply specifies the file format that you want to use.

Review the Compose file reference for info on how this file works.

Update the SECRET_KEY, DEBUG, and ALLOWED_HOSTS variables in settings.py:

# app/drf_project/settings.py

SECRET_KEY = os.environ.get("SECRET_KEY")

DEBUG = int(os.environ.get("DEBUG", default=0))

# 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a space between each.
# For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]'
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")

Then, create a .env.dev file in the "app" directory to store environment variables for development:

DEBUG=1
SECRET_KEY=foo
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]

Build the image:

$ docker-compose build

This will take a few minutes the first time. Subsequent builds will be much faster since Docker caches the results. If you'd like to learn more about Docker caching, review the Order Dockerfile commands slide.

Once the build is done, fire up the container in detached mode:

$ docker-compose up -d

Navigate to http://localhost:8000/ to again view the welcome screen. Check for errors in the logs if this doesn't work via docker-compose logs -f.

If you run into problems with the volume mounting correctly, you may want to remove it altogether by deleting the volume config from the Docker Compose file. You can still go through the course without it; you'll just have to re-build the image after you make changes to the source code.

Windows Users: Having problems getting the volume to work properly? Review the following resources:

  1. Docker on Windows — Mounting Host Directories
  2. Configuring Docker for Windows Shared Drives

You also may need to add COMPOSE_CONVERT_WINDOWS_PATHS=1 to the environment portion of your Docker Compose file. Review Declare default environment variables in file for more info.

Bring down the development containers (and the associated volumes with the -v flag):

$ docker-compose down -v

Since we'll be moving to Postgres, go ahead and remove the db.sqlite3 file from the "app" directory.

├── .gitignore
├── app
│   ├── .dockerignore
│   ├── .env.dev
│   ├── Dockerfile
│   ├── drf_project
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── manage.py
│   ├── movies
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   └── views.py
│   └── requirements.txt
└── docker-compose.yml



Mark as Completed