How to Dockerize Your Django App

Containerizing applications has become a best practice for modern software development, allowing developers to create portable, reproducible environments. Among various tools, Docker stands out as a powerful solution to streamline development and deployment. In this guide, we will walk through the process of Dockerizing a Django application, ensuring consistency and efficiency across environments. This tutorial is aimed at beginners with basic Django knowledge but little to no experience with Docker.

How to Dockerize Your Django App

Why Containerize Your Django Application?

Containerizing a Django application with Docker offers multiple benefits:

  1. Stable Environment: Docker ensures your application runs in the same environment, regardless of the host system. No more "it works on my machine" problems. All dependencies are bundled within the container, making reproducing the setup on any server or machine easy.

  2. Reproducibility and Portability: A Dockerized app contains all its dependencies, environment variables, and configurations, ensuring it runs consistently in development, testing, and production.

  3. Team Collaboration: Developers can work in a unified environment using Docker images, reducing conflicts due to different system configurations.

  4. Efficient Deployment Docker simplifies deployments by removing the need for manual environment setups. It allows you to quickly spin up environments for development, staging, or production.

Prerequisites

Before you begin, ensure you have the following:

  • Docker Desktop and Docker Compose are installed on your system.
  • A Docker Hub accounts for storing and managing Docker images (optional but recommended).
  • A Django project is already set up. If not, we’ll create one as part of this guide.

Step 1. Set Up Your Django Project

  1. Create a Django Project: If you don’t already have a Django project, start by creating one:

    django-admin startproject my_docker_django_app_web
    cd my_docker_django_app_web
    
  2. Create a requirements.txt File: Generate a requirements.txt file to manage dependencies:

    pip freeze > requirements.txt
  3. Environment-Specific Settings: Update settings.py to use environment variables for sensitive and dynamic settings:

    import os
    
    SECRET_KEY = os.environ.get("SECRET_KEY", "default_secret_key")
    DEBUG = bool(os.environ.get("DEBUG", 0))
    ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "127.0.0.1").split(",")
    

Step 2. Create a Dockerfile

A Dockerfile defines how your Docker image is built. Create a file named Dockerfile in the root of your project:

# Use the official Python image
FROM python:3.10-slim

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1  
ENV PYTHONUNBUFFERED 1  

# Set working directory
WORKDIR /app

#Install dependencies
RUN apt-get update && apt install -y gcc libpq-dev && pip install --upgrade pip

# Copy dependencies and install them
COPY requirements.txt /app/  
RUN pip install --no-cache-dir -r requirements.txt  

# Install Gunicorn
RUN pip install gunicorn

# Copy project files to the container
COPY . /app

# Add a non-root user for better security
RUN useradd -m -r appuser && chown -R appuser /app  
USER appuser  

# Expose the application port and define the startup command
EXPOSE 8000  
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "$django_project_name.wsgi:application"]

Build and Test the Image

To build your Docker image:

docker build -t django-docker .

To verify the image was created:

docker image list

Run the container to test the setup:

docker run -p 8000:8000 django-docker

Step 3. Optimize the Dockerfile for Production

The initial Dockerfile works for development but isn’t suitable for production. Let’s make improvements:

  1. Use Gunicorn for a production-ready server: Add Gunicorn to requirements.txt:

    Django>=4.2,<5.0
    psycopg2>2.9
    gunicorn>=20.1
  2. Update the Dockerfile

    # Multi-stage build
    FROM python:3.13-slim AS builder
    
    # Set working directory and environment variables
    WORKDIR /app
    ENV PYTHONDONTWRITEBYTECODE 1  
    ENV PYTHONUNBUFFERED 1  
    
    # Install dependencies
    COPY requirements.txt /app/
    RUN pip install --no-cache-dir -r requirements.txt  
    
    # Final stage
    FROM python:3.13-slim
    COPY --from=builder /usr/local /usr/local  
    COPY . /app  
    
    # Add a non-root user for better security
    RUN useradd -m -r appuser && chown -R appuser /app  
    USER appuser  
    
    # Expose the application port and define the startup command
    EXPOSE 8000  
    CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "my_docker_django_app.wsgi:application"]
    

    This updated Dockerfile reduces the image size, adds a production-ready WSGI server, and ensures better security by running the container as a non-root user.

    Build the Docker image again:

    docker build -t django-docker .
    

    Verify the image size reduction:

    docker image list

    The image size should now be significantly smaller, optimizing deployment speed and storage costs.

Step 4. Configure Docker Compose

Docker Compose helps manage multi-container setups. In this case, we’ll configure a Django container alongside a PostgreSQL database container.

  1. Create a docker-compose.yml file in your project directory:

    version: "3.8"
    
    services:
      db:
        image: postgres:14
        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
    
      web:
        build:
          context: .
        container_name: django-docker
        ports:
          - "8000:8000"
        depends_on:
          - db
        environment:
          DJANGO_SECRET_KEY: \${DJANGO_SECRET_KEY}
          DEBUG: \${DEBUG}
          DATABASE_ENGINE: \${DATABASE_ENGINE}
          DATABASE_NAME: \${DATABASE_NAME}
          DATABASE_USERNAME: \${DATABASE_USERNAME}
          DATABASE_PASSWORD: \${DATABASE_PASSWORD}
          DATABASE_HOST: db
          DATABASE_PORT: \${DATABASE_PORT}
        env_file:
          - .env
    
    volumes:
      postgres_data:
  2. Create a .env file for environment variables:

    DJANGO_SECRET_KEY=your_secret_key
    DEBUG=True
    DATABASE_ENGINE=django.db.backends.postgresql
    DATABASE_NAME=dockerdjango
    DATABASE_USERNAME=dbuser
    DATABASE_PASSWORD=dbpassword
    DATABASE_HOST=db
    DATABASE_PORT=5432
  3. Build and run the services:

    docker-compose up --build
    

    The command will start both the Django and PostgreSQL containers, linking them together.

Step 5. Update Django Settings

Modify your Django settings.py to work seamlessly with the Docker setup:

  1. Update the database configuration to use environment variables:

    DATABASES = {
        'default': {
            'ENGINE': os.getenv('DATABASE_ENGINE', 'django.db.backends.sqlite3'),
            'NAME': os.getenv('DATABASE_NAME', 'db.sqlite3'),
            'USER': os.getenv('DATABASE_USERNAME', 'user'),
            'PASSWORD': os.getenv('DATABASE_PASSWORD', ''),
            'HOST': os.getenv('DATABASE_HOST', 'localhost'),
            'PORT': os.getenv('DATABASE_PORT', ''),
        }
    }
    

    Read the secret key and allowed hosts from the environment:

    SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", "fallback_secret_key")
    ALLOWED_HOSTS = os.getenv("DJANGO_ALLOWED_HOSTS", "127.0.0.1").split(",")
    

    Ensure DEBUG is toggled correctly:

    DEBUG = bool(int(os.getenv("DEBUG", 0)))
    

Step 6. Run and Test the Application

After setting up your Docker and Django configuration, it’s time to test everything:

  1. Run the Containers: Use the following command to start the containers:

    docker-compose up
    

    This command builds and runs all services defined in docker-compose.yml.

  2. Access the Application: Open your browser and navigate to http://localhost:8000. You should see Django’s default welcome page if everything is working.Django Localhost

  3. Apply Migrations: Run the following command to migrate your database:

    docker-compose run web python manage.py migrate
    
  4. Create a Superuser (Optional): Create a superuser to access the Django admin panel:

    docker-compose run web python manage.py createsuperuser
    

    Then navigate to http://localhost:8000/admin to log in.
    Django adminDjango admin

Step 7. Troubleshooting Common Issues

Here are a few common problems you might encounter and how to resolve them:

  1. Database Connection Errors: Check if the database service name in docker-compose.yml matches the DATABASE_HOST value in .env.

  2. File Synchronization Issues: Use the volumes directive in docker-compose.yml to sync local changes to the container.

  3. Container Crashes or Restart Loops: Use docker-compose logs to inspect errors and debug issues.

Step 8. Optimize for Production

  1. Reduce Image Size: Use smaller base images, such as python:3.13-slim.

  2. Use Environment Variables for Sensitive Data: Avoid hardcoding secrets and sensitive data in your application. Use .env files or secret management tools.

  3. Add Logging and Monitoring: Use tools like ELK stack, Prometheus, or Docker logging drivers for monitoring and debugging in production.

  4. Set Up HTTPS: Use a reverse proxy like NGINX with SSL certificates for secure production deployments.

Conclusion

By containerizing your Django application with Docker, you’ve taken a significant step toward modernizing your development and deployment processes. Docker simplifies environment management, ensures consistent performance across systems, and reduces deployment time.

This guide covered

  • Creating a Dockerfile for your Django project.
  • Configuring Docker Compose to manage multi-container setups.
  • Optimizing your setup for production.

With these tools in place, you can scale your application confidently and deploy it with ease. As a next step, consider exploring CI/CD pipelines and cloud hosting services like AWS, Azure, or GCP to further enhance your deployment process.

Check out the GitHub repository for an easy-to-use deployment script that will set up your Django project with Docker in minutes or you can download the source code​​​​​!


Similar Articles
Ezmata Technologies Pvt Ltd
You manage your core business, while we manage your Infrastructure through ITaaS.