Перейти к основному содержимому
Версия: 2.0 (WIP)

СУБД PostgreSQL

В Памир конфигурация и накопленные данные приложения хранятся в СУБД PostgreSQL, запущенной в контейнере Docker (сервис database). База данных приложения называется srm и принадлежит пользователю приложения; кроме неё в кластере PostgreSQL присутствуют служебная БД postgres и роли (пользователи).

Рекомендованная стратегия

Для PostgreSQL рекомендуется логическое резервное копирование утилитами pg_dump / pg_dumpall с восстановлением через pg_restore / psql. Этот способ даёт application-consistent копию, переносимую между версиями и инсталляциями, и не требует остановки сервиса.

Параметры подключения

ПараметрЗначениеИсточник
Сервис / контейнерdatabasedocker-compose.deps.yml
Суперпользователь$POSTGRES_USER (по умолчанию postgres).postgres.env
Пароль суперпользователя$POSTGRES_PASSWORD.postgres.env
Пользователь приложения$POSTGRES_APP_USER.postgres.env
БД приложения$POSTGRES_APP_DB (по умолчанию srm).postgres.env
Каталог данных (PGDATA)/var/lib/postgresql/dataтом pamir_database-data
примечание

Переменные окружения (POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_APP_DB и др.) уже заданы внутри контейнера database из файла .postgres.env. Поэтому в примерах ниже на них можно ссылаться напрямую внутри sh -c '…', не подставляя значения вручную.

Все команды выполняются из каталога приложения ($HOME/.pamir или /opt/pamir).

Флаг -T при перенаправлении вывода

Для команд, вывод которых перенаправляется в файл на хосте (> backup.dump), используйте docker compose exec -T (без выделения псевдотерминала). Псевдотерминал (-it) искажает двоичный поток и делает дамп непригодным для восстановления. Флаг -it уместен только для интерактивных сессий (psql).

Резервное копирование

Дамп базы данных приложения

Дамп БД srm в пользовательском (custom) формате — наиболее гибкий вариант: позволяет выборочное восстановление и сжимается «на лету».

cd "$HOME/.pamir"
mkdir -p "$HOME/pamir-backups"

docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump \
-U "$POSTGRES_USER" -d "$POSTGRES_APP_DB" -Fc' \
> "$HOME/pamir-backups/srm-$(date +%F).dump"

где:

  • -Fc — custom-формат (сжатый, для pg_restore);
  • -d "$POSTGRES_APP_DB" — БД приложения (srm).

Дамп ролей (глобальных объектов)

Роли и права не входят в дамп отдельной БД, поэтому их выгружают отдельно:

cd "$HOME/.pamir"

docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dumpall \
-U "$POSTGRES_USER" --globals-only' \
> "$HOME/pamir-backups/globals-$(date +%F).sql"

Полный дамп кластера (альтернатива)

Если нужно сохранить весь кластер PostgreSQL единым файлом (все БД + роли) в текстовом формате:

cd "$HOME/.pamir"

docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dumpall -U "$POSTGRES_USER"' \
| gzip > "$HOME/pamir-backups/cluster-$(date +%F).sql.gz"

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

warning

Восстановление выполняется при работающем сервисе database, но остановленных сервисах приложения Памир, чтобы исключить запись в БД во время восстановления.

Команда pamirctl start <сервис> поднимает весь стек, поэтому для запуска только СУБД используйте напрямую docker compose:

docker compose stop          # остановить все сервисы
docker compose start database # поднять только СУБД (и её зависимости)

Восстановление из custom-дампа

Сначала восстановите роли (если восстанавливаете на чистый кластер), затем — БД приложения:

cd "$HOME/.pamir"

# 1. Роли (при необходимости)
docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d postgres' \
< "$HOME/pamir-backups/globals-2026-06-08.sql"

# 2. БД приложения: пересоздать схему и загрузить данные
docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_restore \
-U "$POSTGRES_USER" -d "$POSTGRES_APP_DB" \
--clean --if-exists' \
< "$HOME/pamir-backups/srm-2026-06-08.dump"

где:

  • --clean --if-exists — удалить существующие объекты перед загрузкой.
Не используйте --no-owner

Восстановление выполняется от суперпользователя postgres, а объекты БД srm принадлежат пользователю приложения app_postgres. Флаг --no-owner назначил бы всем объектам владельца postgres, и приложение потеряло бы доступ (permission denied).

Поэтому роли восстанавливают первым шагом (чтобы роль app_postgres существовала), а pg_restore запускают без --no-owner — тогда исходное владение (app_postgres) сохраняется.

Восстановление «с нуля»

Если БД srm нужно создать заново, выполните перед загрузкой:

docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d postgres \
-c "DROP DATABASE IF EXISTS \"$POSTGRES_APP_DB\";" \
-c "CREATE DATABASE \"$POSTGRES_APP_DB\" OWNER \"$POSTGRES_APP_USER\";"'

После восстановления запустите приложение:

pamirctl start

Восстановление из полного дампа кластера

cd "$HOME/.pamir"

gunzip -c "$HOME/pamir-backups/cluster-2026-06-08.sql.gz" | \
docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d postgres'

Проверка резервных копий

Поверхностная проверка по размеру и дате, а также целостности дампа:

# Размер и дата
ls -lh "$HOME/pamir-backups/"*.dump "$HOME/pamir-backups/"*.sql* 2>/dev/null

# Просмотр оглавления custom-дампа (TOC) — подтверждает читаемость файла
docker compose exec -T database pg_restore -l \
< "$HOME/pamir-backups/srm-2026-06-08.dump" | head

# Проверка целостности сжатого SQL-дампа
gzip -t "$HOME/pamir-backups/cluster-2026-06-08.sql.gz" && echo "OK"

Если pg_restore -l возвращает оглавление без ошибок, а размер файла соответствует ожидаемому — дамп корректен.

Автоматизация (systemd timer)

Скрипт резервного копирования ~/.local/bin/pamir-backup-postgres.sh:

~/.local/bin/pamir-backup-postgres.sh
#!/usr/bin/env bash
set -euo pipefail

cd "$HOME/.pamir"
DEST="$HOME/pamir-backups"
RETENTION_DAYS=14
mkdir -p "$DEST"
STAMP="$(date +%F_%H-%M)"

# Роли
docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dumpall -U "$POSTGRES_USER" --globals-only' \
> "$DEST/globals-$STAMP.sql"

# БД приложения
docker compose exec -T database \
sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_APP_DB" -Fc' \
> "$DEST/srm-$STAMP.dump"

# Ротация
find "$DEST" -name 'srm-*.dump' -mtime +"$RETENTION_DAYS" -delete
find "$DEST" -name 'globals-*.sql' -mtime +"$RETENTION_DAYS" -delete
chmod +x ~/.local/bin/pamir-backup-postgres.sh

Служба и таймер:

~/.config/systemd/user/pamir-backup-postgres.service
[Unit]
Description=Pamir PostgreSQL logical backup

[Service]
Type=oneshot
ExecStart=%h/.local/bin/pamir-backup-postgres.sh
~/.config/systemd/user/pamir-backup-postgres.timer
[Unit]
Description=Pamir PostgreSQL backup every 6 hours

[Timer]
OnCalendar=*-*-* 00/6:00:00
Persistent=true

[Install]
WantedBy=timers.target

Активация:

systemctl --user daemon-reload
systemctl --user enable --now pamir-backup-postgres.timer
loginctl enable-linger "$USER" # работа таймера без активной сессии
systemctl --user list-timers pamir-backup-postgres.timer

Связанные разделы