Zálohy a obnova

Noční online záloha SQLite do OCI Object Storage, obnova jedním příkazem a nacvičená havárie.

Na této stránce

V jedné větě: Každou noc ve 02:30 UTC se udělá konzistentní snímek všech databází a klíčů, zabalí se a uloží do bucketu mimo VM; obnova je jeden příkaz restore.sh latest.

Jak záloha funguje

sequenceDiagram
    autonumber
    participant T as systemd timer (02:30 UTC)
    participant S as backup.sh
    participant HC as healthchecks.io
    participant P as backup.py (kontejner oci-cli)
    participant V as volumes web-data, inventory-data
    participant B as bucket minishop-backups

    T->>S: spustit (uživatel deploy)
    S->>HC: /start
    S->>P: docker run … backup
    P->>V: online backup SQLite (ordering, journeys, users, inventory) + /data/keys + obrázky produktů
    P->>P: integrity_check, tar.gz minishop-RRRRMMDDTHHMMSSZ
    P->>B: upload (přihlášení instance principal – bez klíče)
    S->>HC: ping OK (jinak /fail)
    Note over B: lifecycle pravidlo smaže zálohy starší než 7 dní
Část Kód
Časovač a služba systemd minishop-backup.timer, minishop-backup.service
Spouštěč + hlášení na healthchecks.io backup.sh
Vlastní záloha a obnova (Python) backup.py
Obnova restore.sh
Bucket, lifecycle, oprávnění backup.tf

Rozhodnutí a proč

Rozhodnutí Proč
Online backup API SQLite, ne kopie souboru soubor může být uprostřed zápisu – kopie by byla poškozená; .backup udělá konzistentní snímek za běhu
Instance principal (identita VM) na VM neleží žádný klíč ani heslo k úložišti
VM smí zapisovat a číst, ne mazat ani přepsat napadená VM zálohy nezničí; staré maže lifecycle pravidlo služby Object Storage
Bucket mimo VM, prevent_destroy záloha musí přežít smazání VM i omyl v OpenTofu
Zálohuje se i /data/keys bez Data Protection klíčů by po obnově neplatily otevřené formuláře
Zálohují se i obrázky produktů (/data/images skladu, e-shop krok 2B) jména souborů jsou v inventory.db – bez souborů by výloha ukazovala chybějící obrázky. Složky se zálohují jako celek (DIRECTORIES v backup.py); starší záloha bez nich obnovu nezastaví
RabbitMQ se nezálohuje zprávy jsou dočasné; pravda je v outboxech obnovených databází
healthchecks.io (dead man's switch) ozve se, když záloha neproběhne – to zevnitř VM nikdo nepozná
Image oci-cli připnutý na verzi záloha se nesmí rozbít tím, že se změní nástroj

Obnova

sudo -u deploy /opt/minishop/restore.sh list     # co je v bucketu
sudo -u deploy /opt/minishop/restore.sh latest   # nejnovější záloha

Skript zastaví web a inventory-api (nikdo nezapisuje), stáhne zálohu, zkontroluje ji (integrity_check), vymění soubory ve volumes (původní nechá jako *.before-restore-…) a služby znovu spustí.

Po startu služby doplní obnoveným databázím chybějící migrace schématu (Sdílené jádro – migrace databází) – i záloze z doby před migracemi (baseline). Obnovit jde tedy i starší zálohu; opačně ne – kód starší než schéma zálohy novější sloupce jen ignoruje.

Před rizikovou akcí ruční záloha: sudo systemctl start minishop-backup.

Nová databáze = přidat do DATABASES, nová složka s daty (jako obrázky) do DIRECTORIES v backup.py.

Cvičná havárie

Obnova, kterou nikdo nezkusil, je jen přání. Proto proběhla zkouška: VM se smazala → tofu apply vytvořila novou → workflow Deploy nasadil aplikaci → restore.sh latest vrátil data → objednávky byly zpět.

Na internetu