notebookvb
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# PostgreSQL Backup - Tower
|
||||
|
||||
PostgreSQL 18 (Docker: `postgresql18`) na Tower (192.168.1.76).
|
||||
|
||||
## Konfigurace
|
||||
|
||||
| Parametr | Hodnota |
|
||||
|----------|---------|
|
||||
| Server | Tower (192.168.1.76) |
|
||||
| Container | `postgresql18` |
|
||||
| Port | 5432 |
|
||||
| User | `vladimir.buzalka` |
|
||||
| Metoda | `pg_dumpall` (všechny DB najednou) |
|
||||
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLBackup/tower/YYYY-MM-DD_HHMM/` |
|
||||
| Retence | 7 dní / posledních 7 záloh |
|
||||
|
||||
## Skripty
|
||||
|
||||
### `postgresqlbackup_with_gzip.sh`
|
||||
Provede `pg_dumpall` všech databází, rolí a tablespaces. Výstup je komprimovaný gzip soubor `all_databases.sql.gz`.
|
||||
|
||||
```bash
|
||||
bash postgresqlbackup_with_gzip.sh
|
||||
```
|
||||
|
||||
Výsledná struktura:
|
||||
```
|
||||
/mnt/user/Backup/Critical/PostgreSQLBackup/tower/
|
||||
└── 2026-05-23_0200/
|
||||
└── all_databases.sql.gz
|
||||
```
|
||||
|
||||
### `postgresqlrestore_from_backup.sh`
|
||||
Obnoví všechny databáze z nejnovější zálohy (nebo ze zadané cesty).
|
||||
|
||||
```bash
|
||||
# Nejnovější záloha (automaticky)
|
||||
bash postgresqlrestore_from_backup.sh
|
||||
|
||||
# Konkrétní záloha
|
||||
bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0200
|
||||
```
|
||||
|
||||
> **POZOR:** Dump obsahuje `--clean --if-exists`, takže restore přepíše existující data.
|
||||
|
||||
### `verify_backup_integrity.sh`
|
||||
Ověří po restore že jsou všechny DB, tabulky, indexy a role přítomny a funkční.
|
||||
|
||||
```bash
|
||||
bash verify_backup_integrity.sh
|
||||
```
|
||||
|
||||
## Nastavení Unraid User Script
|
||||
|
||||
Na Tower přidat User Script `POSTGRESQL_BACKUP`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
bash /boot/config/plugins/user.scripts/scripts/POSTGRESQL_BACKUP/postgresqlbackup_with_gzip.sh
|
||||
```
|
||||
|
||||
Schedule: **Daily**
|
||||
|
||||
## Windows přístup k zálohám
|
||||
|
||||
```
|
||||
\\tower\Backup\Critical\PostgreSQLBackup\
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# CONFIGURATION
|
||||
# ==========================================================
|
||||
CONTAINER_NAME="postgresql18"
|
||||
PG_HOST="localhost"
|
||||
PG_PORT="5432"
|
||||
PG_USER="vladimir.buzalka"
|
||||
export PGPASSWORD="Vlado7309208104++"
|
||||
|
||||
UNRAID_NAME="tower"
|
||||
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLBackup"
|
||||
|
||||
KEEP_DAYS=7
|
||||
KEEP_COUNT=7 # počet posledních záloh k udržení (mimo time-based)
|
||||
|
||||
# ==========================================================
|
||||
# START
|
||||
# ==========================================================
|
||||
echo "Starting PostgreSQL full backup (pg_dumpall)"
|
||||
START_TS=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
DATE=$(date +%Y-%m-%d_%H%M)
|
||||
FINAL_PATH="$BASE_PATH/$UNRAID_NAME/$DATE"
|
||||
mkdir -p "$FINAL_PATH"
|
||||
|
||||
DUMP_FILE="$FINAL_PATH/all_databases.sql.gz"
|
||||
ERR_FILE="$FINAL_PATH/all_databases.err"
|
||||
|
||||
# ==========================================================
|
||||
# DUMP + GZIP
|
||||
# pg_dumpall zachovává: všechny DB, role, tablespaces, grants
|
||||
# Streamuje přes stdout, nepotřebuje volume mount
|
||||
# ==========================================================
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
pg_dumpall \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--clean \
|
||||
--if-exists \
|
||||
| gzip > "$DUMP_FILE" 2> "$ERR_FILE"
|
||||
|
||||
EXIT_CODE=${PIPESTATUS[0]}
|
||||
|
||||
# ==========================================================
|
||||
# VALIDATION
|
||||
# ==========================================================
|
||||
if [ $EXIT_CODE -eq 0 ] && [ -s "$DUMP_FILE" ] && [ ! -s "$ERR_FILE" ]; then
|
||||
echo "SUCCESS: Full PostgreSQL backup completed"
|
||||
echo "Dump size: $(du -h "$DUMP_FILE" | cut -f1)"
|
||||
rm -f "$ERR_FILE"
|
||||
else
|
||||
echo "ERROR: Backup failed"
|
||||
echo "Exit code: $EXIT_CODE"
|
||||
echo "Dump file:"
|
||||
ls -lh "$DUMP_FILE" 2>/dev/null || echo " (not created)"
|
||||
echo "Error output:"
|
||||
[ -s "$ERR_FILE" ] && cat "$ERR_FILE" || echo " (no stderr output)"
|
||||
fi
|
||||
|
||||
# ==========================================================
|
||||
# CLEANUP OLD BACKUPS
|
||||
# 1. Smaž zálohy starší než KEEP_DAYS dnů
|
||||
# 2. Z toho co zbyde, ponech jen posledních KEEP_COUNT
|
||||
# ==========================================================
|
||||
echo "Cleaning up old backups..."
|
||||
find "$BASE_PATH/$UNRAID_NAME" \
|
||||
-mindepth 1 -maxdepth 1 -type d -mtime +$KEEP_DAYS \
|
||||
-exec rm -rf {} \;
|
||||
|
||||
# Nech jen posledních KEEP_COUNT záloh
|
||||
ls -td "$BASE_PATH/$UNRAID_NAME"/*/ 2>/dev/null \
|
||||
| tail -n +$((KEEP_COUNT + 1)) \
|
||||
| xargs -r rm -rf
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo "Backup task completed at $(date)"
|
||||
echo "Started at: $START_TS"
|
||||
set +x
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# CONFIGURATION
|
||||
# ==========================================================
|
||||
CONTAINER_NAME="postgresql18"
|
||||
PG_HOST="localhost"
|
||||
PG_PORT="5432"
|
||||
PG_USER="vladimir.buzalka"
|
||||
export PGPASSWORD="Vlado7309208104++"
|
||||
|
||||
# Cesta k záloze kterou chceš obnovit
|
||||
# Lze předat jako argument, nebo nechá najít nejnovější
|
||||
# Např: $0 /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0200
|
||||
BACKUP_DIR="$1"
|
||||
|
||||
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLBackup/tower"
|
||||
|
||||
# ==========================================================
|
||||
# FIND BACKUP
|
||||
# ==========================================================
|
||||
if [ -z "$BACKUP_DIR" ]; then
|
||||
echo "No backup path specified - using latest available backup"
|
||||
BACKUP_DIR=$(ls -td "$BASE_PATH"/*/ 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$BACKUP_DIR" ]; then
|
||||
echo "ERROR: No backups found in $BASE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$BACKUP_DIR" ]; then
|
||||
echo "ERROR: Backup directory does not exist: $BACKUP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_FILE="$BACKUP_DIR/all_databases.sql.gz"
|
||||
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
echo "ERROR: Backup file not found: $BACKUP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting PostgreSQL restore from: $BACKUP_FILE"
|
||||
echo "Backup date: $(stat -c %y "$BACKUP_FILE" | cut -d' ' -f1-2)"
|
||||
echo "Backup size: $(du -h "$BACKUP_FILE" | cut -f1)"
|
||||
START_TS=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
ERR_FILE="$BACKUP_DIR/all_databases.restore.err"
|
||||
|
||||
# ==========================================================
|
||||
# RESTORE
|
||||
# pg_dumpall dump se obnovuje přes psql
|
||||
# --clean + --if-exists v dumpu zajišťuje drop před recreate
|
||||
# ==========================================================
|
||||
echo "Restoring all databases to PostgreSQL..."
|
||||
gunzip -c "$BACKUP_FILE" \
|
||||
| docker exec -i \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="postgres" \
|
||||
2> "$ERR_FILE"
|
||||
|
||||
RESTORE_EXIT=${PIPESTATUS[1]}
|
||||
|
||||
# ==========================================================
|
||||
# VALIDATION
|
||||
# ==========================================================
|
||||
if [ $RESTORE_EXIT -eq 0 ]; then
|
||||
echo "SUCCESS: All databases restored successfully"
|
||||
rm -f "$ERR_FILE"
|
||||
else
|
||||
echo "ERROR: Restore failed"
|
||||
echo "Exit code: $RESTORE_EXIT"
|
||||
echo "Error output:"
|
||||
[ -s "$ERR_FILE" ] && cat "$ERR_FILE" || echo " (no stderr output)"
|
||||
fi
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo "Restore task completed at $(date)"
|
||||
echo "Started at: $START_TS"
|
||||
set +x
|
||||
@@ -0,0 +1,171 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# VERIFY BACKUP INTEGRITY
|
||||
# Kontroluje že se všechny DB, tabulky a data
|
||||
# správně obnovily po restore
|
||||
# ==========================================================
|
||||
|
||||
CONTAINER_NAME="postgresql18"
|
||||
PG_HOST="localhost"
|
||||
PG_PORT="5432"
|
||||
PG_USER="vladimir.buzalka"
|
||||
export PGPASSWORD="Vlado7309208104++"
|
||||
|
||||
echo "Starting PostgreSQL backup integrity verification..."
|
||||
echo "=========================================="
|
||||
|
||||
ALL_OK=true
|
||||
|
||||
# ==========================================================
|
||||
# 1. CONNECTIVITY CHECK
|
||||
# ==========================================================
|
||||
echo ""
|
||||
echo "Checking PostgreSQL connectivity..."
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="postgres" \
|
||||
--tuples-only \
|
||||
--command="SELECT 'connected';" > /dev/null 2>&1
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ERROR: Cannot connect to PostgreSQL!"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: Connected to PostgreSQL"
|
||||
|
||||
# ==========================================================
|
||||
# 2. LIST ALL DATABASES
|
||||
# ==========================================================
|
||||
echo ""
|
||||
echo "Databases present:"
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="postgres" \
|
||||
--tuples-only \
|
||||
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;"
|
||||
|
||||
# Ulož seznam DB do proměnné pro iteraci
|
||||
DATABASES=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="postgres" \
|
||||
--tuples-only \
|
||||
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;" \
|
||||
| tr -d ' ')
|
||||
|
||||
# ==========================================================
|
||||
# 3. PER-DATABASE CHECKS
|
||||
# ==========================================================
|
||||
for DB_NAME in $DATABASES; do
|
||||
[ -z "$DB_NAME" ] && continue
|
||||
|
||||
echo ""
|
||||
echo "Verifying database: $DB_NAME"
|
||||
echo "------------------------------------------"
|
||||
|
||||
# Počet tabulek
|
||||
TABLE_COUNT=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="$DB_NAME" \
|
||||
--tuples-only \
|
||||
--command="SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';" \
|
||||
| tr -d ' ')
|
||||
|
||||
echo "OK: Tables in public schema: $TABLE_COUNT"
|
||||
|
||||
# Seznam tabulek s počtem řádků
|
||||
echo " Table row counts:"
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="$DB_NAME" \
|
||||
--tuples-only \
|
||||
--command="
|
||||
SELECT
|
||||
schemaname || '.' || relname AS table_name,
|
||||
n_live_tup AS estimated_rows,
|
||||
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
|
||||
FROM pg_stat_user_tables
|
||||
ORDER BY relname;"
|
||||
|
||||
# Počet indexů
|
||||
INDEX_COUNT=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="$DB_NAME" \
|
||||
--tuples-only \
|
||||
--command="SELECT COUNT(*) FROM pg_indexes WHERE schemaname = 'public';" \
|
||||
| tr -d ' ')
|
||||
|
||||
echo "OK: Indexes in public schema: $INDEX_COUNT"
|
||||
|
||||
# Celková velikost DB
|
||||
DB_SIZE=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="$DB_NAME" \
|
||||
--tuples-only \
|
||||
--command="SELECT pg_size_pretty(pg_database_size('$DB_NAME'));" \
|
||||
| tr -d ' ')
|
||||
|
||||
echo "OK: Database size: $DB_SIZE"
|
||||
|
||||
done
|
||||
|
||||
# ==========================================================
|
||||
# 4. CHECK ROLES / USERS
|
||||
# ==========================================================
|
||||
echo ""
|
||||
echo "PostgreSQL roles:"
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
psql \
|
||||
--host="$PG_HOST" \
|
||||
--port="$PG_PORT" \
|
||||
--username="$PG_USER" \
|
||||
--dbname="postgres" \
|
||||
--command="SELECT rolname, rolsuper, rolcreatedb, rolcanlogin FROM pg_roles WHERE rolname NOT LIKE 'pg_%' ORDER BY rolname;"
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
if [ "$ALL_OK" = true ]; then
|
||||
echo "OK: All verifications passed!"
|
||||
else
|
||||
echo "ERROR: Some verifications failed!"
|
||||
exit 1
|
||||
fi
|
||||
set +x
|
||||
Reference in New Issue
Block a user