{{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|Наверх ]]