Deploying a Django Blog with Docker Compose: A Step-by-Step Guide

> This blog post will guide you through deploying a Django blog project using Docker Compose, a powerful tool for managing multi-container applications. We'll leverage the following technologies: * **Docker:** Containerization platform for isolating applications. * **Docker Compose:** Simplifies multi-container deployments. * **Django:** Python web framework for building web applications. * **MySQL:** Database management system for storing blog data. * **Nginx:** High-performance web server for serving your blog content. * **Gunicorn:** Python WSGI server for handling Django requests. **Prerequisites:** * Basic understanding of Docker and Python * Docker installed on your machine **1. Project Setup:** * Create a new directory for your blog project. * Initialize a Django project within the directory: ```bash django-admin startproject blog ``` * Navigate into the project directory: ```shell cd blog ``` * We will create the following directory structure: ``` ├── blog │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── wsgi.py ├── nginx │ ├── example.conf │ ├── Dockerfile ├── manage.py ├── requirements.txt ├── Dockerfile ├── docker-compose.yml └── .dockerignore ``` * Modify blog/settings.py file ```python import os CSRF_TRUSTED_ORIGINS = ['https://*.example.com', 'http://*.127.0.0.1'] if os.getenv('ENVIRONMENT') == 'production': DEBUG = False STATIC_ROOT = BASE_DIR / 'static/' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': 'blog-mysql', # tips: This name must be same with your container_name 'PORT': '3306', 'NAME': 'blog', 'USER': 'root', 'PASSWORD': '', 'OPTIONS': {'charset': 'utf8mb4'}, } } else: STATICFILES_DIRS = [BASE_DIR / 'static/'] ``` **2. Defining Dockerfile:** ```shell # pull official base image FROM python:3.12.2-slim # set work directory WORKDIR /code # set environment variables ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 ENV ENVIRENMENT production # install dependencies RUN apt-get update -y RUN apt-get install python3-dev default-libmysqlclient-dev build-essential mariadb-client pkg-config -y COPY requirements.txt . # if your network limited, you can add this param `-i ${pip_url} --trusted-host ${pip_host}` RUN pip install --upgrade pip RUN pip install -r requirements.txt # copy project COPY . . RUN python manage.py makemigrations RUN python manage.py migrate RUN python manage.py collectstatic --no-input RUN gunicorn blog.wsgi:application --bind 0.0.0.0:8000 ``` **3. Defining Services with docker-compose.yml:** Create a file named `docker-compose.yml` in your project directory. This file defines the services that make up your application: ```yaml version: "3.8" # Specify Docker Compose version services: # MySQL database service db: image: mysql:8.0 # Use official MySQL image (version 8.0) container_name: blog-mysql environment: MYSQL_ROOT_PASSWORD: 13852love MYSQL_DATABASE: blog MYSQL_USER: blog MYSQL_PASSWORD: 13852love TZ: 'Asia/Tokyo' volumes: - mysql-data:/var/lib/mysql # Mount database volume for persistence # Django application service web: image: blog:1.0 container_name: blog-django build: . volumes: - ./static:/static # Mount current directory as project code ports: - "8000:8000" # Expose Django development server port depends_on: - db # Nginx web server service nginx: image: nginx:1.0 container_name: blog-nginx build: ./nginx ports: - "80:80" # Expose port 80 for web traffic volumes: - ./static:/static # Mount custom Nginx configuration depends_on: - web volumes: static: mysql-data: ``` **Explanation:** * This configuration defines three services: * `web`: This service builds the Django application image, exposes port 8000 for development, and mounts the current directory as project code. It also sets environment variables for the database connection. * `db`: This service uses the official MySQL image, mounts a volume for persistent data storage, and sets environment variables for database credentials. * `nginx`: This service uses the official Nginx image, exposes port 80 for web traffic, and mounts a custom Nginx configuration file. * We haven't included the `nginx.conf` file yet. We'll create it in the next step. **4. Configuring Nginx (nginx.conf):** Create a file named `example.conf` in your project directory. This file defines how Nginx serves static files and forwards requests to the Django application: nginx > dockerfile ```shell FROM nginx:1.9-alpine COPY example.conf /etc/nginx/conf.d/example.conf ``` nginx > example.conf ```shell upstream django_gunicorn{ server web:8000; } server { listen 80; # Listen on port 80 # if you have a domain # server_name example.com; location / { proxy_pass http://django_gunicorn; # Forward requests to Django application on port 8000 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_redirect off; } location /static { autoindex on; alias /static; # Serve static files from Django's static directory } location /media { alias /media; } } ``` **Explanation:** * This configuration defines a server block that listens on port 80. * It serves static files from the Django `static` directory using an `alias` directive. * For all other requests, it acts as a reverse proxy and forwards them to the `web` service running on port 8000 within the Docker network. **5. Building and Running the Application:** Now that all the configuration files are set up, it's time to build and run your Django blog with Docker Compose: 1. **Build the Docker images:** ```bash docker-compose build ``` This command instructs Docker Compose to build individual images for each service defined in `docker-compose.yml`. 2. **Run the application:** ```bash docker-compose up -d ``` * `up`: This tells Docker Compose to start all defined services. * `-d`: This runs the containers in detached mode, allowing them to run in the background. **6. Accessing Your Blog:** Once the application is running, you should be able to access your blog by opening http://localhost in your web browser. You'll see the default Django welcome page. **7. Configuring and Migrating Django:** * **Create a virtual environment:** (Optional, but recommended) ```bash python3 -m venv venv source venv/bin/activate ``` * **Install project dependencies:** ```bash pip install -r requirements.txt # Assuming you have a requirements.txt file ``` * **Run Django migrations:** ```bash python manage.py makemigrations python manage.py migrate ``` These commands create database tables based on your Django models and apply any schema changes. * **Start the Django development server:** (Optional, for further development) ```bash python manage.py runserver ``` This will start the Django development server on `http://localhost:8000` accessible within the container network. **8. Additional Considerations:** * **Environment Variables Management:** Consider using a `.env` file to store sensitive information like database credentials and manage them outside of version control. * **Customizing Nginx Configuration:** You can further customize the Nginx configuration file (`nginx.conf`) to handle caching, logging, and other web server settings. * **Deployment on a Cloud Platform:** For production deployment, consider using a cloud platform like Heroku or AWS and adapting the configuration for container orchestration tools like Kubernetes. **Conclusion:** By following these steps, you've successfully deployed a Django blog project using Docker Compose and gained valuable experience working with these technologies. This approach promotes a modular, scalable, and efficient way to deploy web applications. Feel free to explore further configurations and customizations to tailor this setup to your specific needs.
April 7, 2024, 8:22 a.m.