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

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

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

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

Традиционная установка PostgreSQL на локальную машину часто приводит к "загрязнению" системы, конфликтам версий и сложностям при переходе между проектами. Docker-compose решает эти проблемы, предоставляя:

  • Изоляцию окружений — каждый проект имеет свои версии ПО без конфликтов
  • Воспроизводимость — конфигурация описывается кодом (YAML-файл)
  • Портативность — проект запускается одинаково на любой системе с Docker
  • Простота развёртывания — почти идентичная конфигурация для разработки и продакшена

Docker-compose — это инструмент для определения и запуска многоконтейнерных приложений. В нашем случае это будут два контейнера: для Django и для PostgreSQL.

Структура проекта и базовые файлы

Перед началом убедитесь, что у вас установлены Docker и Docker-compose. Типичная структура проекта:

myproject/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
└── src/          # Ваш Django-проект
    ├── manage.py
    └── myproject/
        └── settings.py

1. Dockerfile для Django

Создайте Dockerfile в корне проекта:

FROM python:3.11-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

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

COPY ./src .

CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

2. docker-compose.yml — сердце конфигурации

Это ключевой файл, связывающий все компоненты:

version: '3.8'

services:
  db:
    image: postgres:15-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_DB=mydatabase
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser"]
      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://myuser:mypassword@db:5432/mydatabase

volumes:
  postgres_data:

Использование Alpine-версий образов значительно уменьшает размер контейнеров. Для продакшена замените runserver на Gunicorn или uWSGI.

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

Конфигурация settings.py

Обновите настройки базы данных в Django:

import os
from urllib.parse import urlparse

# Получаем URL из переменной окружения или используем значения по умолчанию
DATABASE_URL = os.environ.get('DATABASE_URL', 
    'postgres://myuser:mypassword@localhost:5432/mydatabase')

parsed_url = urlparse(DATABASE_URL)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': parsed_url.path[1:],  # Убираем первый слэш
        'USER': parsed_url.username,
        'PASSWORD': parsed_url.password,
        'HOST': parsed_url.hostname,
        'PORT': parsed_url.port or 5432,
    }
}

Установка зависимостей

В requirements.txt обязательно добавьте:

Django>=4.2
psycopg2-binary>=2.9
python-dotenv>=1.0  # для управления переменными окружения

Работа с проектом: основные команды

  1. Запуск контейнеров: docker-compose up --build
  2. Запуск в фоновом режиме: docker-compose up -d
  3. Остановка: docker-compose down
  4. Просмотр логов: docker-compose logs -f web
  5. Выполнение команд в контейнере: docker-compose exec web python manage.py migrate
  6. Создание суперпользователя: docker-compose exec web python manage.py createsuperuser

Продвинутые практики и оптимизации

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

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

POSTGRES_DB=mydatabase
POSTGRES_USER=myuser
POSTGRES_PASSWORD=secure_password_here
DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}

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

environment:
  - POSTGRES_DB=${POSTGRES_DB}
  - POSTGRES_USER=${POSTGRES_USER}
  - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

Настройка volumes для разработки

Для hot-reload во время разработки используйте bind mounts:

volumes:
  - ./src:/app
  - ./static:/app/static  # для статических файлов
  - ./media:/app/media    # для медиафайлов

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

В docker-compose.yml можно добавить:

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

Распространённые проблемы и их решения

Если Django не может подключиться к PostgreSQL, убедитесь что контейнер базы данных полностью запустился (healthcheck прошёл успешно). Используйте docker-compose logs db для диагностики.

  • "Connection refused" ошибка: Убедитесь, что в settings.py указан host='db' (имя сервиса из compose), а не 'localhost'
  • Миграции не применяются: Выполните docker-compose exec web python manage.py migrate
  • Медленная работа в Windows/Mac: Используйте WSL2 на Windows или увеличьте ресурсы Docker Desktop
  • Потеря данных при остановке: Все данные сохраняются благодаря volume 'postgres_data'

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

Как сохранить данные PostgreSQL между перезапусками?

Docker-compose автоматически сохраняет данные благодаря объявленному тому 'postgres_data'. Данные сохраняются даже после docker-compose down.

Можно ли использовать эту конфигурацию для продакшена?

Базовую структуру — да, но потребуются доработки: использование Gunicorn/uWSGI, настройка Nginx, SSL-сертификаты, правильные настройки безопасности PostgreSQL.

Как импортировать существующую базу данных?

Скопируйте dump-файл в контейнер и выполните восстановление:
docker-compose exec -T db psql -U myuser mydatabase < backup.sql

Почему используется порт 5432:5432 если контейнеры изолированы?

Проброс порта 5432 на хост-машину нужен для подключения внешних инструментов (например, DBeaver, DataGrip) к контейнеру с базой данных.

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

Измените тег образа в docker-compose.yml (например, на 'postgres:16-alpine'), сделайте backup базы, пересоздайте контейнеры и восстановите данные.

Можно ли подключить несколько Django-проектов к одной базе?

Технически — да, но это плохая практика. Лучше создавать отдельные базы данных или использовать схемы PostgreSQL для изоляции.