notebookvb
This commit is contained in:
@@ -9,7 +9,8 @@
|
||||
"Bash(git add *)",
|
||||
"Bash(git commit *)",
|
||||
"Bash(git push *)",
|
||||
"PowerShell(Test-NetConnection -ComputerName 192.168.1.50 -Port 27017 -InformationLevel Detailed)"
|
||||
"PowerShell(Test-NetConnection -ComputerName 192.168.1.50 -Port 27017 -InformationLevel Detailed)",
|
||||
"Bash(mkdir -p \"U:\\\\PycharmProjects\\\\Backup\\\\PostGRESQLTower\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# Backup Project - Infrastructure Info
|
||||
|
||||
## 🖥️ Servery
|
||||
|
||||
| Server | Hostname | IP | OS |
|
||||
|--------|----------|----|----|
|
||||
| Tower | tower / tower.lan | 192.168.1.76 | Unraid |
|
||||
| Tower1 | tower1 | 192.168.1.50 | Unraid |
|
||||
|
||||
---
|
||||
|
||||
## 🔐 SSH přístup
|
||||
|
||||
**Credentials (oba servery):**
|
||||
- User: `root`
|
||||
- Password: `Vlado7309208104++`
|
||||
|
||||
**Připojení:**
|
||||
```bash
|
||||
ssh root@192.168.1.76 # Tower
|
||||
ssh root@192.168.1.50 # Tower1
|
||||
```
|
||||
|
||||
**Důležité:** Tower a Tower1 mají vzájemně nahrané SSH klíče - Tower1 se může připojit na Tower bez hesla a naopak.
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Docker kontejnery
|
||||
|
||||
| Server | Kontejner | Port |
|
||||
|--------|-----------|------|
|
||||
| Tower | `MongoDB` | 27017 |
|
||||
| Tower1 | `MongoDB` | 27017 |
|
||||
| Tower | `MySQL` | 3306 |
|
||||
|
||||
---
|
||||
|
||||
## 📁 Důležité cesty
|
||||
|
||||
### Tower
|
||||
| Co | Cesta |
|
||||
|----|-------|
|
||||
| MongoDB zálohy | `/mnt/user/Backup/Critical/MongoDBBackup/` |
|
||||
| MySQL zálohy | `/mnt/user/MySQLBackup/` |
|
||||
| User Scripts | `/boot/config/plugins/user.scripts/scripts/` |
|
||||
| Test share | `/mnt/user/#test/` |
|
||||
|
||||
### Windows (lokální)
|
||||
| Co | Cesta |
|
||||
|----|-------|
|
||||
| MongoDB zálohy | `\\tower\Backup\Critical\MongoDBBackup\` |
|
||||
| MySQL zálohy | `\\tower\MySQLBackup\` |
|
||||
| Test share | `\\tower1\#test\` |
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ MongoDB
|
||||
|
||||
- **Verze:** 8.2.9
|
||||
- **Auth:** Žádná (otevřené)
|
||||
- **Databáze k zálohování:** `admin`, `edc` (+ další dle skriptu)
|
||||
- **Připojení z Pythonu:**
|
||||
```python
|
||||
from pymongo import MongoClient
|
||||
client = MongoClient('mongodb://192.168.1.76:27017') # Tower
|
||||
client = MongoClient('mongodb://192.168.1.50:27017') # Tower1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ MySQL
|
||||
|
||||
- **User:** `root`
|
||||
- **Password:** `Vlado9674+`
|
||||
- **Databáze:** `fio`, `torrents`, `OrdinaceDropBoxBackup`, `medevio`, `kanboard`, `medicus`, `studie`, `puzzle`
|
||||
|
||||
---
|
||||
|
||||
## 📜 User Scripts na Tower (Unraid)
|
||||
|
||||
| Název | Popis | Schedule |
|
||||
|-------|-------|----------|
|
||||
| `3_MYSQL_BACKUP_WITH_GZIP` | MySQL backup všech DB | Daily |
|
||||
| `MONGODB_BACKUP` | MongoDB backup (`--archive --gzip`) | Daily |
|
||||
|
||||
## 📜 User Scripts na Tower1 (Unraid)
|
||||
|
||||
| Název | Popis |
|
||||
|-------|-------|
|
||||
| `MONGODB_RESTORE` | Restore edc DB z Tower přes SSH stream |
|
||||
@@ -1,236 +0,0 @@
|
||||
# MongoDB Backup & Restore Scripts
|
||||
|
||||
Kompletní řešení pro zálohování a obnovu MongoDB databází na Unraid.
|
||||
|
||||
## 📋 Obsah backup
|
||||
|
||||
Skripty zálohují a obnovují **KOMPLETNĚ VŠECHNO**:
|
||||
- ✅ **Všechny databáze** (včetně `admin` pro credentials a roles)
|
||||
- ✅ **Všechny kolekce** a dokumenty (BSON formát)
|
||||
- ✅ **Všechny indexy** (včetně unique, compound, text indexů)
|
||||
- ✅ **Metadata kolekcí** (validators, options, atd.)
|
||||
- ✅ **Uživatele a role** (v admin DB)
|
||||
- ✅ **Komprimace gzipem** pro úsporu místa
|
||||
|
||||
**Oveřeno zachowáno:**
|
||||
- Indexové struktury se zachovávají identicky
|
||||
- Collection validators (JSONSchema) se zachovávají
|
||||
- Collection options (capped collections, atd.) se zachovávají
|
||||
- Všechny system collections (`system.indexes`, `system.users`, atd.)
|
||||
- Opaque object IDs, binary data, všechny BSON typy
|
||||
|
||||
## 🔄 Použití
|
||||
|
||||
### 1. **Backup skript** (`mongodbbackup_with_gzip.sh`)
|
||||
|
||||
Zálohuje všechny DB do `/mnt/user/Backup/Critical/MongoDBBackup/tower/{DB_NAME}/{YYYY-MM-DD_HHMM}/`
|
||||
|
||||
```bash
|
||||
chmod +x mongodbbackup_with_gzip.sh
|
||||
./mongodbbackup_with_gzip.sh
|
||||
```
|
||||
|
||||
**Přidej do Unraid scheduled tasksu:**
|
||||
```
|
||||
Schedule: Daily (nebo jak chceš)
|
||||
Command: /mnt/user/path/mongodbbackup_with_gzip.sh
|
||||
```
|
||||
|
||||
**Struktura záloh:**
|
||||
```
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/tower/
|
||||
├── admin/
|
||||
│ └── 2026-05-23_1530/
|
||||
│ ├── admin.archive.gz
|
||||
│ └── admin.err (jen pokud je chyba)
|
||||
├── fio/
|
||||
│ └── 2026-05-23_1530/
|
||||
│ ├── fio.archive.gz
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Konfigurace:**
|
||||
- `CONTAINER_NAME` - jméno MongoDB kontejneru
|
||||
- `KEEP_DAYS` - Jak dlouho se uchovávají staré zálohy (default: 3 dny)
|
||||
- `WHAT_TO_BACKUP` - Seznam DB k zálohování
|
||||
|
||||
---
|
||||
|
||||
### 2. **Restore skript** (`mongodbrestore_from_backup.sh`)
|
||||
|
||||
Obnovuje všechny DB ze zálohy na LOCAL MongoDB.
|
||||
|
||||
```bash
|
||||
chmod +x mongodbrestore_from_backup.sh
|
||||
./mongodbrestore_from_backup.sh /mnt/user/Backup/Critical/MongoDBBackup/tower
|
||||
```
|
||||
|
||||
**Co skript dělá:**
|
||||
1. ✅ Najde nejnovější backup pro KAŽDOU DB
|
||||
2. ✅ Extrahuje .tar.gz archiv
|
||||
3. ✅ Obnoví do MongoDB (s `--drop` na přepsání existujících)
|
||||
4. ✅ Validuje úspěch
|
||||
5. ✅ Čistí temp soubory
|
||||
|
||||
---
|
||||
|
||||
### 3. **Ověřovací skript** (`verify_backup_integrity.sh`)
|
||||
|
||||
Kontroluje že se VŠECHNO správně obnovilo (indexy, metadata, kolekce).
|
||||
|
||||
```bash
|
||||
chmod +x verify_backup_integrity.sh
|
||||
./verify_backup_integrity.sh
|
||||
```
|
||||
|
||||
**Co skript ověřuje:**
|
||||
1. ✅ Zda všechny DB existují
|
||||
2. ✅ Počet a jména kolekcí
|
||||
3. ✅ Indexy pro každou kolekci (včetně jejich definic)
|
||||
4. ✅ Počet dokumentů v každé kolekci
|
||||
5. ✅ Velikost dat v MB
|
||||
6. ✅ Uživatele a role (admin DB)
|
||||
|
||||
**Příklad výstupu:**
|
||||
```
|
||||
Verifying database: fio
|
||||
✅ Database exists: fio
|
||||
✅ Collections count: 8
|
||||
Collections:
|
||||
- users
|
||||
- products
|
||||
- logs
|
||||
Indexes per collection:
|
||||
fio.users: 3 indexes
|
||||
- { "_id": 1 }
|
||||
- { "email": 1 }
|
||||
- { "created_at": -1 }
|
||||
Collection stats:
|
||||
users:
|
||||
Documents: 12345
|
||||
Size: 45.23 MB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testování na 2 Unraid serverech
|
||||
|
||||
### Scénář: Tower1 → Tower2 (Kompletní test)
|
||||
|
||||
#### **Krok 1: Na Tower1 (zdroj) - Spusť backup:**
|
||||
```bash
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/mongodbbackup_with_gzip.sh
|
||||
|
||||
# Ověř že backup existuje
|
||||
ls -lh /mnt/user/Backup/Critical/MongoDBBackup/tower/*/*/
|
||||
```
|
||||
|
||||
**Očekávaný výstup:**
|
||||
```
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/tower/
|
||||
├── admin/2026-05-23_1530/admin.archive.gz (234K)
|
||||
├── fio/2026-05-23_1530/fio.archive.gz (45M)
|
||||
├── torrents/2026-05-23_1530/torrents.archive.gz (...
|
||||
└── ...
|
||||
```
|
||||
|
||||
#### **Krok 2: Zkopíruj backup do Tower2:**
|
||||
```bash
|
||||
# Přes SMB share / rsync / fyzicky disku
|
||||
# Zkopíruj celou strukturu: /mnt/user/Backup/Critical/MongoDBBackup/tower/
|
||||
```
|
||||
|
||||
#### **Krok 3: Na Tower2 (cíl) - Obnovte zálohu:**
|
||||
```bash
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/mongodbrestore_from_backup.sh /mnt/user/Backup/Critical/MongoDBBackup/tower
|
||||
|
||||
# Výstup by měl být:
|
||||
# SUCCESS: admin restored successfully
|
||||
# SUCCESS: fio restored successfully
|
||||
# ...
|
||||
```
|
||||
|
||||
#### **Krok 4: Ověř INTEGRITU na Tower2 - Nejdůležitější!**
|
||||
```bash
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/verify_backup_integrity.sh
|
||||
```
|
||||
|
||||
**To by mělo ověřit:**
|
||||
- ✅ Všechny DB existují
|
||||
- ✅ Všechny kolekce se obnovily
|
||||
- ✅ Všechny indexy jsou tam (se stejnými definicemi!)
|
||||
- ✅ Počet dokumentů je identický
|
||||
- ✅ Uživatelé a role jsou obnovení
|
||||
|
||||
#### **Krok 5: Manuální spot-check (volitelně):**
|
||||
```bash
|
||||
docker exec -it MongoDB mongosh --host localhost --port 27017
|
||||
|
||||
# Ověř indexy v konkrétní kolekci
|
||||
use fio
|
||||
db.some_collection.getIndexes() # Měly by být stejné jako na Tower1
|
||||
|
||||
# Ověř počet dokumentů
|
||||
db.some_collection.countDocuments() # Měl by být identický
|
||||
|
||||
# Ověř že data jsou bezpečná
|
||||
db.some_collection.findOne()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Důležité poznámky
|
||||
|
||||
1. **`--drop` flag** - Restore skript obnovuje s `--drop`, což PŘEPÍŠE existující databázi. To je zvláště důležité pro test.
|
||||
|
||||
2. **Admin DB** - Obsahuje uživatele a role. Pokud máš auth, musíš je správně obnovit.
|
||||
|
||||
3. **Čištění** - Po úspěšném testu si můžeš vymazat temp soubory:
|
||||
```bash
|
||||
rm -rf /tmp/mongodb_restore_*
|
||||
```
|
||||
|
||||
4. **Disk space** - Při restore se vytváří tmp soubory. Ověř prostor na `/tmp` (nebo `/mnt/user`).
|
||||
|
||||
5. **MongoDB port** - Oba skripty očekávají MongoDB na `localhost:27017` (default).
|
||||
|
||||
---
|
||||
|
||||
## 📊 Příklad výstupu
|
||||
|
||||
```
|
||||
Starting scheduled backup for: admin fio torrents OrdinaceDropBoxBackup medevio kanboard medicus studie puzzle
|
||||
------------------------------------------
|
||||
Processing database: admin
|
||||
SUCCESS: admin backed up successfully
|
||||
Dump size: 234K
|
||||
Cleaning up old backups for admin...
|
||||
------------------------------------------
|
||||
Processing database: fio
|
||||
SUCCESS: fio backed up successfully
|
||||
Dump size: 45M
|
||||
Cleaning up old backups for fio...
|
||||
------------------------------------------
|
||||
...
|
||||
All backup tasks completed at Fri May 23 15:30:45 UTC 2026
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
| Problém | Řešení |
|
||||
|---------|--------|
|
||||
| `ERROR: Container not found` | Ověř jméno kontejneru v `CONTAINER_NAME` |
|
||||
| `Dump file too small` | Ověř že MongoDB běží a má data |
|
||||
| `mongodump: command not found` | Mongodump by měl být v MongoDB image, zkontroluj Docker image |
|
||||
| `Permission denied` | Ověř práva na složky: `chmod 755 /mnt/user/Backup/Critical/MongoDBBackup` |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Tipy
|
||||
|
||||
- **Archivuj staré zálohy** - Pokud chceš uchovávat dlouhodobější zálohy, zkopíruj složky před KEEP_DAYS expirací
|
||||
- **Ověř čitelnost** - Po backup jdi ověřit že soubor lze extrahovat: `tar -tzf admin.archive.gz | head`
|
||||
- **Monitoruj velikost** - `du -sh /mnt/user/Backup/Critical/MongoDBBackup/` - kontroluj disk space
|
||||
@@ -0,0 +1,175 @@
|
||||
# MongoDB Backup & Restore - Tower / Tower1
|
||||
|
||||
Kompletní řešení pro zálohování a obnovu MongoDB na Unraid.
|
||||
**Ověřeno v praxi** na dvou Unraid serverech Tower (192.168.1.76) a Tower1 (192.168.1.50).
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Infrastruktura
|
||||
|
||||
| Server | IP | Role | MongoDB kontejner |
|
||||
|--------|-----|------|-------------------|
|
||||
| Tower | 192.168.1.76 | Primární (zdroj záloh) | `MongoDB` |
|
||||
| Tower1 | 192.168.1.50 | Záloha (restore cíl) | `MongoDB` |
|
||||
|
||||
**SSH:** Tower1 ↔ Tower mají vzájemně nahrané SSH klíče (bez hesla).
|
||||
|
||||
---
|
||||
|
||||
## 📋 Co backup zachovává
|
||||
|
||||
- ✅ Všechny kolekce a dokumenty (BSON formát)
|
||||
- ✅ Všechny indexy (unique, compound, sparse, text)
|
||||
- ✅ Metadata kolekcí (validators, options)
|
||||
- ✅ Komprimace gzipem (`--archive --gzip`)
|
||||
|
||||
> **Poznámka k admin DB:** MongoDB je provozováno bez autentifikace, admin DB obsahuje pouze `system.version` (1 dokument, 360 B). Není nutné ji zálohovat pro obnovení dat.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Struktura záloh
|
||||
|
||||
```
|
||||
/mnt/user/Backup/Critical/MongoDBBackup/tower/
|
||||
├── admin/
|
||||
│ └── 2026-05-23_0532/
|
||||
│ └── admin.archive.gz (~360 B)
|
||||
├── edc/
|
||||
│ └── 2026-05-23_0532/
|
||||
│ └── edc.archive.gz (~436 KB)
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Dostupné přes Windows:** `\\tower\Backup\Critical\MongoDBBackup\`
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Konfigurace backup skriptu
|
||||
|
||||
Soubor: `mongodbbackup_with_gzip.sh`
|
||||
|
||||
| Proměnná | Hodnota | Popis |
|
||||
|----------|---------|-------|
|
||||
| `CONTAINER_NAME` | `MongoDB` | Jméno Docker kontejneru |
|
||||
| `BASE_PATH` | `/mnt/user/Backup/Critical/MongoDBBackup` | Cesta k zálohám |
|
||||
| `KEEP_DAYS` | `3` | Smazat zálohy starší než N dní |
|
||||
| `KEEP_COUNT` | `3` | Ponechat max N posledních záloh |
|
||||
| `WHAT_TO_BACKUP` | `("admin" "edc" ...)` | Seznam DB k zálohování |
|
||||
|
||||
**Klíčové:** Backup používá `mongodump --archive --gzip` který streamuje přes stdout - nepotřebuje volume mount v kontejneru.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Backup
|
||||
|
||||
Skript je registrován v Unraid User Scripts jako **MONGODB_BACKUP** na Tower.
|
||||
|
||||
```
|
||||
TOOLS → USER SCRIPTS → MONGODB_BACKUP → RUN SCRIPT
|
||||
```
|
||||
|
||||
**Cesta na Unraidu:**
|
||||
```
|
||||
/boot/config/plugins/user.scripts/scripts/MONGODB_BACKUP/script
|
||||
```
|
||||
|
||||
**Očekávaný výstup:**
|
||||
```
|
||||
Processing database: edc
|
||||
SUCCESS: edc backed up successfully
|
||||
Dump size: 436K
|
||||
Cleaning up old backups for edc...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Restore
|
||||
|
||||
### Metoda 1: Ze sdíleného share (doporučeno, ověřeno)
|
||||
|
||||
Záloha je dostupná na Tower1 přes SMB - `/mnt/user/Backup/Critical/MongoDBBackup/`.
|
||||
Pokud není automaticky namountováno, zkopíruj soubor na Tower1 share `#test`:
|
||||
|
||||
```bash
|
||||
# Z Windows:
|
||||
Copy-Item "\\tower\Backup\Critical\MongoDBBackup\tower\edc\2026-05-23_0532\edc.archive.gz" "\\tower1\#test\edc.archive.gz"
|
||||
```
|
||||
|
||||
Restore skript na Tower1 (User Scripts → **MONGODB_RESTORE**):
|
||||
```bash
|
||||
docker exec -i MongoDB mongorestore --archive --gzip --drop < /mnt/user/#test/edc.archive.gz
|
||||
```
|
||||
|
||||
### Metoda 2: SSH stream Tower → Tower1 (ověřeno, funguje)
|
||||
|
||||
```bash
|
||||
ssh -o StrictHostKeyChecking=no root@192.168.1.76 \
|
||||
'cat /mnt/user/Backup/Critical/MongoDBBackup/tower/edc/2026-05-23_0532/edc.archive.gz' \
|
||||
| docker exec -i MongoDB mongorestore --archive --gzip --drop
|
||||
```
|
||||
|
||||
**Cesta skriptu na Tower1:**
|
||||
```
|
||||
/boot/config/plugins/user.scripts/scripts/MONGODB_RESTORE/script
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ Reálné časy (ověřeno)
|
||||
|
||||
| Databáze | Velikost zálohy | Dokumentů | Čas restore |
|
||||
|----------|----------------|-----------|-------------|
|
||||
| admin | 360 B | 1 | < 1 min |
|
||||
| edc | 436 KB | 4563 | ~7 minut |
|
||||
|
||||
> **Pozor:** Restore vypadá že "stojí" - ale probíhá indexace. Například `edc.queries_snapshots` (2091 docs, 5 indexů včetně compound unique) trvá několik minut. **Nezavírat okno!**
|
||||
|
||||
---
|
||||
|
||||
## ✅ Výsledek úspěšného restore (edc)
|
||||
|
||||
```
|
||||
finished restoring edc.MDD3003_DateofVisit (381 documents, 0 failures)
|
||||
finished restoring edc.queries_snapshots (2091 documents, 0 failures)
|
||||
finished restoring edc.queries (2091 documents, 0 failures)
|
||||
restoring indexes for collection edc.queries from metadata
|
||||
- queryId_1 (sparse, unique)
|
||||
- queryStatus_1
|
||||
- openedDate_1
|
||||
- site.number_1
|
||||
- subject.label_1
|
||||
restoring indexes for collection edc.queries_snapshots from metadata
|
||||
- queryId_1_snapshotDate_1 (compound, unique)
|
||||
- snapshotDate_1
|
||||
- queryStatus_1
|
||||
- site.number_1
|
||||
- subject.label_1
|
||||
4563 document(s) restored successfully. 0 document(s) failed to restore.
|
||||
Exit: True
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
| Problém | Příčina | Řešení |
|
||||
|---------|---------|--------|
|
||||
| Restore "stojí" minuty | Indexace probíhá | Počkej, nezavírej okno |
|
||||
| `--dumpDbUsersAndRoles` error | MongoDB bez auth nemá users/roles | Flag odstraněn ze skriptů |
|
||||
| `tar: Cannot stat` | mongodump zapisuje do kontejneru, ne na host | Použít `--archive --gzip` (stdout stream) |
|
||||
| SSH stream visí | SSH drží stdin otevřený | Přidat `-n` flag nebo použít lokální soubor |
|
||||
| `Permission denied` | Práva na složky | `chmod 755 /mnt/user/Backup/Critical/MongoDBBackup` |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Historie vývoje a naučené lekce
|
||||
|
||||
1. **mongodump `--out` do kontejneru nefunguje** - kontejner zapisuje do svého filesystému, host soubory nevidí. Řešení: `--archive --gzip` streamuje přes stdout.
|
||||
|
||||
2. **`--dumpDbUsersAndRoles` selže** na MongoDB bez auth - odstraněno.
|
||||
|
||||
3. **tar cesta** - mongodump vytváří `DUMP_DIR/DB_NAME/kolekce.bson`, ne přímo `DUMP_DIR/kolekce.bson`.
|
||||
|
||||
4. **Restore je pomalý** - indexace compound a unique indexů trvá. Normální chování, není to chyba.
|
||||
|
||||
5. **SSH stream** - funguje ale při pomalé indexaci může paramiko timeout. Bezpečnější je lokální soubor přes share.
|
||||
@@ -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