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.