Docker и Compose

Бэкап Docker volumes и баз в контейнерах

Именованный том переживёт пересоздание контейнера, но не потерю сервера и не docker volume prune. dbsend сохраняет содержимое томов версиями в российском облаке: для баз — логические дампы прямо из контейнеров, для остальных данных — tar-архивы. Всё по cron и с алертом, если бэкап не пришёл.

  • Данные в РФ
  • AES-256-GCM
  • Бесплатный тариф без карты
$ docker exec postgres pg_dump -U app --format=plain app > /var/backups/app.sql$ dbsend backup /var/backups/app.sql -d 9b17… -e postgresql_dump✓ Версия v41 сохранена (id 5d0c…, 48 МБ)  https://dbsend.ru/databases/9b17…/snapshots$ docker run --rm -v stack_uploads:/data:ro -v /var/backups:/backup alpine tar czf /backup/uploads.tar.gz -C /data .$ dbsend backup /var/backups/uploads.tar.gz -d c8d1… -e generic_file✓ Версия v6 сохранена (id 90ae…, 640 МБ)

Почему копировать /var/lib/docker/volumes — плохая идея

Том — это обычный каталог на диске хоста, и его легко заархивировать. Но если в нём лежат файлы работающей базы PostgreSQL или MySQL, копия «на ходу» почти наверняка окажется несогласованной: часть страниц записана до транзакции, часть — после. Такая копия может не запуститься или запуститься с повреждёнными данными.

Вторая ловушка — версия. Каталог данных PostgreSQL привязан к мажорной версии сервера: файлы от PostgreSQL 15 не запустятся на 16. Логический дамп переносим между версиями и серверами.

Третья — всё лежит на одном хосте. docker compose down -v, docker volume prune или сбой диска — и вместе с томом пропадают локальные архивы, если их складывали рядом.

Что даёт dbsend для Docker

Логические дампы из контейнеров

pg_dump и mysqldump запускаются внутри контейнера через docker exec и пишут дамп на хост — база продолжает работать. dbsend хранит дампы версиями, а на тарифах от «Старт» показывает таблицы, число строк и diff.

Архивы обычных томов

Загрузки, конфиги, данные приложений: том архивируется одноразовым контейнером alpine и загружается как generic_file — с версиями и проверкой SHA-256, но без разбора содержимого архива.

SQLite без остановки

Если база SQLite лежит в томе, CLI на хосте сделает согласованную копию через VACUUM INTO: приложение в контейнере продолжает писать, а в облако уходит целостный файл.

Алерты для любого оркестратора

Ожидаемый интервал и уведомления в Telegram или на email, если бэкап не пришёл (тарифы от «Старт»). Работает одинаково для Compose, Coolify, Portainer и голого docker run.

Как это работает

Настройка: дампы, архивы томов, cron

Установите CLI на хост (Node.js 22.12+) и выполните dbsend login. Для каждого источника создайте в панели отдельную базу с подходящим типом: postgresql_dump, mysql_dump, sqlite или generic_file. Имена томов смотрите командой docker volume ls — Compose добавляет к ним имя проекта, например stack_pgdata.

  1. Базы в контейнерах — логические дампы

    # PostgreSQL (без -t: псевдотерминал может испортить вывод)
    docker exec postgres pg_dump -U app --format=plain app > /var/backups/app.sql
    dbsend backup /var/backups/app.sql -d <id базы> -e postgresql_dump
    
    # MySQL / MariaDB
    docker exec mysql sh -c 'exec mysqldump --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD" shop' > /var/backups/shop.sql
    dbsend backup /var/backups/shop.sql -d <id базы> -e mysql_dump
    
    # SQLite в томе: CLI сам сделает согласованную копию через VACUUM INTO
    sudo dbsend backup /var/lib/docker/volumes/stack_appdata/_data/app.db -d <id базы> -e sqlite

    В образах MariaDB 11+ используйте mariadb-dump и переменную MARIADB_ROOT_PASSWORD. Каталог /var/lib/docker/volumes доступен только root — dbsend login нужно выполнить и для root.

  2. Обычный том — архив через одноразовый контейнер

    docker run --rm -v stack_uploads:/data:ro -v /var/backups:/backup alpine \
      tar czf /backup/uploads.tar.gz -C /data .
    dbsend backup /var/backups/uploads.tar.gz -d <id базы> -e generic_file

    Том монтируется только для чтения (:ro). Архив сохраняет права и владельцев файлов — распаковывайте его тем же способом, от root внутри контейнера.

  3. Согласованность: остановите тех, кто пишет в том

    docker compose stop app worker
    docker run --rm -v stack_uploads:/data:ro -v /var/backups:/backup alpine \
      tar czf /backup/uploads.tar.gz -C /data .
    docker compose start app worker
    dbsend backup /var/backups/uploads.tar.gz -d <id базы> -e generic_file

    Остановка нужна, только если приложение активно пишет в том и важна целостность набора файлов. Контейнеры баз не останавливайте — для них есть дампы из шага 1. Загрузку в облако делайте уже после запуска приложения.

  4. Скрипт и cron

    #!/usr/bin/env bash
    # /usr/local/bin/docker-backup.sh
    set -euo pipefail
    cd /var/backups
    docker exec postgres pg_dump -U app --format=plain app > app.sql
    dbsend backup ./app.sql -d "$PG_DB_ID" -e postgresql_dump -l "nightly-$(date +%F)"
    docker run --rm -v stack_uploads:/data:ro -v "$PWD":/backup alpine \
      tar czf /backup/uploads.tar.gz -C /data .
    dbsend backup ./uploads.tar.gz -d "$UPLOADS_DB_ID" -e generic_file
    rm -f app.sql uploads.tar.gz
    
    # crontab -e (root): каждую ночь в 03:15
    15 3 * * * PG_DB_ID=9b17… UPLOADS_DB_ID=c8d1… /usr/local/bin/docker-backup.sh >> /var/log/docker-backup.log 2>&1
  5. Восстановление

    dbsend restore <id версии> /var/backups/app.sql --yes
    docker exec postgres createdb -U app app_restore
    docker exec -i postgres psql -U app -d app_restore < /var/backups/app.sql
    
    dbsend restore <id версии> /var/backups/uploads.tar.gz --yes
    docker run --rm -v stack_uploads_restore:/data -v /var/backups:/backup alpine \
      tar xzf /backup/uploads.tar.gz -C /data

    Для psql нужен флаг -i, чтобы дамп попал в stdin контейнера. Восстанавливайте в новую базу и новый том, проверяйте и только потом переключайте сервис.

Coolify, Compose и Portainer

В Coolify у управляемых баз есть собственные плановые бэкапы в S3 — их можно оставить. dbsend пригодится как независимая копия с версиями и diff, а также для того, что Coolify сам не бэкапит: томов приложений и сервисов. Имена томов видны в настройках хранилища ресурса и в docker volume ls, а контейнер базы ищите через docker ps — в его имени есть идентификатор ресурса.

В Docker Compose удобнее обращаться к сервису, а не к контейнеру: docker compose exec -T db pg_dump -U app app > app.sql. Флаг -T отключает псевдотерминал — без него дамп может испортиться.

Скрипт запускайте на хосте, а не внутри контейнера приложения: так он переживёт пересборку образа и не будет зависеть от его содержимого. Если хостов несколько, поставьте CLI на каждый и создайте отдельные базы в dbsend — у каждой своя история версий.

dbsend или свой скрипт tar + S3

  • Логические дампы БД вместо сырых файлов

    tar + cron + S3
    если не забыли
    dbsend
    pg_dump, mysqldump, VACUUM INTO
  • Ключи от бакета на хосте

    tar + cron + S3
    нужны
    dbsend
    не нужны
  • Diff дампов (таблицы, строки, схема)

    tar + cron + S3
    dbsend
    для дампов и SQLite, от «Старт»
  • Время на настройку

    tar + cron + S3
    скрипт, бакет, ключи, ротация — часы
    dbsend
    3 команды — несколько минут
  • История версий с метками

    tar + cron + S3
    имена файлов по дате
    dbsend
    v1…vN, метки, закрепление
  • Не плодит одинаковые копии

    tar + cron + S3
    dbsend
  • Проверка SHA-256 при восстановлении

    tar + cron + S3
    если написали сами
    dbsend
  • Алерт, если бэкап не пришёл

    tar + cron + S3
    dbsend
    Telegram и email
  • Шифрование и хранение в РФ

    tar + cron + S3
    зависит от бакета
    dbsend
    AES-256-GCM, РФ
  • Доступ из Claude Code и Cursor (MCP)

    tar + cron + S3
    dbsend
  • Стоимость

    tar + cron + S3
    хранилище + ваше время
    dbsend
    от 0 ₽

Тарифы и лимиты — на странице «Тарифы». Документация: CLI, форматы файлов, базы.

Частые вопросы

Можно ли просто заархивировать том с PostgreSQL?

Только с остановленным контейнером базы, и восстанавливать придётся на ту же мажорную версию PostgreSQL. Надёжнее логический дамп pg_dump через docker exec: база продолжает работать, дамп переносим, а dbsend разбирает его по таблицам.

Нужно ли останавливать контейнеры на время бэкапа?

Для баз — нет, используйте дампы. Для обычных томов — если приложение пишет в них во время архивации и важно, чтобы набор файлов был согласован. Остановка длится ровно столько, сколько создаётся архив.

Почему неизменившийся том каждый раз создаёт новую версию?

gzip записывает в архив время создания, поэтому контрольная сумма каждый раз другая. Если важно не плодить одинаковые версии, собирайте архив GNU tar с --sort=name и сжимайте через gzip -n. Для SQLite это работает сразу, а mysqldump по умолчанию дописывает в дамп дату — её отключает флаг --skip-dump-date.

Где хранить API-ключ dbsend?

dbsend login сохраняет ключ в конфиг пользователя на хосте с правами 600 — в образы, контейнеры и docker-compose.yml его класть не нужно. Ключ можно ограничить одной базой и сроком действия.

Какой максимальный размер архива тома?

«Бесплатный» — 100 МБ, «Старт» — 500 МБ, «Про» — 2 ГБ, «Команда» — 2 ГБ. Файлы больше 32 МБ CLI загружает частями. Большой том разбейте на несколько архивов по подкаталогам — каждый в свою базу dbsend.

Статьи по теме

Все статьи →

Другие сценарии

Тома живут на одном диске. Бэкапы — не должны

Бесплатный тариф: 1 база, 500 МБ и 3 версии, карта не нужна. Первый дамп из контейнера — за пару минут.