01/08/2025 | News release | Distributed by Public on 01/08/2025 13:14
One of the best ways to make sure your web apps work well in different environments is to containerize them. Containers let you work in a more controlled way, which makes development and deployment easier. This guide will show you how to containerize a Django web app with Docker and explain why it's a good idea.
We will walk through creating a Docker container for your Django application. Docker gives you a standardized environment, which makes it easier to get up and running and more productive. This tutorial is aimed at those new to Docker who already have some experience with Django. Let's get started!
Django apps can be put into containers to help you work more productively and consistently. Here are the main reasons why you should use Docker for your Django project:
Setting up a Django app in Docker is straightforward. You don't need to do much more than add in the basic Django project files.
To follow this guide, make sure you first:
If you need help with the installation, you can find detailed instructions on the Docker and Django websites.
The following six steps include code snippets to guide you through the process.
1. Initialize a Django project.
If you don't have a Django project set up yet, you can create one with the following commands:
django-admin startproject my_docker_django_app cd my_docker_django_app
2. Create a requirements.txt file.
In your project, create a requirements.txt file to store dependencies:
pip freeze > requirements.txt
3. Update key environment settings.
You need to change some sections in the settings.py file to enable them to be set using environment variables when the container is started. This allows you to change these settings depending on the environment you are working in.
# The secret key SECRET_KEY = os.environ.get("SECRET_KEY") DEBUG = bool(os.environ.get("DEBUG", default=0)) ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",")
A Dockerfile is a script that tells Docker how to build your Docker image. Put it in the root directory of your Django project. Here's a basic Dockerfile setup for Django:
# Use the official Python runtime image FROM python:3.13 # Create the app directory RUN mkdir /app # Set the working directory inside the container WORKDIR /app # Set environment variables # Prevents Python from writing pyc files to disk ENV PYTHONDONTWRITEBYTECODE=1 #Prevents Python from buffering stdout and stderr ENV PYTHONUNBUFFERED=1 # Upgrade pip RUN pip install --upgrade pip # Copy the Django project and install dependencies COPY . /app/ # run this command to install all dependencies RUN pip install --no-cache-dir -r requirements.txt # Copy the Django project to the container COPY . /app/ # Expose the Django port EXPOSE 8000 # Run Django's development server CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Each line in the Dockerfile serves a specific purpose:
You can build the Django Docker container with the following command:
docker build -t django-docker .
To see your image, you can run:
docker image list
The result will look something like this:
REPOSITORY TAG IMAGE ID CREATED SIZE django-docker latest ace73d650ac6 20 seconds ago 1.55GB
Although this is a great start in containerizing the application, you'll need to make a number of improvements to get it ready for production.
Let's get started with these improvements.
Make sure to add gunicorn to your requirements.txt. It should look like this:
asgiref==3.8.1 Django==5.1.3 sqlparse==0.5.2 gunicorn==23.0.0 psycopg2-binary==2.9.10
The Dockerfile below has changes that solve the three items on the list. The changes to the file are as follows:
# Stage 1: Base build stage FROM python:3.13-slim AS builder # Create the app directory RUN mkdir /app # Set the working directory WORKDIR /app # Set environment variables to optimize Python ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 # Upgrade pip and install dependencies RUN pip install --upgrade pip # Copy the requirements file first (better caching) COPY requirements.txt /app/ # Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt # Stage 2: Production stage FROM python:3.13-slim RUN useradd -m -r appuser && \ mkdir /app && \ chown -R appuser /app # Copy the Python dependencies from the builder stage COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/ COPY --from=builder /usr/local/bin/ /usr/local/bin/ # Set the working directory WORKDIR /app # Copy application code COPY --chown=appuser:appuser . . # Set environment variables to optimize Python ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 # Switch to non-root user USER appuser # Expose the application port EXPOSE 8000 # Start the application using Gunicorn CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "my_docker_django_app.wsgi:application"]
Build the Docker container image again.
docker build -t django-docker .
After making these changes, we can run a docker image list again:
REPOSITORY TAG IMAGE ID CREATED SIZE django-docker latest 3c62f2376c2c 6 seconds ago 299MB
You can see a significant improvement in the size of the container.
The size was reduced from 1.6 GB to 299MB, which leads to faster a deployment process when images are downloaded and cheaper storage costs when storing images.
You could use docker init as a command to generate the Dockerfile and compose.yml file for your application to get you started.
A docker-compose.yml file allows you to manage multi-container applications. Here, we'll define both a Django container and a PostgreSQL database container.
The compose file makes use of an environment file called .env, which will make it easy to keep the settings separate from the application code. The environment variables listed here are standard for most applications:
services: db: image: postgres:17 environment: POSTGRES_DB: ${DATABASE_NAME} POSTGRES_USER: ${DATABASE_USERNAME} POSTGRES_PASSWORD: ${DATABASE_PASSWORD} ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data env_file: - .env django-web: build: . container_name: django-docker ports: - "8000:8000" depends_on: - db environment: DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY} DEBUG: ${DEBUG} DJANGO_LOGLEVEL: ${DJANGO_LOGLEVEL} DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS} DATABASE_ENGINE: ${DATABASE_ENGINE} DATABASE_NAME: ${DATABASE_NAME} DATABASE_USERNAME: ${DATABASE_USERNAME} DATABASE_PASSWORD: ${DATABASE_PASSWORD} DATABASE_HOST: ${DATABASE_HOST} DATABASE_PORT: ${DATABASE_PORT} env_file: - .env volumes: postgres_data:
And the example .env file:
DJANGO_SECRET_KEY=your_secret_key DEBUG=True DJANGO_LOGLEVEL=info DJANGO_ALLOWED_HOSTS=localhost DATABASE_ENGINE=postgresql_psycopg2 DATABASE_NAME=dockerdjango DATABASE_USERNAME=dbuser DATABASE_PASSWORD=dbpassword DATABASE_HOST=db DATABASE_PORT=5432
1. Configure database settings.
Update settings.py to use PostgreSQL:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.{}'.format( os.getenv('DATABASE_ENGINE', 'sqlite3') ), 'NAME': os.getenv('DATABASE_NAME', 'polls'), 'USER': os.getenv('DATABASE_USERNAME', 'myprojectuser'), 'PASSWORD': os.getenv('DATABASE_PASSWORD', 'password'), 'HOST': os.getenv('DATABASE_HOST', '127.0.0.1'), 'PORT': os.getenv('DATABASE_PORT', 5432), } }
2. Set ALLOWED_HOSTS to read from environment files.
In settings.py, set ALLOWED_HOSTS to:
# 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a , between each. # For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1,[::1]' ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS","127.0.0.1").split(",")
3. Set the SECRET_KEY to read from environment files.
In settings.py, set SECRET_KEY to:
# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
4. Set DEBUG to read from environment files.
In settings.py, set DEBUG to:
# SECURITY WARNING: don't run with debug turned on in production! DEBUG = bool(os.environ.get("DEBUG", default=0))
To build and start your containers, run:
docker compose up --build
This command will download any necessary Docker images, build the project, and start the containers. Once complete, your Django application should be accessible at http://localhost:8000.
Once the app is running, you can test it by navigating to http://localhost:8000. You should see Django's welcome page, indicating that your app is up and running. To verify the database connection, try running a migration:
docker compose run django-web python manage.py migrate
Here are some common issues you might encounter and how to solve them:
To improve your Django Docker setup, consider these optimization tips:
Containerizing your Django application with Docker is an effective way to simplify development, ensure consistency across environments, and streamline deployments. By following the steps outlined in this guide, you've learned how to set up a Dockerized Django app, optimize your Dockerfile for production, and configure Docker Compose for multi-container setups.
Docker not only helps reduce "it works on my machine" issues but also fosters better collaboration within development teams by standardizing environments. Whether you're deploying a small project or scaling up for enterprise use, Docker equips you with the tools to build, test, and deploy reliably.
Ready to take the next step? Explore Docker's powerful tools, like Docker Hub and Docker Scout, to enhance your containerized applications with scalable storage, governance, and continuous security insights.