gitaspen docs

Резервное копирование и восстановление

Что копировать, куда, как проверять и как восстанавливаться. Документ исходит из того, что резервная копия существует не сама по себе, а ради восстановления: непроверенная копия равнозначна её отсутствию.

6 минут

Что копировать, куда, как проверять и как восстанавливаться. Документ исходит из того, что резервная копия существует не сама по себе, а ради восстановления: непроверенная копия равнозначна её отсутствию.

Что нужно до начала: работающий сервер с приложением, доступ к хранилищу вне этого сервера.

Место в цепочке

Откуда пришлиЭтот документКуда ведёт
приложение выкатывается и работаетчто копируем, куда, как восстанавливаем и как это проверяетсянаблюдение за системой, включая контроль свежести копий

Что предыдущее звено обязано обеспечить: перед миграциями базы делается снимок — выкат с изменением схемы без свежей копии не имеет пути назад.


Что копировать, а что нет

ДанныеКопироватьПочему
база данныхдаединственный экземпляр, пересоздать нельзя
загруженные файлы (тома)дато же самое
секреты и файлы окружениядане лежат в репозитории; без них восстановленная система не запустится
конфигурация сервера вне репозиториядавоспроизводится по памяти дорого
исходный коднетлежит в репозитории
образы контейнеровнетпересобираются из кода
логиобычно нетвосстановлению не помогают; хранятся отдельно и недолго

Проверка полноты — мысленный опыт: сервер уничтожен целиком. Что нужно, чтобы поднять систему заново? Всё из этого списка должно быть в копии либо в репозитории.


Куда класть

Копия хранится вне сервера, который копируется. Копия на том же диске защищает только от случайного удаления файла и не защищает ни от отказа диска, ни от потери доступа к серверу, ни от шифровальщика.

Минимально достаточная схема: свежие копии на сервере (быстрое восстановление) + отправка во внешнее хранилище (защита от потери сервера).

Доступ к внешнему хранилищу выдаётся отдельным ключом только на запись и чтение своего каталога. Ключ с правом удаления, лежащий на сервере, означает, что тот, кто получил сервер, удалит и копии.


Как копировать базу

Логический снимок переносим между версиями и читаем человеком:

bash
pg_dump --format=custom --no-owner --no-privileges "$DATABASE_URL" > db-$(date -u +%Y%m%dT%H%M%SZ).dump
  • --format=custom — сжатый формат, из которого можно восстановить выборочно;
  • --no-owner, --no-privileges — снимок не тянет за собой пользователей и права конкретной установки, поэтому восстанавливается на другом сервере.

Снимать копию с работающей базы допустимо: команда видит согласованное состояние на момент старта.

Если база работает в контейнере, снимок делается клиентом той же основной версии — иначе формат может оказаться несовместим.

Проверка: файл ненулевого размера и читается инструментом восстановления:

bash
ls -lh db-*.dump
pg_restore --list db-*.dump | head     # ожидается перечень объектов, а не ошибка формата

Как копировать файлы и секреты

Тома контейнеров и каталоги с секретами — архивом, права и владельцы сохраняются:

bash
tar -czf files-$(date -u +%Y%m%dT%H%M%SZ).tar.gz -C /var/lib/app uploads
tar -czf secrets-$(date -u +%Y%m%dT%H%M%SZ).tar.gz -C /opt/app .secrets

Архив с секретами шифруется до отправки во внешнее хранилище: там он лежит долго и доступен всем, у кого есть доступ к хранилищу.

bash
gpg --symmetric --cipher-algo AES256 secrets-*.tar.gz     # результат: .gpg, исходный файл удалить

Пароль шифрования хранится не на этом сервере — иначе он теряется вместе с ним.


Расписание и срок хранения

Частота определяется тем, потерю какого объёма работы вы готовы принять: суточная копия означает, что в худшем случае теряются сутки.

Срок хранения задаётся так, чтобы пережить незамеченную порчу данных. Если ошибка обнаруживается через неделю, а копии хранятся три дня, восстанавливать будет нечего. Распространённая схема: ежедневные копии за последние две недели плюс еженедельные за несколько месяцев.

Старые копии удаляются автоматически: ручная чистка либо не делается, либо однажды удаляет нужное.


Проверка восстановлением

Единственное доказательство, что копия рабочая, — восстановление из неё. Проверка делается регулярно и не на боевой машине.

bash
# 1. поднять пустую базу для проверки
docker run --rm -d --name restore-check -e POSTGRES_PASSWORD=check -p 15432:5432 postgres:18-alpine

# 2. восстановить копию
pg_restore --clean --if-exists --no-owner -d "postgresql://postgres:check@127.0.0.1:15432/postgres" db-*.dump

# 3. убедиться, что данные на месте
psql "postgresql://postgres:check@127.0.0.1:15432/postgres" -c "\dt"
psql "postgresql://postgres:check@127.0.0.1:15432/postgres" -c "SELECT count(*) FROM <ключевая таблица>"

# 4. убрать проверочную базу
docker rm -f restore-check

Ожидается: восстановление без ошибок, таблицы на месте, число записей близко к боевому.

Проверять стоит и свежесть: копия, которая перестала создаваться месяц назад, выглядит как работающая, пока её не понадобится восстановить. Возраст последней копии — хороший повод для оповещения (см. документ о наблюдении).


Восстановление

Порядок при потере сервера:

  1. поднять чистый сервер, поставить Docker;
  2. получить копии из внешнего хранилища;
  3. расшифровать и распаковать секреты и файлы;
  4. развернуть код из репозитория, собрать образы;
  5. поднять базу, восстановить снимок;
  6. запустить приложение, проверить служебные ручки;
  7. направить домен на новый сервер, выпустить сертификат.

Порядок важен: приложение стартует после восстановления базы, а домен переключается последним, когда система уже отвечает.

Частичное восстановление — когда потеряны отдельные данные, а система работает. Снимок в пользовательском формате позволяет восстановить одну таблицу, не трогая остальные:

bash
pg_restore --data-only --table=<таблица> -d "$DATABASE_URL" db-*.dump

Перед этим стоит сделать копию текущего состояния: восстановление поверх живых данных необратимо.


Типичные отказы

ПризнакПричинаЧто делать
копия создаётся, но пустаяу пользователя нет прав на чтение данныхпроверить права; контролировать размер файла, а не факт запуска
pg_restore не читает файлснимок снят клиентом новее сервераиспользовать клиент той же основной версии
восстановление падает на правах и владельцахснимок снят без --no-ownerпересоздать снимок с нужными флагами
копий нет за последние неделизадание перестало выполняться молчаоповещение по возрасту последней копии
копии есть, но не восстанавливаютсяникогда не проверялисьввести регулярную проверку восстановлением
копии удалены вместе с серверомключ доступа к хранилищу разрешал удалениеключ только на запись; хранение с защитой от удаления
восстановили, приложение не стартуетне скопированы секреты и окружениевключить их в копию и в проверку
Инструкция не помогла?

Откройте исходник документа по ссылке «Предложить правку» — там же видно, что и когда в нём менялось.