Современная веб-разработка немыслима без контейнеризации, и связка Django с PostgreSQL в Docker-окружении стала стандартом де-факто для изолированного, воспроизводимого и масштабируемого стека. В этом руководстве мы разберем не просто базовое подключение, а архитектурные принципы, настройку для production-среды и решения для типичных проблем, с которыми сталкиваются разработчики.
Почему именно Docker Compose для Django и PostgreSQL?
Docker Compose позволяет описать мультиконтейнерное приложение в одном файле docker-compose.yml. Для Django-проекта это означает, что вы можете поднять базу данных, само приложение, кэш (например, Redis) и даже очередь задач (Celery) одной командой. Это устраняет проблему "а у меня на машине работает", обеспечивая идентичное окружение на всех этапах: от локальной разработки до staging-сервера.
Ключевое преимущество — изоляция. Ваш PostgreSQL работает в своем контейнере, не конфликтуя с другими версиями СУБД на хостовой машине. Все зависимости упакованы в образы.
Структура проекта и базовый docker-compose.yml
Предположим, у вас уже есть Django-проект. Рекомендуемая структура для начала:
myproject/
├── django_app/ # Ваш проект Django (manage.py здесь)
├── Dockerfile # Для сборки образа Django
├── docker-compose.yml
└── .env # Переменные окружения (не коммитить!)
Содержимое docker-compose.yml
Создайте файл docker-compose.yml в корне:
version: '3.8'
services:
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME}
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- ./django_app:/app
ports:
- "8000:8000"
environment:
- DB_HOST=db
- DB_NAME=${DB_NAME}
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
volumes:
postgres_data:
Настройка Django для работы с контейнеризованной PostgreSQL
В вашем settings.py используйте переменные окружения:
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'db'), # 'db' — имя сервиса в compose
'PORT': 5432,
}
}
Обратите внимание: HOST — это не localhost, а имя сервиса db. Внутри Docker-сети контейнеры общаются по именам сервисов, определенных в docker-compose.yml.
Практический workflow: от первого запуска до миграций
- Создайте файл
.envв корне (добавьте в.gitignore):DB_NAME=mydatabase DB_USER=myuser DB_PASSWORD=mysecurepassword - Соберите и запустите:
docker-compose up --build - Выполните миграции (в новом терминале):
docker-compose exec web python manage.py migrate - Создайте суперпользователя:
docker-compose exec web python manage.py createsuperuser
Продвинутые сценарии и оптимизация
Использование .dockerignore
Создайте файл .dockerignore, чтобы исключить из контекста сборки ненужные файлы (__pycache__, .git, виртуальное окружение), что ускорит build и уменьшит размер образа.
Production-готовый Dockerfile для Django
Для production используйте многоступенчатую сборку и сервер вроде Gunicorn:
FROM python:3.11-slim as builder
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /app/wheels -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /app/wheels /wheels
COPY --from=builder /app/requirements.txt .
RUN pip install --no-cache /wheels/*
COPY ./django_app .
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
FAQ: Часто задаваемые вопросы
Как подключиться к PostgreSQL из внешнего клиента (например, DBeaver)?
Используйте localhost:5432, логин и пароль из .env файла. Порт проброшен благодаря строке ports: - \"5432:5432\" в сервисе db.
Как сохранить данные PostgreSQL при перезапуске контейнеров?
Мы используем именованный volume postgres_data. Данные сохраняются в нем даже после docker-compose down. Для полного удаления данных выполните docker-compose down -v.
Получаю ошибку "connection refused" от Django. В чем дело?
1. Убедитесь, что в settings.py HOST='db'.
2. Проверьте, что сервис web зависит от здорового (condition: service_healthy) сервиса db.
3. Проверьте корректность переменных окружения в .env.
Как выполнить management-команду Django?
Используйте docker-compose exec web python manage.py <command>. Например, для создания миграций: docker-compose exec web python manage.py makemigrations.
Можно ли использовать эту конфигурацию в production?
Базовую — нет. Для production необходимо: использовать Gunicorn/Uvicorn вместо runserver, настроить статику через Nginx, использовать секреты (например, Docker Secrets или vault), настроить логирование и мониторинг, обеспечить backup базы данных.