Постоянные данные и база PostgreSQL
До этого мы могли восстановить сайт выбором известного артефакта. У приложения появляются данные, которых нет внутри образа: записи базы, загруженные файлы и результаты действий пользователя. Теперь разделим эти состояния на учебном release-lab-app. Самая важная граница: пересоздание контейнера кода не должно означать удаление накопленных данных.
Для отдельной прикладной ветки выберем PostgreSQL 16. Это фиксированная учебная версия, а не заявление о последней версии сервера или составе ProfessorWeb. Программа прошлого урока пока не использует базу; здесь подготавливаем хранилище и таблицу для последующего разбора миграций. Не будем изображать подключение, которого в приведённом WSGI-коде ещё нет.
Три разных типа файлов
Код и библиотеки относятся к образу приложения. Временные файлы можно пересоздать и обычно не нужно включать в копию. Постоянные данные должны пережить остановку и замену процесса. На обычном VPS им выделяют, например, /srv/release-lab/shared/uploads; в контейнерном варианте используют именованный том или осознанное подключение каталога хоста. Смена current не переносит эти данные в новый каталог автоматически.
Docker volume живёт отдельно от файлового слоя контейнера. Это позволяет пересоздать экземпляр без потери состояния тома, но не защищает от удаления самого тома или отказа хоста. Команды очистки требуют понимания, какие объекты содержат данные. Нельзя относиться к down -v как к безобидному завершению процесса, если его том хранит базу. Официальная документация Docker volumes.
Подготовить отдельный сервис базы
Добавим следующий фрагмент к Compose-конфигурации прошлого урока. Это дополнение, не замена определения app. База не публикует порт на внешнем интерфейсе. Контейнеры одного проекта смогут обращаться к имени db; процесс на самом хосте не получает это имя автоматически и потребует другой специально описанной схемы соединения.
services:
db:
image: postgres:16
environment:
POSTGRES_DB: release_lab
POSTGRES_USER: release_lab
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- db_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
db_data:
secrets:
db_password:
file: /etc/release-lab/postgres-password
Секрет создаётся владельцем стенда вне репозитория с ограниченным доступом; реальное значение в статье отсутствует. В примере используется каталог данных образа PostgreSQL 16. Для других крупных версий образа правила могут отличаться, поэтому нельзя менять тег на произвольный latest, сохраняя остальную схему без чтения инструкции. Параметры начальной инициализации также не означают автоматическую смену пароля уже существующей базы при каждой правке переменной.
Для полностью повторяемого запуска выбирают проверенный образ с точной версией или digest. Тег 16 здесь обозначает учебное семейство. До подготовки нового экземпляра читатель записывает фактический образ и совместимость клиента резервирования. Эти сведения понадобятся при восстановлении. База и её данные не становятся частью архива статических HTML только потому, что находятся на том же VPS. Инструкция официального образа PostgreSQL.
Небольшая таблица для продолжения
На отдельной пустой учебной базе будущий читатель может создать таблицу с двумя строками. Это собственные примерные данные, а не извлечение материалов ProfessorWeb. У таблицы пока есть только идентификатор и заголовок. Следующий урок добавит описание, сохранив совместимость кода, который знает лишь эти поля.
CREATE TABLE articles (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title text NOT NULL
);
INSERT INTO articles (title) VALUES
('Статический сайт из Markdown'),
('Публикация известного выпуска');
После будущего выполнения ожидаются две записи. При повторном запуске этот фрагмент не следует применять вслепую: таблица уже существует, а данные могли измениться. Начальное заполнение и миграции — разные операции. Содержимое базы подтверждают запросом в конкретном окружении, отмечая время и источник. Строки урока не являются результатом выполнения SQL.
Согласованная копия базы
Копирование каталога работающей PostgreSQL обычным файловым архиватором не равно корректной резервной копии. Для нашего небольшого примера используем логический дамп. pg_dump получает согласованный снимок одной базы в рамках своего механизма. Он не сохраняет автоматически все внешние файлы приложения и общие роли кластера. Если восстановление зависит от них, состав набора расширяют отдельно. Документация PostgreSQL 16 о SQL-дампе.
docker compose exec -T db pg_dump -U release_lab -d release_lab -Fc \
> release-lab-db.dump
Используем инструмент из выбранного контейнера базы, чтобы не скрыть несовпадение версии клиента. Файл на стороне оператора защищают и передают в независимое хранилище. Пароль не пишут непосредственно в команду или урок; конкретный способ аутентификации согласуют со стендом. Успешное завершение дампа и размер файла — первоначальные признаки, но не доказательство способности восстановить приложение.
Восстановить отдельно и прочитать данные
Пробную базу создают отдельно от действующей, с собственным именем или отдельным экземпляром. Дамп в формате custom восстанавливают через pg_restore, а не передают как SQL в psql. Проверка должна остановиться при ошибке и показать понятный результат. Роли и права назначения подготавливают заранее; параметры управления владельцем выбирают по задаче, а не скрывают все ошибки восстановления.
pg_restore --exit-on-error --no-owner \
-d release_lab_recovery release-lab-db.dump
Листинг предполагает уже созданную пустую учебную базу и доверенные настройки подключения к ней. Команда не выполнялась. После восстановления читают две ожидаемые строки, структуру таблицы и необходимые права. Затем подключают совместимое приложение в закрытой среде. Только такое наблюдение проверяет практический смысл копии, а не существование отдельного файла дампа.
Версия клиента резервирования не должна быть старше обслуживаемой версии сервера в несовместимом направлении: старый pg_dump не обязан понимать более новый сервер. Также при восстановлении учитывают расширения и доступные типы. Архив одной базы не создаёт автоматически все необходимые роли кластера. Поэтому паспорт копии содержит версию инструментов и отдельные предпосылки, а пробный запуск выполняется в подготовленной среде. Ошибка отсутствующего расширения не исправляется повторным скачиванием того же файла. Справочник pg_dump PostgreSQL 16.
Файлы и база должны объяснять один момент
Если строка базы ссылается на загруженное изображение, дамп и копия uploads могут представлять разные моменты. В результате запись восстановлена, а файл отсутствует. Для небольшого приложения можно выбрать окно ограничения записи и сделать согласованный набор; более сложные варианты требуют специального механизма. Важно описать выбранную точку и допустимую потерю новых действий, не обещая согласованность двух независимых копирований.
Мы получили постоянное хранилище и отдельный способ его восстановления. Возврат образа теперь не равен возврату всего приложения. Следующий урок разберёт, как менять схему базы так, чтобы прежний код ещё мог работать и быстрый откат не требовал уничтожения новых записей.