Docker Config
Part 1, Chapter 4
Let's containerize the Django app.
Start by ensuring that you have Docker and Docker Compose:
$ docker -v
Docker version 27.0.3, build 7d4bcd8
$ docker compose version
Docker Compose version v2.28.1-desktop.1
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.12.4-slim-bookworm
# set working directory
WORKDIR /usr/src/app
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# add app
COPY . .
Here, we started with a slim-bookworm-based Docker image for Python 3.12.4. We then set a working directory along with two environment variables:
PYTHONDONTWRITEBYTECODE
: Prevents Python from writing pyc files to disc (equivalent topython -B
option)PYTHONUNBUFFERED
: Prevents Python from buffering stdout and stderr (equivalent topython -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 Best Practices 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:
services:
movies:
build: ./app
command: python manage.py runserver 0.0.0.0:8000
volumes:
- ./app/:/usr/src/app/
ports:
- 8009: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.
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(" ")
Add the import:
import os
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 Appropriately section.
Once the build is done, fire up the container in detached mode:
$ docker compose up -d
Navigate to http://localhost:8009/ 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:
You also may need to add
COMPOSE_CONVERT_WINDOWS_PATHS=1
to theenvironment
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
│ │ ├── asgi.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