Backup · Restore
The data lake backup comes in two kinds. Choose based on what you lost.
| Logical Dump | Physical Backup | |
|---|---|---|
| Command | pd backup (no arguments) | pd backup run …, and a daily systemd timer |
| What | PostgreSQL user DB as a SQL file (pg_dump) | PostgreSQL via pgBackRest, Cassandra via Medusa — the data files themselves |
| Where | /data1/pp-data/postgres/dump/<db>-YYYYmmdd_HHMMSS.sql | /data1/pp-backup/ (pgbackrest/ · medusa/) + log history.jsonl |
| Restore | pd recover <파일> — pp one DB | pd backup restore … — entire data directory |
| Full / differential · point-in-time recovery | None (always full) | Yes. PostgreSQL supports point-in-time recovery (PITR) via --target |
The backup the timer takes at night and the backup an operator takes with pd backup run pass through the same toolkit (plantpulse-backup) and land in the same history.jsonl. The admin console backup screen runs the same command.
Automatic Backup — Already Enabled
| Job | When | What |
|---|---|---|
postgres-diff | Daily at 01:30 | PostgreSQL differential |
postgres-full | Sunday at 01:00 | PostgreSQL full |
cassandra-diff | Daily at 01:20 | Cassandra differential |
cassandra-full | Sunday at 00:10 | Cassandra full |
purge | Sunday at 03:00 | Clean up per retention policy |
docker exec plantpulse-datalake pd backup schedule # 일정 · 마지막 결과 · 다음 실행
docker exec plantpulse-datalake pd backup list # 세트 목록
docker exec plantpulse-datalake pd backup status # 지금 도는 것이 있나
If the LAST column in pd backup schedule is never, it has never run (normal); if it is fail (…), it shows the error from the last run. A Cassandra set with SIZE of - has no size information, but that is not zero. Do not restore from a set where STATUS is error or incomplete.
Change the Schedule
docker exec plantpulse-datalake pd backup schedule set --job postgres-diff --calendar "*-*-* 02:45:00"
docker exec plantpulse-datalake pd backup schedule set --job purge --enabled false
docker exec plantpulse-datalake pd backup schedule reset --job postgres-diff # 그 잡만 기본으로
docker exec plantpulse-datalake pd backup schedule reset # 전부 기본으로
The calendar uses systemd syntax — *-*-* 02:45:00 (daily at 02:45), Sun *-*-* 01:00:00 (Sunday at 01:00), Mon..Fri *-*-* 23:30:00 (weekdays). Invalid expressions are caught in validation and nothing is written. The choice is saved in /data1/pp-data/backup/schedule.json and is reapplied at every startup, even if you recreate the container.
The global switch wins. If you set PP_BACKUP_SCHEDULE_ENABLED=false in the sidecar, the timer only logs «skipped» for every job, regardless of individual settings.
Before Large Operations — Capture One More Snapshot Now
Before upgrades, restores, or configuration changes, capture one more snapshot of this moment.
docker exec plantpulse-datalake pd backup run --engine postgres --type diff
docker exec plantpulse-datalake pd backup run --engine cassandra --type full
docker exec plantpulse-datalake pd backup # 그리고 SQL 사본 하나
Only one runs at a time — if one is running, it rejects with exit 3. Even if the tool exits with 0, if the repository did not grow, it is marked as fail.
Restore — from Physical Backup
Last resort. All writes after that set are lost. This verb enforces a procedure — if you run it without --yes, it refuses and tells you to use --dry-run.
# 1. 세트 고르기 — STATUS 가 ok 인 것만
docker exec plantpulse-datalake pd backup list
# 2. 드라이런 — 전제조건 일곱과 «정확히 무슨 명령이 무엇을 덮어쓸지». 아무것도 안 건드린다
docker exec plantpulse-datalake pd backup restore --engine postgres --set 20260903-013040F_20260904-135107D --dry-run
# preconditions (all pass - ready) 가 나올 때까지 실행하지 않는다
# 3. pp 를 쓰는 서비스를 역순으로 내린다 — storage 는 둔다 (PostgreSQL 은 이 동사가 스스로 멈추고 띄운다)
docker exec plantpulse-datalake pd stop admin-api
docker exec plantpulse-datalake pd stop data-gateway
docker exec plantpulse-datalake pd stop workflow
docker exec plantpulse-datalake pd stop cep
docker exec plantpulse-datalake pd stop timeseries
# 4. 실행
docker exec plantpulse-datalake pd backup restore --engine postgres --set 20260903-013040F_20260904-135107D --yes
# 5. 끝 줄 "done in NNs - restart the dependent services" 를 보고
docker exec plantpulse-datalake pd restart
# 6. 확인
docker exec plantpulse-datalake pd status # 0 STOPPED
docker exec plantpulse-datalake pd backup status # 락이 free
- Point-in-time recovery (PITR) — PostgreSQL only; you can pass a timestamp like
--target "2026-09-04 12:00:00". That set is restored, then WAL is replayed up to that time. If you pass--targetto Cassandra, exit 2. - Cassandra restore: Medusa stops and starts Cassandra itself. If you choose a differential set, the full set it references is also restored.
- Does not run on workers. Restore is a master operation; workers follow it.
Restore — from Logical Dump
pp restores one database to a logical dump snapshot. No undo, no dry run — the moment you pass the file name, DROP DATABASE "pp" executes.
ls -l /data1/pp-data/postgres/dump/ # 날짜와 크기를 먼저 눈으로
docker exec -it plantpulse-datalake pd recover # 목록을 찍고 파일 이름을 묻는다 (Ctrl+C 취소)
docker exec plantpulse-datalake pd recover pp-20260904_131500.sql
The procedure is the same as steps 3–6 of physical restore (stop the service first, bring it up after). Even if you load a dump from another database (temporal, hive, kestra), it goes into pp — those databases use physical backup.
Do Not
- Do not run
--yeswithout--dry-run. A restore you did not see the plan for is a restore where you do not know what point in time you are returning to. - Do not restore over a running service. Attached services hold stale sessions and emit errors.
- Do not manually delete the lock file (
/data1/pp-backup/pd-backup.lock). A lock from a dead PID is read as free bypd. - Do not copy dumps to
/data1/pp-temp.pd cleandeletes them.
Related Documentation
- Backup and Recovery — volume backup, offsite replication, disaster recovery scenarios
pdCLI- Admin Console — Backup Screen