From 2f7d3c2770585a63fbf309b5a1b875887d94b720 Mon Sep 17 00:00:00 2001 From: Dusan Vojacek Date: Sun, 5 Apr 2026 10:45:39 +0200 Subject: [PATCH] upgrade na pg18 --- CLAUDE.md | 1 + deploy/docker-compose.yml | 2 +- docker-compose.yml | 3 +- docs/database-reset-and-restore.md | 194 +++++++++++++++++++++++++++++ docs/deployment-self-hosted.md | 9 +- scripts/import_ems_db.sh | 23 +++- 6 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 docs/database-reset-and-restore.md diff --git a/CLAUDE.md b/CLAUDE.md index edcef10..8ee0a7a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -176,6 +176,7 @@ Specifikace z `docs/02-architecture.md`, modulových docs a komentářů v `plan | Audit 15min | `db/routines/R__fn_fill_audit_interval.sql`, `docs/04-modules/telemetry.md` | | Nové sloupce / tabulky | nový `db/migration/V00x__*.sql` + případně `db/routines` / `db/views` | | Self-hosted deploy (Gitea, Caddy, `/opt/ems-deploy`) | `docs/deployment-self-hosted.md`, `deploy/deploy.sh` | +| Reset DB / restore z dumpu (Docker volume, Timescale) | `docs/database-reset-and-restore.md`, `scripts/import_ems_db.sh` | | Nespecifikované chování | `docs/06-open-questions.md` (přidat otázku, neimpl. naslepo) | --- diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index c59b494..05238ed 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -8,7 +8,7 @@ services: db: - image: timescale/timescaledb:latest-pg16 + image: timescale/timescaledb:2.26.1-pg18 restart: unless-stopped environment: POSTGRES_DB: ems diff --git a/docker-compose.yml b/docker-compose.yml index f1153b7..9ba638d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,8 @@ services: db: - image: timescale/timescaledb:latest-pg16 + #image: timescale/timescaledb:2.26.1-pg18 + image: timescale/timescaledb:2.26.1-pg16 restart: unless-stopped environment: POSTGRES_DB: ems diff --git a/docs/database-reset-and-restore.md b/docs/database-reset-and-restore.md new file mode 100644 index 0000000..3c061ab --- /dev/null +++ b/docs/database-reset-and-restore.md @@ -0,0 +1,194 @@ +# Reset PostgreSQL / Timescale (Docker) a obnova z dumpu + +Přesný postup pro **smazání dat databáze** (volume) a **nový import** `pg_dump -Fc` na serveru typu `/opt/ems-deploy`. Po resetu zmizí veškerá data v DB EMS. + +**Související skripty v repu:** `scripts/import_ems_db.sh`, `scripts/export_ems_db.sh`. + +Obecný kontext self-hosted deploye: [deployment-self-hosted.md](deployment-self-hosted.md). + +--- + +## 0. Před začátkem + +- Máš zálohu `.dump` (custom format), ideálně z `scripts/export_ems_db.sh` nebo ekvivalentního `pg_dump -Fc`. +- **`DB_USER` / `DB_PASSWORD` v `.env` na cíli** odpovídají tomu, co očekává init kontejneru `db` (po smazání volume se DB vytvoří znovu se stejnými údaji z `.env`). +- Timescale: image `timescale/timescaledb:latest-pg16` se v čase mění. Záloha ze **staršího** Timescale na **novější** imagi vyžaduje po restore `ALTER EXTENSION timescaledb UPDATE` — to už dělá `import_ems_db.sh`. Při problémech zvaž **pin** imagi (např. `:2.25.2-pg16`) stejně jako u zdroje dumpu. +- **`pg_restore` nikdy s `-j`** (paralelní restore) u Timescale. + +--- + +## 1. (Volitelně) Export z vývojového stroje + +Z kořene repa, kde běží lokální `docker compose` a `.env` s `DB_USER` / `DB_PASSWORD`: + +```bash +cd /cesta/k/ems-cursor +./scripts/export_ems_db.sh ~/ems_zaloha_$(date +%Y%m%d_%H%M%S).dump +``` + +Přenos na server (příklad): + +```bash +scp ~/ems_zaloha_*.dump root@server:/tmp/ems.dump +``` + +--- + +## 2. Na serveru: zastavit služby, které píší do DB + +Aby při mazání volume a restore nebyl konflikt: + +```bash +cd /opt/ems-deploy +docker compose --env-file .env stop backend postgrest frontend +``` + +(`db` nech může běžet do kroku 4, nebo všechno zastavit — viz krok 3.) + +--- + +## 3. Zastavit stack a smazat datový volume Postgresu + +```bash +cd /opt/ems-deploy +docker compose --env-file .env down +``` + +**Jméno volume** závisí na názvu Compose projektu (složka nebo `COMPOSE_PROJECT_NAME`). Zjisti ho: + +```bash +docker volume ls | grep -E 'db_data|ems' +``` + +Typicky u deploye z `/opt/ems-deploy` uvidíš něco jako `ems-deploy_db_data` (prefix `{project}_db_data` k klíči `db_data:` z compose). + +**Smaž volume** (doplň přesný název z výpisu): + +```bash +docker volume rm ems-deploy_db_data +``` + +Tím zmizí **celý** obsah dat Postgresu v tom projektu. Ostatní Docker volume (pokud nějaké máš) se nedotknou. + +--- + +## 4. Naběhnout jen databázi + +```bash +cd /opt/ems-deploy +docker compose --env-file .env up -d db +docker compose --env-file .env ps +``` + +Počkej, až je služba `db` **healthy** (`pg_isready` v healthchecku). + +Init image vytvoří prázdnou databázi **`ems`** a uživatele z `POSTGRES_USER` / `POSTGRES_PASSWORD`. + +--- + +## 5. Import dumpu (Timescale hooks + restore) + +Dump musí být na serveru, např. `/tmp/ems.dump`. + +```bash +cd /opt/ems-deploy +bash app/scripts/import_ems_db.sh /tmp/ems.dump +``` + +Skript v kontejneru `db` postupně: + +1. `CREATE EXTENSION IF NOT EXISTS timescaledb` +2. `SELECT timescaledb_pre_restore();` +3. `pg_restore` **bez** `-j` (`--clean --if-exists --no-owner --no-acl`) +4. `ALTER EXTENSION timescaledb UPDATE;` (srovnání katalogu se verzí v imagi) +5. `SELECT timescaledb_post_restore();` + +Výjimky: `EMS_SKIP_TIMESCALE_RESTORE_HOOKS=1` v prostředí přeskočí body 2 a 5 (jen výjimečně). + +**Časté jevy:** + +- `pg_restore: warning: errors ignored` — často kvůli FK na hypertable (`ALTER TABLE ONLY`). Po importu **vždy** Flyway (migrace **V034** doplní chybějící FK). +- Selhání **catalog version mismatch** — typicky vyřeší `ALTER EXTENSION` ve skriptu; jinak pin Timescale imagi nebo nový dump po upgrade zdroje. + +--- + +## 6. Flyway migrace + +Doplní schéma oproti dumpu (včetně oprav PK/chunků/FK z V032–V034 podle verze repa): + +```bash +cd /opt/ems-deploy +docker compose --env-file .env run --rm flyway migrate +``` + +--- + +## 7. Celý stack + +```bash +cd /opt/ems-deploy +docker compose --env-file .env up -d +``` + +Nebo jednorázový deploy z aplikace: + +```bash +/opt/ems-deploy/deploy.sh +``` + +(`deploy.sh` dělá git sync, `flyway migrate`, `build`, `up -d` — pokud už jsi Flyway spustil v kroku 6, znovu obvykle jen doplní repeatable migrace.) + +--- + +## 8. Rychlá kontrola + +```bash +docker compose -f /opt/ems-deploy/docker-compose.yml --env-file /opt/ems-deploy/.env ps +``` + +Volitelně SQL (z hosta přes `docker compose exec`): + +```bash +docker compose --env-file .env exec -T -e PGPASSWORD="$DB_PASSWORD" db \ + psql -U "$DB_USER" -d ems -c "SELECT count(*) FROM ems.site;" +``` + +--- + +## 9. Slabší varianta bez mazání volume + +Pokud nechceš mazat celý volume, lze zkusit přepnout databázi uvnitř (méně typické u Timescale; u poškozeného katalogu chunků je **spolehlivější smazat volume**): + +```bash +docker compose --env-file .env exec -T -e PGPASSWORD="$DB_PASSWORD" db \ + psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS ems WITH (FORCE);" +docker compose --env-file .env exec -T -e PGPASSWORD="$DB_PASSWORD" db \ + psql -U "$DB_USER" -d postgres -c "CREATE DATABASE ems OWNER \"${DB_USER}\";" +``` + +Pak znovu **`import_ems_db.sh`** a **Flyway**. + +--- + +## 10. Robustnější strategie (odkaz) + +Plný „schema odděleně od dat“ a obnova hypertable přes `create_hypertable` popisuje **Tiger Data / Timescale** v dokumentaci k backupu a restore. Tento repozitář používá praktický jednokrokový `-Fc` restore přes `import_ems_db.sh`; u opakovaných problémů zvaž jejich oficiální postup (pre-data dump bez `_timescaledb*`, data zvlášť). + +--- + +## 11. Shrnutí příkazů (kostra) + +```bash +# server +cd /opt/ems-deploy +docker compose --env-file .env stop backend postgrest frontend +docker compose --env-file .env down +docker volume rm # z docker volume ls + +docker compose --env-file .env up -d db +# počkat healthy + +bash app/scripts/import_ems_db.sh /tmp/ems.dump +docker compose --env-file .env run --rm flyway migrate +docker compose --env-file .env up -d +``` diff --git a/docs/deployment-self-hosted.md b/docs/deployment-self-hosted.md index 31a691f..52a16f2 100644 --- a/docs/deployment-self-hosted.md +++ b/docs/deployment-self-hosted.md @@ -153,8 +153,15 @@ curl -sf http://127.0.0.1:8080/ >/dev/null && echo frontend OK --- -## 10. Odkazy v repu +## 10. Reset DB a obnova z dumpu + +Kompletní postup (zastavení služeb, `down`, smazání volume `db_data`, jen `db`, `import_ems_db.sh`, Flyway, `up`): **[database-reset-and-restore.md](database-reset-and-restore.md)**. + +--- + +## 11. Odkazy v repu - `deploy/deploy.sh` — jediný produkční vstup „co se na serveru spouští“. - `deploy/docker-compose.yml` — šablona runtime Compose (kopíruje se do `/opt/ems-deploy`). - `.gitea/workflows/deploy.yml` — napojení na runner + job kontejner. +- `docs/database-reset-and-restore.md` — zahození dat Postgres/Timescale a import zálohy. diff --git a/scripts/import_ems_db.sh b/scripts/import_ems_db.sh index 76dee06..d274c9a 100755 --- a/scripts/import_ems_db.sh +++ b/scripts/import_ems_db.sh @@ -20,8 +20,11 @@ # TimescaleDB – doporučení z dokumentace (full restore): # - Cílová DB má mít rozšíření timescaledb před restore. # - Před pg_restore: SELECT timescaledb_pre_restore(); -# - Po pg_restore: SELECT timescaledb_post_restore(); -# - Stejná major verze Postgres + Timescale jako u zálohy. +# - Po pg_restore: ALTER EXTENSION timescaledb UPDATE; (srovná katalog zálohy s verzí v imagi – +# jinak post_restore hlásí „catalog version mismatch expected … seen …“) +# - Pak: SELECT timescaledb_post_restore(); +# - Ideálně stejná major verze Postgres + Timescale jako u zálohy; jinak pin imagí +# (např. timescale/timescaledb:2.25.2-pg16 místo latest-pg16). # - Bez paralelního pg_restore (-j) – může rozbít pořadí objektů a chunky. # # pg_restore z běžného pg_dump i tak může u hypertable vygenerovat nevhodné DDL (např. ALTER TABLE ONLY @@ -103,10 +106,18 @@ RESTORE_EXIT=$? set -e if [[ "${EMS_SKIP_TIMESCALE_RESTORE_HOOKS:-0}" != "1" ]]; then - echo "Timescale: timescaledb_post_restore()…" - if ! compose_db psql -U "$DB_USER" -d ems -v ON_ERROR_STOP=1 \ - -c "SELECT timescaledb_post_restore();"; then - echo "ERROR: timescaledb_post_restore() selhal" >&2 + echo "Timescale: ALTER EXTENSION timescaledb UPDATE (katalog ze zálohy → verze v imagi)…" + if compose_db psql -U "$DB_USER" -d ems -v ON_ERROR_STOP=1 \ + -c "ALTER EXTENSION timescaledb UPDATE;"; then + echo "Timescale: timescaledb_post_restore()…" + if ! compose_db psql -U "$DB_USER" -d ems -v ON_ERROR_STOP=1 \ + -c "SELECT timescaledb_post_restore();"; then + echo "ERROR: timescaledb_post_restore() selhal (zkontroluj verze PG/Timescale vs. záloha)." >&2 + RESTORE_EXIT=1 + fi + else + echo "ERROR: ALTER EXTENSION timescaledb UPDATE selhalo – nespouštím post_restore." >&2 + echo " Zkus v compose stejný Timescale tag jako u zdroje dumpu (např. :2.25.2-pg16), nebo nový dump po upgrade zdroje." >&2 RESTORE_EXIT=1 fi else