notebookvb
This commit is contained in:
+108
-34
@@ -1,68 +1,142 @@
|
||||
# PostgreSQL Backup - Tower
|
||||
|
||||
PostgreSQL 18 (Docker: `postgresql18`) na Tower (192.168.1.76).
|
||||
Dva samostatné PostgreSQL Docker kontejnery na Tower (192.168.1.76).
|
||||
|
||||
## Konfigurace
|
||||
---
|
||||
|
||||
## Instance 1 — postgresql18 (hlavní)
|
||||
|
||||
| Parametr | Hodnota |
|
||||
|----------|---------|
|
||||
| Server | Tower (192.168.1.76) |
|
||||
| Container | `postgresql18` |
|
||||
| Port | 5432 |
|
||||
| Docker kontejner | `postgresql18` |
|
||||
| Image | `postgres:18` |
|
||||
| Port | `5432` (host) → `5432` (container) |
|
||||
| User | `vladimir.buzalka` |
|
||||
| Metoda | `pg_dumpall` (všechny DB najednou) |
|
||||
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLBackup/tower/YYYY-MM-DD_HHMM/` |
|
||||
| Password | `Vlado7309208104++` |
|
||||
| Data path (Unraid) | `/mnt/user/appdata/postgresql18` |
|
||||
| Obsah | Hlavní aplikační databáze |
|
||||
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLBackup/tower/YYYY-MM-DD_HHMM/all_databases.sql.gz` |
|
||||
| Retence | 7 dní / posledních 7 záloh |
|
||||
| User Script (Unraid) | `PostgreSQLBackup` |
|
||||
| Skript | `postgresqlbackup_with_gzip.sh` |
|
||||
| První test | 2026-05-23 06:59:51 → 07:03:12 (cca 3 min), dump **3.3 GB** |
|
||||
|
||||
---
|
||||
|
||||
## Instance 2 — PostgreSQL_Immich (Immich)
|
||||
|
||||
| Parametr | Hodnota |
|
||||
|----------|---------|
|
||||
| Docker kontejner | `PostgreSQL_Immich` |
|
||||
| Image | `tensorchord/pgvecto-rs:pg16-v0.2.0` (PG 16 + pgvecto-rs extension) |
|
||||
| Port | `5433` (host) → `5432` (container) |
|
||||
| User | `postgres` |
|
||||
| Password | `postgres` |
|
||||
| DB | `immich` |
|
||||
| Data path (Unraid) | `/mnt/user/appdata/PostgreSQL_Immich` |
|
||||
| Obsah | Metadata Immich (fotky, alba, uživatelé) — bez samotných fotek |
|
||||
| Záloha | `/mnt/user/Backup/Critical/PostgreSQLImmichBackup/tower/YYYY-MM-DD_HHMM/immich_all.sql.gz` |
|
||||
| Retence | 7 dní / posledních 7 záloh |
|
||||
| User Script (Unraid) | `PostgreSQLImmichBackup` |
|
||||
| Skript | `postgresqlimmichbackup_with_gzip.sh` |
|
||||
| První test | 2026-05-23 07:25:31 → 07:25:49 (18 sekund), dump **52 MB** |
|
||||
|
||||
> **Poznámka:** `pgvecto-rs` je specializovaná extension pro vektorové vyhledávání (používá Immich pro AI similarity search). Dump obsahuje i extension definice, takže restore vyžaduje stejný image (`tensorchord/pgvecto-rs`), ne čistý `postgres`.
|
||||
|
||||
---
|
||||
|
||||
## 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`.
|
||||
| Soubor | Popis |
|
||||
|--------|-------|
|
||||
| `postgresqlbackup_with_gzip.sh` | Backup postgresql18 (pg_dumpall → gzip) |
|
||||
| `postgresqlimmichbackup_with_gzip.sh` | Backup PostgreSQL_Immich (pg_dumpall → gzip) |
|
||||
| `postgresqlrestore_from_backup.sh` | Restore postgresql18 z nejnovější / zadané zálohy |
|
||||
| `verify_backup_integrity.sh` | Ověření DB, tabulek, indexů, rolí po restore |
|
||||
|
||||
### Backup (spuštění ručně na Tower)
|
||||
|
||||
```bash
|
||||
bash postgresqlbackup_with_gzip.sh
|
||||
bash /boot/config/plugins/user.scripts/scripts/PostgreSQLBackup/script
|
||||
bash /boot/config/plugins/user.scripts/scripts/PostgreSQLImmichBackup/script
|
||||
```
|
||||
|
||||
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).
|
||||
### Restore postgresql18 (nejnovější záloha)
|
||||
|
||||
```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.
|
||||
### Restore postgresql18 (konkrétní záloha)
|
||||
|
||||
### `verify_backup_integrity.sh`
|
||||
Ověří po restore že jsou všechny DB, tabulky, indexy a role přítomny a funkční.
|
||||
```bash
|
||||
bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0659
|
||||
```
|
||||
|
||||
> **POZOR:** Dump je vytvořen s `--clean --if-exists` → restore dropne a znovu vytvoří všechny objekty. Existující data budou přepsána.
|
||||
|
||||
### Verify po restore
|
||||
|
||||
```bash
|
||||
bash verify_backup_integrity.sh
|
||||
```
|
||||
|
||||
## Nastavení Unraid User Script
|
||||
---
|
||||
|
||||
Na Tower přidat User Script `POSTGRESQL_BACKUP`:
|
||||
## Metoda zálohy
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
bash /boot/config/plugins/user.scripts/scripts/POSTGRESQL_BACKUP/postgresqlbackup_with_gzip.sh
|
||||
- **pg_dumpall** — jeden soubor obsahující všechny DB, role, tablespaces, grants, extensions
|
||||
- Streamuje přes `stdout | gzip` přímo na disk → žádný dočasný soubor uvnitř kontejneru
|
||||
- Restore: `gunzip -c file.sql.gz | psql`
|
||||
- Validace: EXIT_CODE z `${PIPESTATUS[0]}` + kontrola velikosti souboru + prázdný .err soubor
|
||||
|
||||
---
|
||||
|
||||
## Struktura záloh na disku
|
||||
|
||||
```
|
||||
/mnt/user/Backup/Critical/
|
||||
├── PostgreSQLBackup/
|
||||
│ └── tower/
|
||||
│ └── 2026-05-23_0659/
|
||||
│ └── all_databases.sql.gz (3.3 GB)
|
||||
└── PostgreSQLImmichBackup/
|
||||
└── tower/
|
||||
└── 2026-05-23_0725/
|
||||
└── immich_all.sql.gz (52 MB)
|
||||
```
|
||||
|
||||
Schedule: **Daily**
|
||||
|
||||
## Windows přístup k zálohám
|
||||
### Windows přístup
|
||||
|
||||
```
|
||||
\\tower\Backup\Critical\PostgreSQLBackup\
|
||||
\\tower\Backup\Critical\PostgreSQLImmichBackup\
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unraid User Scripts (Tower)
|
||||
|
||||
Skripty jsou nasazeny v:
|
||||
```
|
||||
/boot/config/plugins/user.scripts/scripts/PostgreSQLBackup/
|
||||
/boot/config/plugins/user.scripts/scripts/PostgreSQLImmichBackup/
|
||||
```
|
||||
|
||||
Nastavit schedule: **Settings → User Scripts → Daily**
|
||||
|
||||
---
|
||||
|
||||
## SSH přístup na Tower (z Windows/Python)
|
||||
|
||||
Heslo pro SSH se liší od ostatních hesel!
|
||||
|
||||
```python
|
||||
import paramiko
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
client.connect("192.168.1.76", username="root", password="7309208104",
|
||||
look_for_keys=False, allow_agent=False)
|
||||
```
|
||||
|
||||
> Standardní `ssh root@192.168.1.76` z Windows selže kvůli "Too many authentication failures" (nabízí klíče před heslem). Použít `look_for_keys=False, allow_agent=False`.
|
||||
|
||||
@@ -1,24 +1,60 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# PostgreSQLBackup — záloha PostgreSQL 18 (hlavní instance) na Tower
|
||||
# ==============================================================================
|
||||
#
|
||||
# CO DĚLÁ:
|
||||
# Zálohuje celý PostgreSQL 18 server pomocí pg_dumpall — jeden SQL soubor
|
||||
# obsahuje všechny databáze, role, tablespaces a grants. Výstup je komprimován
|
||||
# gzip přímo ve streamu (bez mezičlánku na disku).
|
||||
#
|
||||
# TECHNICKÉ DETAILY:
|
||||
# - pg_dumpall: záloha celého serveru (ne jen jedné DB) — zahrnuje i role/uživatele
|
||||
# - --clean --if-exists: generuje DROP příkazy před CREATE (bezpečný re-restore)
|
||||
# - Stream přes stdout: docker exec → pipe → gzip → soubor na hostiteli
|
||||
# → žádný volume mount, žádná dočasná kopie uvnitř kontejneru
|
||||
# - ${PIPESTATUS[0]}: exit kód pg_dumpall (ne gzip) — gzip by jinak maskoval chybu
|
||||
# - PGPASSWORD: předáváme jako env var do kontejneru přes -e (ne jako argument)
|
||||
#
|
||||
# SCHEDULE:
|
||||
# Unraid User Script "PostgreSQLBackup" — daily (4:40 ráno)
|
||||
#
|
||||
# STRUKTURA ZÁLOHY:
|
||||
# /mnt/user/Backup/Critical/PostgreSQLBackup/tower/
|
||||
# YYYY-MM-DD_HHMM/
|
||||
# all_databases.sql.gz ← komprimovaný pg_dumpall výstup
|
||||
# all_databases.err ← dočasný soubor chyb (smazán při úspěchu)
|
||||
#
|
||||
# VELIKOST / ČAS:
|
||||
# Dump: ~3.3 GB, záloha trvá ~3 minuty
|
||||
#
|
||||
# ROTACE:
|
||||
# Dvoustupňová — nejprve dle stáří (KEEP_DAYS), pak oříznutí na KEEP_COUNT.
|
||||
#
|
||||
# RESTORE:
|
||||
# Viz postgresqlrestore_from_backup.sh
|
||||
# gunzip -c all_databases.sql.gz | docker exec -i postgresql18 psql ...
|
||||
# ==============================================================================
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# CONFIGURATION
|
||||
# ==========================================================
|
||||
CONTAINER_NAME="postgresql18"
|
||||
PG_HOST="localhost"
|
||||
PG_PORT="5432"
|
||||
PG_USER="vladimir.buzalka"
|
||||
export PGPASSWORD="Vlado7309208104++"
|
||||
# ==============================================================================
|
||||
# KONFIGURACE
|
||||
# ==============================================================================
|
||||
CONTAINER_NAME="postgresql18" # Docker kontejner s PostgreSQL 18
|
||||
PG_HOST="localhost" # uvnitř kontejneru
|
||||
PG_PORT="5432" # výchozí PG port
|
||||
PG_USER="vladimir.buzalka" # superuser s právy pro pg_dumpall
|
||||
export PGPASSWORD="Vlado7309208104++" # heslo jako env var (pg_dumpall čte PGPASSWORD)
|
||||
|
||||
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)
|
||||
KEEP_DAYS=7 # zálohy starší než 7 dní se smažou v prvním průchodu
|
||||
KEEP_COUNT=7 # z toho co zbyde, ponech vždy alespoň 7 záloh
|
||||
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# START
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
echo "Starting PostgreSQL full backup (pg_dumpall)"
|
||||
START_TS=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
@@ -26,14 +62,19 @@ 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_FILE="$FINAL_PATH/all_databases.sql.gz" # výsledný komprimovaný dump
|
||||
ERR_FILE="$FINAL_PATH/all_databases.err" # stderr pg_dumpall
|
||||
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# DUMP + GZIP
|
||||
# pg_dumpall zachovává: všechny DB, role, tablespaces, grants
|
||||
# Streamuje přes stdout, nepotřebuje volume mount
|
||||
# ==========================================================
|
||||
# docker exec spustí pg_dumpall uvnitř kontejneru.
|
||||
# -e PGPASSWORD: předá heslo jako env var do kontejneru (bez -e by pg_dumpall
|
||||
# nemohl autentizovat a skončil by promptem na stdin).
|
||||
# Pipe na gzip: komprimuje stream v reálném čase — na disku nikdy není
|
||||
# nekomprimovaný dump (úspora místa a I/O).
|
||||
# > "$DUMP_FILE": výstup gzip jde do souboru na hostiteli.
|
||||
# 2> "$ERR_FILE": stderr pg_dumpall (warnings, errory) jde do .err souboru.
|
||||
# ==============================================================================
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
@@ -45,11 +86,17 @@ docker exec \
|
||||
--if-exists \
|
||||
| gzip > "$DUMP_FILE" 2> "$ERR_FILE"
|
||||
|
||||
# PIPESTATUS[0] = exit kód prvního příkazu v pipe (pg_dumpall).
|
||||
# Prostý $? by vrátil exit kód gzip — i když pg_dumpall selže, gzip může skončit 0.
|
||||
EXIT_CODE=${PIPESTATUS[0]}
|
||||
|
||||
# ==========================================================
|
||||
# VALIDATION
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# VALIDACE
|
||||
# Tři podmínky pro úspěch:
|
||||
# 1. EXIT_CODE=0 — pg_dumpall skončil bez chyby
|
||||
# 2. -s "$DUMP_FILE" — soubor existuje a není prázdný
|
||||
# 3. ! -s "$ERR_FILE" — žádné chybové hlášky (prázdný .err)
|
||||
# ==============================================================================
|
||||
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)"
|
||||
@@ -63,17 +110,20 @@ else
|
||||
[ -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
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# ROTACE STARÝCH ZÁLOH — dvoustupňová
|
||||
#
|
||||
# Krok 1: Smaž adresáře starší než KEEP_DAYS dní.
|
||||
# -mindepth/-maxdepth 1: jen přímé podadresáře (ne rekurzivně)
|
||||
#
|
||||
# Krok 2: Z toho co zbyde, ponech jen posledních KEEP_COUNT.
|
||||
# Důvod dvou kroků: i při přerušeném schedule garantuje min. KEEP_COUNT záloh.
|
||||
# ==============================================================================
|
||||
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
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# PostgreSQLImmichBackup — záloha PostgreSQL Immich instance na Tower
|
||||
# ==============================================================================
|
||||
#
|
||||
# CO DĚLÁ:
|
||||
# Zálohuje celý PostgreSQL server pro Immich (foto server) pomocí pg_dumpall.
|
||||
# Stejný princip jako hlavní PostgreSQL záloha, ale jiný kontejner a přihlašovací údaje.
|
||||
#
|
||||
# DŮLEŽITÉ — SPECIÁLNÍ IMAGE:
|
||||
# PostgreSQL_Immich běží na nestandardním image tensorchord/pgvecto-rs:pg16-v0.2.0,
|
||||
# který obsahuje pgvecto-rs extension pro vektorové operace (embedding fotek).
|
||||
# Při RESTORE je NUTNÉ použít stejný image — standardní postgres:16 nebude fungovat,
|
||||
# protože dump obsahuje CREATE EXTENSION pro pgvecto-rs.
|
||||
#
|
||||
# TECHNICKÉ DETAILY:
|
||||
# - Kontejner: PostgreSQL_Immich (port 5433 na hostiteli → 5432 uvnitř)
|
||||
# - pg_dumpall: záloha celého serveru incl. role, extensions (pgvecto-rs), grants
|
||||
# - --clean --if-exists: DROP + CREATE = idempotentní restore
|
||||
# - Stream přes stdout → pipe → gzip → soubor na hostiteli
|
||||
# - ${PIPESTATUS[0]}: exit kód pg_dumpall (gzip by jinak maskoval chybu)
|
||||
#
|
||||
# SCHEDULE:
|
||||
# Unraid User Script "PostgreSQLImmichBackup" — daily (4:40 ráno)
|
||||
#
|
||||
# STRUKTURA ZÁLOHY:
|
||||
# /mnt/user/Backup/Critical/PostgreSQLImmichBackup/tower/
|
||||
# YYYY-MM-DD_HHMM/
|
||||
# immich_all.sql.gz ← komprimovaný pg_dumpall výstup
|
||||
# immich_all.err ← dočasný soubor chyb (smazán při úspěchu)
|
||||
#
|
||||
# VELIKOST / ČAS:
|
||||
# Dump: ~52 MB, záloha trvá ~18 sekund
|
||||
#
|
||||
# ROTACE:
|
||||
# Dvoustupňová — nejprve dle stáří (KEEP_DAYS), pak oříznutí na KEEP_COUNT.
|
||||
#
|
||||
# RESTORE POSTUP:
|
||||
# 1. Ujisti se, že běží správný image (tensorchord/pgvecto-rs:pg16-v0.2.0)
|
||||
# 2. gunzip -c immich_all.sql.gz | docker exec -i PostgreSQL_Immich psql -U postgres postgres
|
||||
# 3. Restartuj Immich kontejner
|
||||
# ==============================================================================
|
||||
set -x
|
||||
|
||||
# ==============================================================================
|
||||
# KONFIGURACE
|
||||
# ==============================================================================
|
||||
CONTAINER_NAME="PostgreSQL_Immich" # Docker kontejner s PG pro Immich (jiný než postgresql18!)
|
||||
PG_HOST="localhost" # uvnitř kontejneru
|
||||
PG_PORT="5432" # port uvnitř kontejneru (na hostiteli je 5433)
|
||||
PG_USER="postgres" # výchozí postgres superuser
|
||||
export PGPASSWORD="postgres" # jednoduché heslo (interní kontejner, není exponován)
|
||||
|
||||
UNRAID_NAME="tower"
|
||||
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLImmichBackup"
|
||||
|
||||
KEEP_DAYS=7 # zálohy starší než 7 dní se smažou
|
||||
KEEP_COUNT=7 # vždy ponech alespoň 7 záloh
|
||||
|
||||
# ==============================================================================
|
||||
# START
|
||||
# ==============================================================================
|
||||
echo "Starting PostgreSQL Immich 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/immich_all.sql.gz" # výsledný komprimovaný dump
|
||||
ERR_FILE="$FINAL_PATH/immich_all.err" # stderr pg_dumpall
|
||||
|
||||
# ==============================================================================
|
||||
# DUMP + GZIP
|
||||
# Stejný princip jako u hlavního PostgreSQL:
|
||||
# docker exec → pg_dumpall (stdout) → gzip → soubor na hostiteli
|
||||
# PGPASSWORD předáváme jako -e env var do kontejneru.
|
||||
# Uvnitř kontejneru pg_dumpall komunikuje přes localhost:5432 (interní port).
|
||||
# ==============================================================================
|
||||
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"
|
||||
|
||||
# PIPESTATUS[0] = exit kód pg_dumpall (ne gzip)
|
||||
EXIT_CODE=${PIPESTATUS[0]}
|
||||
|
||||
# ==============================================================================
|
||||
# VALIDACE
|
||||
# ==============================================================================
|
||||
if [ $EXIT_CODE -eq 0 ] && [ -s "$DUMP_FILE" ] && [ ! -s "$ERR_FILE" ]; then
|
||||
echo "SUCCESS: Immich 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
|
||||
|
||||
# ==============================================================================
|
||||
# ROTACE STARÝCH ZÁLOH — dvoustupňová (viz postgresqlbackup_with_gzip.sh)
|
||||
# ==============================================================================
|
||||
echo "Cleaning up old backups..."
|
||||
find "$BASE_PATH/$UNRAID_NAME" \
|
||||
-mindepth 1 -maxdepth 1 -type d -mtime +$KEEP_DAYS \
|
||||
-exec rm -rf {} \;
|
||||
|
||||
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
|
||||
@@ -1,27 +1,56 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# PostgreSQLRestore — obnovení PostgreSQL 18 ze zálohy
|
||||
# ==============================================================================
|
||||
#
|
||||
# CO DĚLÁ:
|
||||
# Obnoví celý PostgreSQL 18 server z pg_dumpall zálohy.
|
||||
# Pokud není zadán konkrétní adresář, automaticky najde nejnovější zálohu.
|
||||
#
|
||||
# POUŽITÍ:
|
||||
# bash postgresqlrestore_from_backup.sh [cesta_k_záloze]
|
||||
#
|
||||
# Bez argumentu — použije nejnovější zálohu:
|
||||
# bash postgresqlrestore_from_backup.sh
|
||||
#
|
||||
# S konkrétním adresářem:
|
||||
# bash postgresqlrestore_from_backup.sh /mnt/user/Backup/Critical/PostgreSQLBackup/tower/2026-05-23_0440
|
||||
#
|
||||
# TECHNICKÉ DETAILY:
|
||||
# - gunzip -c: dekomprimuje na stdout (nezahazuje archiv)
|
||||
# - pipe → docker exec -i psql: stream SQL příkazů do PostgreSQL
|
||||
# - --dbname=postgres: psql se musí připojit k existující DB (postgres je vždy)
|
||||
# - --clean + --if-exists v dumpu: DROP objekty před jejich vytvoření
|
||||
# - ${PIPESTATUS[1]}: exit kód psql (ne gunzip)
|
||||
#
|
||||
# POZOR:
|
||||
# Restore přepíše všechna stávající data! Spouštět vědomě, ne automaticky.
|
||||
# Chybové hlášky jako "role already exists" jsou normální — dump je idempotentní.
|
||||
# ==============================================================================
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# CONFIGURATION
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# KONFIGURACE
|
||||
# ==============================================================================
|
||||
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
|
||||
# Volitelný argument — konkrétní adresář zálohy.
|
||||
# Pokud není zadán, skript sám najde nejnovější.
|
||||
BACKUP_DIR="$1"
|
||||
|
||||
BASE_PATH="/mnt/user/Backup/Critical/PostgreSQLBackup/tower"
|
||||
|
||||
# ==========================================================
|
||||
# FIND BACKUP
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# NALEZENÍ ZÁLOHY
|
||||
# ==============================================================================
|
||||
if [ -z "$BACKUP_DIR" ]; then
|
||||
echo "No backup path specified - using latest available backup"
|
||||
# ls -td: seřadit adresáře dle mtime, nejnovější první
|
||||
# head -1: vzít jen nejnovější
|
||||
BACKUP_DIR=$(ls -td "$BASE_PATH"/*/ 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$BACKUP_DIR" ]; then
|
||||
@@ -49,11 +78,15 @@ 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
|
||||
# ==========================================================
|
||||
# gunzip -c: dekomprimuje all_databases.sql.gz na stdout (soubor zůstane)
|
||||
# pipe → docker exec -i psql: SQL streamed přímo do PostgreSQL
|
||||
# -i: nutné pro stdin stream (bez -i by psql nedostával vstup)
|
||||
# --dbname=postgres: psql se musí připojit k nějaké DB — postgres vždy existuje
|
||||
# Záloha obsahuje příkazy pro všechny DB, role a grants — psql je postupně vykoná.
|
||||
# 2> "$ERR_FILE": stderr psql (chyby, warnings) — "role already exists" je normální
|
||||
# ==============================================================================
|
||||
echo "Restoring all databases to PostgreSQL..."
|
||||
gunzip -c "$BACKUP_FILE" \
|
||||
| docker exec -i \
|
||||
@@ -66,11 +99,12 @@ gunzip -c "$BACKUP_FILE" \
|
||||
--dbname="postgres" \
|
||||
2> "$ERR_FILE"
|
||||
|
||||
# PIPESTATUS[1] = exit kód docker exec / psql (index 1 = druhý prvek pipe)
|
||||
RESTORE_EXIT=${PIPESTATUS[1]}
|
||||
|
||||
# ==========================================================
|
||||
# VALIDATION
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# VALIDACE
|
||||
# ==============================================================================
|
||||
if [ $RESTORE_EXIT -eq 0 ]; then
|
||||
echo "SUCCESS: All databases restored successfully"
|
||||
rm -f "$ERR_FILE"
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# PostgreSQL Verify Backup Integrity — ověření konzistence po restore
|
||||
# ==============================================================================
|
||||
#
|
||||
# CO DĚLÁ:
|
||||
# Připojí se k PostgreSQL 18 a pro každou databázi zkontroluje:
|
||||
# 1. Konektivitu k serveru
|
||||
# 2. Seznam všech databází
|
||||
# 3. Pro každou DB: počet tabulek, počty řádků, velikosti, počet indexů
|
||||
# 4. PostgreSQL role a uživatele
|
||||
#
|
||||
# KDY POUŽÍT:
|
||||
# Po provedení postgresqlrestore_from_backup.sh — ověří, že data jsou v pořádku.
|
||||
# Spouštět ručně, není součástí automatizovaného schedule.
|
||||
#
|
||||
# VÝSTUP:
|
||||
# OK / ERROR indikátory, tabulky se statistikami.
|
||||
# Skript vrátí exit code 1 pokud cokoliv selže.
|
||||
# ==============================================================================
|
||||
set -x
|
||||
|
||||
# ==========================================================
|
||||
# VERIFY BACKUP INTEGRITY
|
||||
# Kontroluje že se všechny DB, tabulky a data
|
||||
# správně obnovily po restore
|
||||
# ==========================================================
|
||||
|
||||
# ==============================================================================
|
||||
# KONFIGURACE
|
||||
# ==============================================================================
|
||||
CONTAINER_NAME="postgresql18"
|
||||
PG_HOST="localhost"
|
||||
PG_PORT="5432"
|
||||
@@ -18,9 +34,11 @@ echo "=========================================="
|
||||
|
||||
ALL_OK=true
|
||||
|
||||
# ==========================================================
|
||||
# 1. CONNECTIVITY CHECK
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# 1. KONEKTIVITA
|
||||
# Jednoduchý SELECT 'connected' — pokud selže, PostgreSQL není dostupný
|
||||
# a nemá smysl pokračovat.
|
||||
# ==============================================================================
|
||||
echo ""
|
||||
echo "Checking PostgreSQL connectivity..."
|
||||
docker exec \
|
||||
@@ -40,9 +58,12 @@ if [ $? -ne 0 ]; then
|
||||
fi
|
||||
echo "OK: Connected to PostgreSQL"
|
||||
|
||||
# ==========================================================
|
||||
# 2. LIST ALL DATABASES
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# 2. SEZNAM DATABÁZÍ
|
||||
# pg_database: systémová tabulka s metadaty databází.
|
||||
# datistemplate=false: vynechá šablonové DB (template0, template1).
|
||||
# Výsledek jde nejdřív na stdout (pro přehled), pak do proměnné pro iteraci.
|
||||
# ==============================================================================
|
||||
echo ""
|
||||
echo "Databases present:"
|
||||
docker exec \
|
||||
@@ -56,7 +77,8 @@ docker exec \
|
||||
--tuples-only \
|
||||
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;"
|
||||
|
||||
# Ulož seznam DB do proměnné pro iteraci
|
||||
# Znovu spustíme dotaz pro iteraci — ukládáme do proměnné.
|
||||
# tr -d ' ': odstraní bílé znaky z výstupu psql (odsazení sloupce).
|
||||
DATABASES=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
@@ -69,17 +91,21 @@ DATABASES=$(docker exec \
|
||||
--command="SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname;" \
|
||||
| tr -d ' ')
|
||||
|
||||
# ==========================================================
|
||||
# 3. PER-DATABASE CHECKS
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# 3. KONTROLA KAŽDÉ DATABÁZE
|
||||
# ==============================================================================
|
||||
for DB_NAME in $DATABASES; do
|
||||
[ -z "$DB_NAME" ] && continue
|
||||
[ -z "$DB_NAME" ] && continue # přeskoč prázdné řádky z výstupu psql
|
||||
|
||||
echo ""
|
||||
echo "Verifying database: $DB_NAME"
|
||||
echo "------------------------------------------"
|
||||
|
||||
# Počet tabulek
|
||||
# --------------------------------------------------------------------------
|
||||
# Počet tabulek v public schema
|
||||
# information_schema.tables: standardní SQL pohled, table_schema='public'
|
||||
# filtruje jen uživatelské tabulky (ne systémové views).
|
||||
# --------------------------------------------------------------------------
|
||||
TABLE_COUNT=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
@@ -94,7 +120,12 @@ for DB_NAME in $DATABASES; do
|
||||
|
||||
echo "OK: Tables in public schema: $TABLE_COUNT"
|
||||
|
||||
# Seznam tabulek s počtem řádků
|
||||
# --------------------------------------------------------------------------
|
||||
# Tabulky s počtem řádků a velikostí
|
||||
# pg_stat_user_tables: statistiky o uživatelských tabulkách (live tuples, dead tuples).
|
||||
# n_live_tup: odhadovaný počet živých řádků (ANALYZE musí být aktuální).
|
||||
# pg_total_relation_size: celková velikost incl. indexy a TOAST.
|
||||
# --------------------------------------------------------------------------
|
||||
echo " Table row counts:"
|
||||
docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
@@ -113,7 +144,11 @@ SELECT
|
||||
FROM pg_stat_user_tables
|
||||
ORDER BY relname;"
|
||||
|
||||
# Počet indexů
|
||||
# --------------------------------------------------------------------------
|
||||
# Počet indexů v public schema
|
||||
# pg_indexes: systémový katalog indexů. Slouží jako ověření, že
|
||||
# pg_dumpall správně obnovil i CREATE INDEX příkazy (ne jen data).
|
||||
# --------------------------------------------------------------------------
|
||||
INDEX_COUNT=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
@@ -128,7 +163,10 @@ ORDER BY relname;"
|
||||
|
||||
echo "OK: Indexes in public schema: $INDEX_COUNT"
|
||||
|
||||
# Celková velikost DB
|
||||
# --------------------------------------------------------------------------
|
||||
# Celková velikost databáze
|
||||
# pg_database_size: vrátí velikost v bytech, pg_size_pretty ji naformátuje.
|
||||
# --------------------------------------------------------------------------
|
||||
DB_SIZE=$(docker exec \
|
||||
-e PGPASSWORD="$PGPASSWORD" \
|
||||
"$CONTAINER_NAME" \
|
||||
@@ -145,9 +183,12 @@ ORDER BY relname;"
|
||||
|
||||
done
|
||||
|
||||
# ==========================================================
|
||||
# 4. CHECK ROLES / USERS
|
||||
# ==========================================================
|
||||
# ==============================================================================
|
||||
# 4. ROLE A UŽIVATELÉ
|
||||
# pg_roles: systémový katalog všech rolí.
|
||||
# Filtrujeme pryč built-in pg_* role (pg_monitor, pg_read_all_settings, atd.)
|
||||
# aby výstup byl přehledný — zajímají nás jen uživatelské role.
|
||||
# ==============================================================================
|
||||
echo ""
|
||||
echo "PostgreSQL roles:"
|
||||
docker exec \
|
||||
|
||||
Reference in New Issue
Block a user