{{description>Скрипт для архивирования всех баз PostgreSQL на Linux (улучшенная версия) }}
====== Скрипт архивирования всех баз PostgreSQL на Linux (Версия 2.0). ======
[[http://wiki.mihanik.net/doku.php?id=субд:postgresql:скрипт_архивирования_всех_баз_postgresql_на_linux_ver-2.0&do=export_pdf|Экспорт в PDF ]] ~~ODT~~
Дата создания: 2026/07/01 08:43 (C) mihanik
{{ :субд:postgresql:pg_backup.png?600 |}}
===== Дано =====
* Операционная система Linux с установленным PostgreSQL.
* В СУБД создано несколько баз.
* Имеется текстовый файл со списком баз, которые нужно архивировать.
===== Надо =====
* Создать архивную копию баз из списка.
* Бекап каждой базы должен храниться в отдельном архивном файле.
* Во время архивации старые архивные копии должны перезаписываться.
===== Решение =====
Предыдущая версия скрипта расположена тут: [[:субд:postgresql:скрипт_архивирования_всех_баз_postgresql_на_linux|Скрипт архивирования всех баз postgresql на linux]]
Исходный скрипт решал задачу, но был уязвим в нескольких местах.
Вот что было улучшено по категориям:
==== 🛡️ Надёжность и защита данных ====
| Было | Стало | Зачем |
|`rm -f $BackupDir/$dbname.sql.gz` перед созданием|Запись в `.tmp` + `mv`|Если бэкап упадёт, старый архив не будет потерян|
|Нет проверки результата `pg_dump`|`if pg_dump …; then … else … fi`|Ошибки фиксируются, битые файлы удаляются|
|Нет ротации|`find … -mtime +7 -delete`|Диск не переполнится старыми архивами\\ Ротация (закомментирована, включается при необходимости)|
==== 🔒 Безопасность ====
| Было | Стало | Зачем |
|`$BackupDir/$dbname.sql.gz` без кавычек|`"$BackupDir/${dbname}.dump"`|Защита от имён с пробелами|
|Парсинг через `tail|head|egrep`|SQL-фильтр `WHERE datistemplate = false`|Не зависит от формата вывода `psql`|
==== 📋 Функциональность ====
| Было | Стало | Зачем |
|Бэкап всех БД кроме шаблонов|Список из файла `/opt/scripts/pg_backup_list.lst`|Можно бэкапить только нужные БД, игнорировать комментарии|
|Plain SQL + `gzip`|Кастомный формат `-Fc -Z 6`|Быстрее, компактнее, можно восстанавливать отдельные таблицы|
|Нет отчёта|Счётчики `total/success/failed`|Видно результат выполнения|
|Код возврата всегда 0|`exit 1` при ошибках|Мониторинг (Zabbix, Prometheus) замечает сбои|
==== 📝 Удобство эксплуатации ====
| Было | Стало | Зачем |
|`echo "Архив создан"`|`log()` с временными метками в файл и консоль|Есть история в `/var/log/pg_backup.log`|
|Нет обработки peer-ошибок|`-h localhost` в командах|Работает из-под любого пользователя ОС|
|Нет создания директории|`mkdir -p "$BackupDir"`|Скрипт не падает, если папка ещё не создана|
|Нет проверки списка БД|Проверка существования `LIST_FILE`|Ясная ошибка вместо молчаливого провала|
==== 🎯 Ключевые архитектурные изменения ====
=== 1. Формат бэкапа ===
**Было**: pg_dump | gzip → .sql.gz\\
**Стало**: pg_dump -Fc -Z 6 → .dump
**Это даёт:**
* Встроенное сжатие (не нужен gzip)
* Возможность параллельного восстановления (pg_restore -j 4)
* Возможность восстановить одну таблицу из дампа: pg_restore -t users ...
* Меньше нагрузка на CPU при дампе
=== 2. Список баз ===
**Было**: Автоматический, все БД кроме шаблонов\\
**Стало**: Управляемый файл /opt/scripts/pg_backup_list.lst с комментариями
=== 3. Аутентификация ===
* **Было**: Подключение через unix-сокет → ошибка Peer authentication failed\\
* **Стало**: -h localhost → TCP-подключение с проверкой пароля
==== Файл со списком баз ====
Создайте файл со списком баз для бэкапа: **/opt/scripts/pg_backup_list.lst**
# Список баз для бэкапа
my_db1
my_db2
# analytics - временно отключена
==== Сам скрипт ====
#!/bin/bash
# === Настройки ===
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
BackupDir="/mnt/backups/pgsql"
LIST_FILE="/opt/scripts/pg_backup_list.lst"
LOG_FILE="/var/log/pg_backup.log"
# Уровень сжатия кастомного формата (0-9, по умолчанию 6)
DUMP_COMPRESSION=6
# === Функции ===
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# === Проверки ===
mkdir -p "$BackupDir" || { log "ОШИБКА: не удалось создать $BackupDir"; exit 1; }
if [ ! -f "$LIST_FILE" ]; then
log "ОШИБКА: файл со списком баз $LIST_FILE не найден."
exit 1
fi
# === Аутентификация ===
# Рекомендуется использовать ~/.pgpass вместо PGPASSWORD
export PGPASSWORD="123456"
log "=== Начало процесса бэкапа ==="
# === Счётчики для отчёта ===
total=0
success=0
failed=0
# === Основной цикл ===
while IFS= read -r dbname || [ -n "$dbname" ]; do
# Убираем пробелы по краям
dbname="$(echo "$dbname" | xargs)"
# Пропускаем пустые строки и комментарии
[[ -z "$dbname" || "$dbname" =~ ^[[:space:]]*# ]] && continue
total=$((total + 1))
log "[$total] Обработка базы: $dbname"
temp_file="$BackupDir/${dbname}.dump.tmp"
final_file="$BackupDir/${dbname}.dump"
# -Fc — кастомный формат (сжатый, бинарный)
# -Z — уровень сжатия (0-9)
if pg_dump -h localhost -U postgres -Fc -Z "$DUMP_COMPRESSION" "$dbname" > "$temp_file"; then
mv "$temp_file" "$final_file"
log "Успешно создан архив: $final_file"
success=$((success + 1))
else
log "ОШИБКА при создании архива $dbname! Старый бэкап сохранен."
rm -f "$temp_file"
failed=$((failed + 1))
fi
done < "$LIST_FILE"
# === Ротация: удаляем бэкапы старше 7 дней ===
# Закомментирована
#find "$BackupDir" -name "*.dump" -type f -mtime +7 -delete
#log "Ротация завершена: удалены файлы старше 7 дней."
# === Итог ===
unset PGPASSWORD
log "=== Завершение: всего=$total успешно=$success ошибок=$failed ==="
if [ "$failed" -gt 0 ]; then
exit 1
fi
===== Источники =====
[[#top|Наверх ]]