Локально проект с базой поднимается одной командой docker compose up, а публикация добавляет вопросы, которых до неё не было: где база будет жить, как приложение к ней подключится, где держать пароль и что случится с данными при следующем обновлении кода. Классический путь — арендовать сервер, поставить базу, настроить доступ и не забыть про бэкапы. На Dockbox приложение и база поднимаются как один проект из docker-compose, а данные лежат в постоянном хранилище и переживают обновления. Ниже — по шагам, где именно теряются данные и как этого не допустить.
Почему проект с базой тащат на VPS
Отдельная установка базы. PostgreSQL мало поставить — надо решить, где она хранит файлы, создать пользователя, выдать права и не забыть об обновлениях безопасности.
Доступ снаружи. Приходится либо открывать порт базы в интернет, либо настраивать туннель. База, торчащая наружу, — самый частый способ потерять данные.
Данные внутри контейнера. При обновлении кода проект пересобирается, и всё, что лежало не в том месте, стирается вместе с контейнером.
Пароли и бэкапы. Пароль в docker-compose.yml, строка подключения в коде, регулярных копий нет — обычный набор в самодельном деплое.
Платформа снимает эту часть: описание сервисов уходит как есть, база поднимается рядом с приложением, а выделенный том закрывает вопрос с обновлениями. Ни сервера, ни ручной установки, ни открытых наружу портов.
Шаг 1. Опишите приложение и базу в одном файле
Положите в корень проекта docker-compose.yml и опишите в нём два сервиса: приложение и базу — PostgreSQL, MySQL, MongoDB или Redis из готового официального образа. Приложение собирается из вашего кода, база — из образа, ставить и настраивать её вручную нечего.
services:
app:
build: .
environment:
DATABASE_URL: postgres://app:***@db:5432/app
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Шаг 2. Дайте базе постоянное хранилище
Это ключевой шаг, и пропускать его нельзя. Добавьте базе именованный том (db_data выше) и привяжите его к папке, где база хранит свои файлы: у PostgreSQL это /var/lib/postgresql/data. Без тома данные лежат внутри контейнера и стираются при первом же обновлении кода. С томом они переживают перезапуски и повторные публикации — такие данные удаляются только вместе с проектом.
Шаг 3. Соединяйте сервисы по имени, а не по адресу
Внутри проекта сервисы видят друг друга по именам из описания. Если база называется db, приложение подключается к хосту db на стандартном порту базы. IP-адреса здесь не нужны и вредны: при перезапуске они меняются, а имя остаётся прежним. И выпускать базу наружу незачем — публичный адрес получает только приложение, а база доступна лишь соседнему сервису внутри проекта.
DATABASE_URL=postgres://app:***@db:5432/app
Шаг 4. Пароль базы — в секреты, а не в файл
Не пишите пароль, пользователя и строку подключения прямо в docker-compose.yml и тем более в коде — читайте их из переменных окружения. Файл описания вы почти наверняка будете коммитить, поэтому секрет в файле = секрет утёк.
Плохой вариант:
environment:
DATABASE_URL: postgres://app:secret@db:5432/app
Хороший — значение приходит извне, а код только читает его:
import os
DATABASE_URL = os.environ["DATABASE_URL"]
В настройках проекта эти значения задаются отдельно и хранятся зашифрованными: в панели видны имена переменных, а сами значения — никому.
Шаг 5. Миграции — при старте, а не вручную
Терминала внутри проекта нет, поэтому схему накатывают из стартовой команды до запуска сервера. Тогда таблицы появляются на первом запуске, а на следующих обновлениях данные остаются на месте.
python manage.py migrate --noinput && gunicorn config.wsgi:application --bind 0.0.0.0:$PORT
Проект попадает на платформу ZIP-архивом или импортом репозитория GitHub — приватный тоже подойдёт. Платформа видит описание сервисов, поднимает базу и приложение и выдаёт публичный HTTPS-адрес, а логи сборки и запуска видны в панели в реальном времени.
Шаг 6. SQLite или PostgreSQL
SQLite годится для небольшого проекта, но только если файл базы лежит в постоянной папке /data. Файл рядом с кодом пересоздаётся при каждой публикации, и все записи в нём теряются. У проектов с собственным docker-compose папки /data нет — там постоянное хранилище задаётся именованным томом из вашего файла.
PostgreSQL стоит брать, если данных станет больше или к базе будут обращаться несколько сервисов одновременно. Меняется немногое: в описании сервисов вместо папки появляется образ postgres, и та же строка DATABASE_URL указывает уже на хост db.
Сколько это стоит и как работают контейнеры
Администрировать сервер не нужно — контейнеры работают постоянно, без ограничения по часам и без «засыпания». Упавший контейнер платформа перезапускает сама.
Starter — 990 ₽/мес. 1 vCPU, 2 GB RAM, 20 GB SSD, один проект. Первый месяц бесплатный. Для приложения с базой этого достаточно, и лимита по времени работы у тарифа нет.
Pro — 2 490 ₽/мес. 2 vCPU, 4 GB RAM, до пяти проектов — если рядом живут база, кеш и воркер.
Team — 4 990 ₽/мес — для команд, которым нужен запас ресурсов и SLA.
Тарифы и подробности — на dockbox.host.
Частые вопросы
Пропадут ли данные при обновлении кода?
Нет, если у базы подключён именованный том. Обновление тогда пересобирает только приложение, а файлы базы остаются на месте. Без тома данные лежат внутри контейнера и стираются при первой же повторной публикации, поэтому этот шаг обязателен.
Какие базы можно запустить?
Любые, для которых есть готовый образ: PostgreSQL, MySQL, MariaDB, MongoDB, Redis и другие. Достаточно описать сервис в docker-compose.yml — устанавливать и настраивать вручную нечего.
Как приложение подключается к базе?
По имени сервиса из файла описания. Если база называется db, строка подключения указывает на хост db и стандартный порт базы. IP-адреса не нужны: при перезапуске они меняются, а имя остаётся прежним.
Будет ли база доступна из интернета?
Нет. Публичный адрес получает только приложение, а база видна лишь соседним сервисам внутри проекта. Так и надо: база, открытая наружу, — самый частый способ потерять данные.
Как прогнать миграции после деплоя?
Терминала внутри проекта нет, поэтому миграции выполняются при старте. Вызовите migrate в начале стартовой команды, перед запуском сервера, — так таблицы обновляются на каждом деплое, а не при первом визите пользователя.