Django + PostgreSQL в Docker: Полное руководство по контейнеризации вашего проекта

Django + PostgreSQL в Docker: Полное руководство по контейнеризации вашего проекта

Современная разработка на Django всё чаще происходит в контейнеризированной среде, где Docker и docker-compose становятся стандартом де-факто. Подключение PostgreSQL к Django через docker-compose — это не просто техническая задача, а целая философия разработки, обеспечивающая воспроизводимость, изоляцию и масштабируемость вашего приложения. В этом руководстве мы разберём каждый шаг — от базовой настройки до продвинутых практик, которые превратят вашу локальную разработку в профессиональный процесс.

Почему именно Docker-compose для Django и PostgreSQL?

Docker-compose позволяет описывать многоконтейнерные приложения в одном YAML-файле. Для Django-проекта это означает, что вы можете одновременно запускать: контейнер с вашим приложением, контейнер с PostgreSQL, а при необходимости — дополнительные сервисы вроде Redis, Celery или Nginx. Все они будут общаться через изолированную сеть, иметь общие тома для данных и запускаться одной командой.

Главное преимущество — идентичность окружений. То, что работает на вашем ноутбуке, гарантированно заработает на сервере коллеги или в production-среде. Больше не будет проблем с версиями Python, PostgreSQL или системными библиотеками.

Структура проекта и базовый docker-compose.yml

Начнём с типичной структуры проекта:

  • your_project/
  • ├── Dockerfile (для Django-приложения)
  • ├── docker-compose.yml
  • ├── requirements.txt
  • └── src/ (ваш Django-проект)

Содержимое 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=django_user
      - POSTGRES_PASSWORD=strong_password
      - POSTGRES_DB=django_db
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U django_user"]
      interval: 10s
      timeout: 5s
      retries: 5

  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./src:/app
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgres://django_user:strong_password@db:5432/django_db

volumes:
  postgres_data:

Настройка Django для работы с PostgreSQL в контейнере

Ключевой момент — правильная конфигурация settings.py. Вместо хардкода параметров используем переменные окружения:

import os
from pathlib import Path
import dj_database_url

# Чтение DATABASE_URL из переменных окружения
database_url = os.environ.get('DATABASE_URL')

DATABASES = {
    'default': dj_database_url.parse(database_url) if database_url else {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('POSTGRES_DB', 'django_db'),
        'USER': os.environ.get('POSTGRES_USER', 'django_user'),
        'PASSWORD': os.environ.get('POSTGRES_PASSWORD', 'strong_password'),
        'HOST': os.environ.get('POSTGRES_HOST', 'db'),  # 'db' — имя сервиса в compose
        'PORT': os.environ.get('POSTGRES_PORT', 5432),
    }
}

Обратите внимание на HOST: 'db'. В Docker-compose сервисы общаются по именам, указанным в файле конфигурации. Имя 'db' разрешается во внутренний IP-адрес контейнера с PostgreSQL.

Dockerfile для Django-приложения

Ваш Dockerfile должен устанавливать зависимости и настраивать приложение:

FROM python:3.11-slim

WORKDIR /app

# Установка зависимостей для PostgreSQL клиента
RUN apt-get update && apt-get install -y \
    libpq-dev gcc \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY src/ .

# Рекомендуется использовать gunicorn для production
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "your_project.wsgi"]

Работа с миграциями и статикой

Создайте скрипт entrypoint.sh для автоматического применения миграций при запуске:

#!/bin/bash

# Ждём готовности PostgreSQL
until pg_isready -h db -p 5432; do
  echo "Waiting for database..."
  sleep 2
done

# Применяем миграции
python manage.py migrate --noinput

# Собираем статику
python manage.py collectstatic --noinput --clear

# Запускаем основной процесс
 exec "$@"

И обновите Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Продвинутые сценарии

Использование .env файла для конфиденциальных данных

Никогда не храните пароли в docker-compose.yml! Создайте .env файл:

POSTGRES_PASSWORD=your_strong_password_here
POSTGRES_USER=django_user
POSTGRES_DB=django_db
SECRET_KEY=django-secret-key

И обновите docker-compose.yml:

db:
  environment:
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
  env_file:
    - .env

Добавление pgAdmin для управления БД

Добавьте в docker-compose.yml:

pgadmin:
  image: dpage/pgadmin4
  environment:
    - PGADMIN_DEFAULT_EMAIL=admin@admin.com
    - PGADMIN_DEFAULT_PASSWORD=admin
  ports:
    - "5050:80"
  depends_on:
    - db

FAQ: Часто задаваемые вопросы

Как подключиться к PostgreSQL извне Docker?

Используйте localhost:5432 с теми же credentials, что указаны в environment. Убедитесь, что порт проброшен (ports: "5432:5432").

Данные PostgreSQL пропадают после остановки контейнеров?

Используйте volumes (как в нашем примере). Данные будут храниться в томе postgres_data, который сохраняется между перезапусками. Для полного удаления используйте docker-compose down -v.

Как выполнить manage.py команды?

Используйте docker-compose exec web python manage.py migrate или создайте отдельный сервис для management-команд.

Проект работает медленно на macOS/Windows?

Используйте cached volumes и настройте ресурсы Docker Desktop. Для Linux-хостов проблем с производительностью обычно нет.

Как обновить версию PostgreSQL?

Измените тег образа (например, на postgres:16-alpine), создайте дамп, обновите и восстановите данные. Всегда тестируйте на staging-окружении!