Files
ems/docs/database-reset-and-restore.md
Dusan Vojacek c11ce83a97
Some checks failed
deploy / deploy (push) Successful in 18s
test / smoke-test (push) Has been cancelled
update flyway 10->12
2026-04-05 11:53:02 +02:00

9.5 KiB

Reset PostgreSQL / Timescale (Docker) a obnova z dumpu

Postup pro smazání dat databáze (volume), nový čistý cluster a obnovu z pg_dump -Fc. Platí stejně na lokálu i na cílovém serveru (např. /opt/ems-deploy): neprováděj in-place „upgrade“ starého datadisku jen přepnutím Docker image mezi major verzemi PostgreSQL.

Související skripty v repu: scripts/export_ems_db.sh, scripts/import_ems_db.sh.

Obecný kontext self-hosted deploye: deployment-self-hosted.md.


Proč ne „jen změnit image“ z PG16 na PG18

Major upgrade PostgreSQL se má dělat pg_upgrade nebo dump/restore. Prosté přepnutí image u existujícího volume nestačí a může vést k poškozenému nebo nekompatibilnímu datadir. Oficiální dokumentace: PostgreSQL: pg_upgrade.

V Docker Compose je dump/restore obvykle jednodušší než pg_upgrade (potřebuješ staré i nové binárky a dva datadiry najednou). Bezpečná cesta: nový prázdný cluster (nový volume) + restore zálohy.


Sladění verzí TimescaleDB

Zdroj zálohy a cílový kontejner musí mít sladěnou verzi rozšíření TimescaleDB vůči tomu, co očekává image — jinak často narazíš na catalog mismatch při restore nebo po něm. Před migrací ověř na obou stranách:

docker compose exec -T db psql -U "$DB_USER" -d ems -c "select version();"
docker compose exec -T db psql -U "$DB_USER" -d ems -c "select extname, extversion from pg_extension where extname='timescaledb';"

Kontext a restore workflow: TimescaleDB: Troubleshooting (self-hosted), Upgrade TimescaleDB in Docker.

V repozitáři je pro nové instalace očekávaný image např. timescale/timescaledb:2.26.1-pg18 (viz docker-compose.yml). Pinni tag na cíli stejně jako u zdroje dumpu.


0. Před začátkem

  • Máš zálohu .dump (custom format -Fc), ideálně podle kroku 1 níže nebo ./scripts/export_ems_db.sh.
  • DB_USER / DB_PASSWORD v .env na cíli odpovídají initu kontejneru db (po smazání volume se DB založí znovu z .env).
  • pg_restore nikdy s -j (paralelní restore) u Timescale — může rozbít pořadí objektů u hypertable.

Na serveru před mazáním volume často zastav služby, které píší do DB:

cd /opt/ems-deploy
docker compose --env-file .env stop backend postgrest frontend

(db může běžet až do smazání volume; nebo celý stack sestřelíš v jednom kroku níže.)


1) Na zdroji: dump

Z kořene projektu (lokálně nebo na stroji, kde běží zdrojová DB):

docker compose exec -T db pg_dump \
  -U "$DB_USER" \
  -d ems \
  -Fc \
  --no-owner \
  --no-privileges \
  -f /tmp/ems.dump

docker compose cp db:/tmp/ems.dump ./ems.dump
ls -lh ./ems.dump

Alternativa z repa: ./scripts/export_ems_db.sh ./ems.dump.

Přenos na server (příklad):

scp ./ems.dump root@server:/tmp/ems.dump

2) Ověření zdroje (a případně cíle)

docker compose exec -T db psql -U "$DB_USER" -d ems -c "select version();"
docker compose exec -T db psql -U "$DB_USER" -d ems -c "select extname, extversion from pg_extension where extname='timescaledb';"

3) Zastavit stack a smazat jen DB volume

docker compose down
docker volume ls | grep db_data

Smaž volume pro databázi. Název závisí na Compose project name (složka nebo COMPOSE_PROJECT_NAME), typicky {projekt}_db_data, např. ems_db_data nebo ems-deploy_db_data:

docker volume rm ems_db_data

Jestli nechceš hledat přesný název a máš jen compose-definované volumes:

docker compose down -v

Pozor: down -v smaže volumes definované v daném compose souboru — lokální DB tím kompletně zahodíš (v tomto scénáři je to záměr, obnova jde z dumpu).


4) Compose na cílové verzi Postgresu / Timescale

V docker-compose.yml nastav konkrétní tag, např.:

services:
  db:
    image: timescale/timescaledb:2.26.1-pg18

Nespoléhej na „upgrade“ starého volume změnou image — viz úvod.


5) Nový prázdný cluster (jen db)

docker compose up -d db

Počkej na healthy (pg_isready v healthchecku). Init vytvoří prázdnou databázi ems a uživatele z POSTGRES_USER / POSTGRES_PASSWORD.

Ověření:

docker compose exec -T db psql -U "$DB_USER" -d ems -c "select version();"
docker compose exec -T db psql -U "$DB_USER" -d ems -c "select extname, extversion from pg_extension where extname='timescaledb';"

6) Nahraj dump do kontejneru

docker compose cp ./ems.dump db:/tmp/ems.dump

Na serveru může být cesta /tmp/ems.dump už na disku — pak cp z hosta odpovídá tvé cestě k souboru.


7) Restore (Timescale pre / post)

Nejdřív příprava podle dokumentace Timescale (full restore):

docker compose exec -T db psql -U "$DB_USER" -d ems -c "select public.timescaledb_pre_restore();"

Restore:

docker compose exec -T db pg_restore \
  -U "$DB_USER" \
  -d ems \
  --no-owner \
  --no-privileges \
  -v \
  /tmp/ems.dump

Dokončení:

docker compose exec -T db psql -U "$DB_USER" -d ems -c "select public.timescaledb_post_restore();"

Alternativa: bash scripts/import_ems_db.sh /tmp/ems.dump (z kořene repa na serveru s naklonovanou aplikací) — skript doplní CREATE EXTENSION, timescaledb_pre_restore, pg_restore s --clean --if-exists, pak ALTER EXTENSION timescaledb UPDATE (srovnání katalogu zálohy s verzí v imagi) a timescaledb_post_restore. Na úplně čerstvém volume je ruční sekvence výše ekvivalentní v principu; skript je praktičtější při opakovaném importu na serveru.

Časté jevy:

  • pg_restore: warning: errors ignored — často kvůli FK na hypertable (ALTER TABLE ONLY). Po importu vždy Flyway (migrace V034 a okolí doplňují chybějící FK podle verze repa).
  • Catalog version mismatch — sladit Timescale tag na cíli se zdrojem nebo pořídit nový dump po upgrade zdroje; skript import_ems_db.sh řeší část přes ALTER EXTENSION timescaledb UPDATE.

Výjimka v prostředí: EMS_SKIP_TIMESCALE_RESTORE_HOOKS=1 u skriptu přeskočí pre/post (jen výjimečně).


8) Flyway migrace (EMS)

cd /opt/ems-deploy
docker compose --env-file .env run --rm flyway migrate

Lokálně z kořene repa (bez --env-file, pokud používáš výchozí .env):

docker compose run --rm flyway migrate

9) Celý stack

docker compose up -d

Na serveru např.:

docker compose --env-file .env up -d

nebo /opt/ems-deploy/deploy.sh (git sync, flyway, build, up -d — pokud už je Flyway z kroku 8 hotový, znovu typicky jen doplní repeatable migrace).


10) Rychlá kontrola

docker compose exec -T -e PGPASSWORD="$DB_PASSWORD" db \
  psql -U "$DB_USER" -d ems -c "SELECT count(*) FROM ems.site;"

11) Úplně čistá varianta bez mazání stávajícího volume (rollback)

Můžeš vedle současného stacku spustit druhý compose projekt (jiné COMPOSE_PROJECT_NAME nebo jiná složka), jiný volume a jiný mapovaný port, např.:

  • starý stack na host portu 5432;
  • nový PG18 dočasně na 5433;
  • restore do nového, ověření;
  • pak starý stack zastavit a volume zahodit, nebo porty přemapovat podle potřeby.

Tím máš možnost vrátit se ke staré DB, dokud novou neověříš.


12) Slabší varianta: drop databáze ems bez mazání celého volume

Pokud nechceš mazat celý Postgres volume, lze zrušit jen databázi ems a znovu ji vytvořit (méně typické u hlubších problémů s katalogem Timescale; u poškozených chunků je spolehlivější smazat volume):

docker compose exec -T -e PGPASSWORD="$DB_PASSWORD" db \
  psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS ems WITH (FORCE);"
docker compose exec -T -e PGPASSWORD="$DB_PASSWORD" db \
  psql -U "$DB_USER" -d postgres -c "CREATE DATABASE ems OWNER \"${DB_USER}\";"

Pak znovu krok 7 (restore) a Flyway.


13) Robustnější strategie (odkaz)

Plný postup „schéma odděleně od dat“ a obnova hypertable přes create_hypertable popisuje Tiger Data / Timescale v dokumentaci k zálohám. Tento repozitář používá praktický jednosouborový -Fc restore; při opakovaných problémech zvaž jejich oficiální postup.


14) Shrnutí příkazů (server /opt/ems-deploy)

cd /opt/ems-deploy
docker compose --env-file .env stop backend postgrest frontend
docker compose --env-file .env down
docker volume rm <JMÉNO_db_data>   # z: docker volume ls | grep db_data

docker compose --env-file .env up -d db
# počkat až je db healthy

docker compose cp /tmp/ems.dump db:/tmp/ems.dump
docker compose --env-file .env exec -T db psql -U "$DB_USER" -d ems -c "select public.timescaledb_pre_restore();"
docker compose --env-file .env exec -T db pg_restore -U "$DB_USER" -d ems --no-owner --no-privileges -v /tmp/ems.dump
docker compose --env-file .env exec -T db psql -U "$DB_USER" -d ems -c "select public.timescaledb_post_restore();"

docker compose --env-file .env run --rm flyway migrate
docker compose --env-file .env up -d

Nebo místo tří exec řádků s restore použij bash app/scripts/import_ems_db.sh /tmp/ems.dump a pak Flyway + up -d.