docs(prod): репа догоняет новую раскладку postgres на prod-vm
Some checks failed
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (test + latest) (push) Has been cancelled
Docker Web / Build + push Web (push) Has been cancelled
Docker Public / Deploy :test → test.food-market.kz (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled

05.10.2026 общий postgres-инстанс с чужими боевыми базами (sklad, purchase,
calcman, calcman_staging, makesales + мусорная старая food_market) вынесен
из compose прода food-market в отдельный compose-проект shared-postgres
(контейнер shared-postgres, порт 5434, том food-market-postgres-data external).
Прод food-market поднимается в собственный контейнер food-market-prod-postgres
(порт 5437, том food-market-prod-postgres-data). Простой при разделении — 12с,
соседи живы. См. docs/shared-postgres-followup-progress.md.

Этот коммит синхронизирует репозиторий, чтобы следующий деплой из main не
воскресил старую раскладку:

- deploy/docker-compose.yml: container_name/port/volume приведены к прод-файлу
  (food-market-prod-postgres, 127.0.0.1:5437, food-market-prod-postgres-data).
- deploy/shared-postgres/ (новое): документационная копия соседнего compose'а,
  с явной пометкой «food-market им не управляет».
- deploy/food-market-backup.sh / anonymize-prod.sh / db-schema-diff.sh:
  defaults FM_PG_CONTAINER / FM_PROD_CONT = food-market-prod-postgres.
- docs/RUNBOOK.md: новый раздел «Postgres на prod-vm» с таблицей трёх
  инстансов и явным запретом трогать shared-postgres из наших скриптов.
- docs/backup-restore.md: контейнер в таблице и примерах — новый.

Guards (не в репе — живут в ~/deploy-stage.sh и ~/quality-watchdog.sh)
расширены симметрично: стенду запрещены shared-postgres, food-market-prod-
postgres[-data], 5434/5437; проду — food-market-postgres-data (чужие данные).
Проверка: docker compose config/ps на prod-vm shared-postgres не упоминают,
grep по репе — ни один скрипт не делает docker exec в shared-postgres.
This commit is contained in:
nns 2026-10-06 00:35:54 +05:00
parent ef29acb0d1
commit c4a59d7bf2
9 changed files with 194 additions and 26 deletions

View file

@ -21,14 +21,18 @@
# deploy/anonymize-prod.sh [--source <conn-uri>] [--target <conn-uri>] # deploy/anonymize-prod.sh [--source <conn-uri>] [--target <conn-uri>]
# [--out <file>] [--dry-run] # [--out <file>] [--dry-run]
# #
# Default source: ssh prod docker exec food-market-postgres pg_dump # Default source: ssh prod docker exec food-market-prod-postgres pg_dump
# Default target: local postgres@14 with TEMP DB food_market_anon # Default target: local postgres@14 with TEMP DB food_market_anon
# Default out: /home/nns/food-market-anon-YYYYMMDD.sql.gz # Default out: /home/nns/food-market-anon-YYYYMMDD.sql.gz
#
# ВАЖНО: контейнер food-market-prod-postgres (с 2026-10-05). НЕ shared-postgres —
# тот принадлежит соседнему compose-проекту с чужими боевыми базами (sklad,
# purchase, calcman, calcman_staging, makesales). См. docs/shared-postgres-followup-progress.md.
set -uo pipefail set -uo pipefail
SOURCE_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}" SOURCE_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}"
SOURCE_CONTAINER="${FM_PROD_CONT:-food-market-postgres}" SOURCE_CONTAINER="${FM_PROD_CONT:-food-market-prod-postgres}"
SOURCE_DB="${FM_PG_DB:-food_market}" SOURCE_DB="${FM_PG_DB:-food_market}"
SOURCE_USER="${FM_PG_USER:-food_market}" SOURCE_USER="${FM_PG_USER:-food_market}"
LOCAL_USER="${PGUSER:-nns}" LOCAL_USER="${PGUSER:-nns}"

View file

@ -7,8 +7,13 @@
# #
# Подразумевает что обе БД доступны (например через SSH-туннель или # Подразумевает что обе БД доступны (например через SSH-туннель или
# pg_dump --host=<host>). Дефолтные подключения: # pg_dump --host=<host>). Дефолтные подключения:
# stage = docker exec food-market-stage-postgres-1 pg_dump (через ssh dev-vm) # stage = docker exec food-market-stage-postgres pg_dump (через ssh prod-vm)
# prod = docker exec food-market-postgres pg_dump (через ssh prod-vm) # prod = docker exec food-market-prod-postgres pg_dump (через ssh prod-vm)
#
# ВАЖНО: прод-контейнер — `food-market-prod-postgres` (с 2026-10-05). Соседний
# `shared-postgres` на той же машине обслуживает ЧУЖИЕ боевые базы (sklad,
# purchase, calcman, calcman_staging, makesales) и в diff не участвует.
# См. docs/shared-postgres-followup-progress.md.
# #
# Usage: # Usage:
# deploy/db-schema-diff.sh [--stage-host HOST] [--prod-host HOST] # deploy/db-schema-diff.sh [--stage-host HOST] [--prod-host HOST]
@ -24,8 +29,8 @@ set -uo pipefail
STAGE_HOST="${FM_STAGE_HOST:-nns@192.168.1.190}" STAGE_HOST="${FM_STAGE_HOST:-nns@192.168.1.190}"
PROD_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}" PROD_HOST="${FM_PROD_HOST:-nns@admin.food-market.kz}"
STAGE_CONT="${FM_STAGE_CONT:-food-market-stage-postgres-1}" STAGE_CONT="${FM_STAGE_CONT:-food-market-stage-postgres}"
PROD_CONT="${FM_PROD_CONT:-food-market-postgres}" PROD_CONT="${FM_PROD_CONT:-food-market-prod-postgres}"
DB="${FM_PG_DB:-food_market}" DB="${FM_PG_DB:-food_market}"
DB_USER="${FM_PG_USER:-food_market}" DB_USER="${FM_PG_USER:-food_market}"
QUICK=0 QUICK=0

View file

@ -1,16 +1,32 @@
# Прод-compose food-market.
#
# ВАЖНО (2026-10-05): у food-market свой postgres прода — контейнер
# `food-market-prod-postgres`, том `food-market-prod-postgres-data`, порт
# `127.0.0.1:5437`. На prod-vm параллельно существует отдельный compose-проект
# `shared-postgres` (~/shared-postgres/docker-compose.yml, порт 5434, том
# `food-market-postgres-data` *external*) с ЧУЖИМИ боевыми базами (sklad,
# purchase, calcman, calcman_staging, makesales). Он food-market НЕ принадлежит
# и в этот compose возвращаться НЕ должен. См. docs/shared-postgres-followup-progress.md.
#
# Guards в ~/deploy-stage.sh и ~/quality-watchdog.sh падают, если здесь появится
# `shared-postgres`, `food-market-postgres-data`, порт `5434` или старое имя
# контейнера `food-market-postgres`.
services: services:
postgres: postgres:
image: ${REGISTRY:-127.0.0.1:5001}/mirror/postgres:16-alpine image: ${REGISTRY:-127.0.0.1:5001}/mirror/postgres:16-alpine
container_name: food-market-postgres container_name: food-market-prod-postgres
restart: unless-stopped restart: unless-stopped
environment: environment:
POSTGRES_DB: food_market POSTGRES_DB: food_market
POSTGRES_USER: food_market POSTGRES_USER: food_market
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-food_market_dev} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-food_market_dev}
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
# Stage VM already uses 5432 (host postgres) — map ours to 5434 to avoid clash. # prod-vm занят: 5432 — host postgres, 5434 — shared-postgres (чужой),
# 5435 — stage-postgres, 5436 — food-market-server-postgres (сосед).
# Нам остаётся 5437.
ports: ports:
- "127.0.0.1:5434:5432" - "127.0.0.1:5437:5432"
volumes: volumes:
- postgres-data:/var/lib/postgresql/data - postgres-data:/var/lib/postgresql/data
healthcheck: healthcheck:
@ -88,7 +104,9 @@ services:
volumes: volumes:
postgres-data: postgres-data:
name: food-market-postgres-data # ВАЖНО: НЕ `food-market-postgres-data` — тот том принадлежит отдельному
# проекту shared-postgres (чужие боевые базы). См. docs/shared-postgres-followup-progress.md.
name: food-market-prod-postgres-data
api-data: api-data:
name: food-market-api-data name: food-market-api-data
api-logs: api-logs:

View file

@ -2,7 +2,7 @@
# #
# food-market: ежедневный бэкап БД + загруженных файлов с ротацией. # food-market: ежедневный бэкап БД + загруженных файлов с ротацией.
# #
# Дампит Postgres (контейнер food-market-postgres) в custom-формат pg_dump # Дампит Postgres (контейнер food-market-prod-postgres) в custom-формат pg_dump
# (-Fc, пригоден для pg_restore с параллелизмом/выборочным восстановлением) и # (-Fc, пригоден для pg_restore с параллелизмом/выборочным восстановлением) и
# архивирует каталог uploads. Удаляет бэкапы старше RETENTION_DAYS дней. # архивирует каталог uploads. Удаляет бэкапы старше RETENTION_DAYS дней.
# #
@ -10,16 +10,19 @@
# вручную. Конфигурируется переменными окружения (значения по умолчанию # вручную. Конфигурируется переменными окружения (значения по умолчанию
# совпадают с deploy/docker-compose.yml): # совпадают с deploy/docker-compose.yml):
# #
# FM_PG_CONTAINER имя контейнера Postgres (food-market-postgres) # FM_PG_CONTAINER имя контейнера Postgres (food-market-prod-postgres)
# FM_PG_DB имя БД (food_market) # FM_PG_DB имя БД (food_market)
# FM_PG_USER пользователь БД (food_market) # FM_PG_USER пользователь БД (food_market)
# FM_BACKUP_DIR куда складывать бэкапы (/opt/food-market-data/backups) # FM_BACKUP_DIR куда складывать бэкапы (/opt/food-market-data/backups)
# FM_UPLOADS_DIR каталог изображений (/opt/food-market-data/uploads) # FM_UPLOADS_DIR каталог изображений (/opt/food-market-data/uploads)
# FM_BACKUP_RETENTION_DAYS срок хранения, дней (30) # FM_BACKUP_RETENTION_DAYS срок хранения, дней (30)
# #
# ВАЖНО: НЕ `food-market-postgres` и НЕ `shared-postgres` — это контейнер
# соседнего compose-проекта с ЧУЖИМИ боевыми базами (sklad, purchase, calcman,
# calcman_staging, makesales). См. docs/shared-postgres-followup-progress.md.
set -euo pipefail set -euo pipefail
CONTAINER="${FM_PG_CONTAINER:-food-market-postgres}" CONTAINER="${FM_PG_CONTAINER:-food-market-prod-postgres}"
DB="${FM_PG_DB:-food_market}" DB="${FM_PG_DB:-food_market}"
DB_USER="${FM_PG_USER:-food_market}" DB_USER="${FM_PG_USER:-food_market}"
BACKUP_DIR="${FM_BACKUP_DIR:-/opt/food-market-data/backups}" BACKUP_DIR="${FM_BACKUP_DIR:-/opt/food-market-data/backups}"

View file

@ -0,0 +1,17 @@
# deploy/shared-postgres/
Снимок стороннего compose-проекта `shared-postgres` с prod-vm, положенный в репу
как справочник. **Food-market этим compose'ом не управляет** — он живёт на
prod-vm в `~/shared-postgres/` и там же обслуживается. Любой скрипт food-market,
который трогает `shared-postgres`, том `food-market-postgres-data`, порт 5434 —
баг (guards падают).
Контекст: 2026-10-05 общий postgres-инстанс с чужими боевыми базами (`sklad`,
`purchase`, `calcman`, `calcman_staging`, `makesales` + мусорная старая
`food_market`) вынесен из compose прода food-market в отдельный compose-проект.
См. [`docs/shared-postgres-followup-progress.md`](../../docs/shared-postgres-followup-progress.md)
и [`docs/RUNBOOK.md`](../../docs/RUNBOOK.md) → раздел «Postgres на prod-vm».
Прод food-market ходит в **свой** postgres: `food-market-prod-postgres`,
том `food-market-prod-postgres-data`, порт `127.0.0.1:5437` — описан в
`deploy/docker-compose.yml`.

View file

@ -0,0 +1,50 @@
# ──────────────────────────────────────────────────────────────────────────
# shared-postgres: ДОКУМЕНТАЦИОННАЯ копия стороннего compose'а на prod-vm.
# ──────────────────────────────────────────────────────────────────────────
#
# Этот файл **не используется** ни одним из скриптов репозитория. Он лежит в
# репе как справочник: именно так на prod-vm выглядит compose-проект
# `shared-postgres`, живущий в `~/shared-postgres/docker-compose.yml`.
#
# Что это такое. С 2026-10-05 общий postgres-инстанс (чужие боевые базы
# `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс
# мусорная старая `food_market` — повреждена, не восстанавливается) вынесен
# из compose прода food-market в отдельный compose-проект. Раньше он жил в
# том же `~/food-market/deploy/docker-compose.yml` под project-name `deploy`,
# и любой `docker compose down` у food-market гасил чужие боевые базы.
#
# Проект называется `shared-postgres`, контейнер — `shared-postgres`, порт —
# `127.0.0.1:5434`, том `food-market-postgres-data` объявлен *external*
# (имя историческое — на нём лежат чужие продакшн-данные соседних систем,
# переименовывать нельзя).
#
# **Food-market НЕ управляет этим compose.** Любые наши скрипты (backup,
# anonymize, schema-diff, deploy, watchdog), включая `docker exec`, не должны
# ссылаться на `shared-postgres` / `food-market-postgres-data` / порт 5434 —
# за этим следят guards в ~/deploy-stage.sh и ~/quality-watchdog.sh.
#
# Нужен dump/бэкап чужой базы — делает её владелец у себя. См.
# docs/shared-postgres-followup-progress.md и docs/RUNBOOK.md.
name: shared-postgres
services:
db:
image: 192.168.1.193:5001/mirror/postgres:16-alpine
container_name: shared-postgres
restart: unless-stopped
env_file: .env
environment:
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- "127.0.0.1:5434:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pgdata:
external: true
name: food-market-postgres-data

View file

@ -87,6 +87,37 @@ Nginx внутри контейнера сделан с `absolute_redirect off;
off;` — иначе 301 с `/signup` на `/signup/` строился через HTTP-schema и off;` — иначе 301 с `/signup` на `/signup/` строился через HTTP-schema и
браузер уходил с https → http. См. `src/food-market.public/deploy/nginx.conf`. браузер уходил с https → http. См. `src/food-market.public/deploy/nginx.conf`.
## Postgres на prod-vm
На prod-vm (`admin.food-market.kz`, `192.168.1.190`) **три** Postgres-контейнера.
Food-market владеет только одним из них — остальные **нельзя** трогать нашими
скриптами, бэкапами, миграциями или `docker exec`.
| Контейнер | Compose-проект | Том | Порт | Чьи данные |
|---|---|---|---|---|
| `food-market-prod-postgres` | `food-market` (`~/food-market/deploy/`) | `food-market-prod-postgres-data` | `127.0.0.1:5437` | **наш прод** |
| `food-market-stage-postgres` | `food-market-stage` (`~/food-market-stage/deploy/`) | `food-market-stage-postgres-data` | `127.0.0.1:5435` | наш стенд |
| `shared-postgres` | `shared-postgres` (`~/shared-postgres/`) | `food-market-postgres-data` *external* | `127.0.0.1:5434` | **НЕ наш** — чужие боевые базы `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс мусорная старая `food_market` (повреждена, не восстанавливаем) |
Истоpически (до 2026-10-05) все эти базы жили в одном compose-проекте food-market
под именем контейнера `food-market-postgres` / томом `food-market-postgres-data`.
Любой `docker compose down` у food-market гасил чужие боевые базы. Координатор
физически разделил инстансы с одобрения владельца: food-market съехал в
собственный контейнер и том, а общий инстанс остался в compose-проекте
`shared-postgres` на старом томе (имя тома историческое — переименовывать
нельзя, в нём живые данные соседей). См. `docs/shared-postgres-followup-progress.md`.
**Правила:**
- Прод-бэкап, anonymize, schema-diff, миграции идут **только** через
`food-market-prod-postgres` (defaults скриптов именно такие).
- Контейнер `shared-postgres`, том `food-market-postgres-data`, порт `5434` —
**запрещённые** цели в наших compose/скриптах. Guards в `~/deploy-stage.sh`
и `~/quality-watchdog.sh` падают, если упомянутые паттерны всплывут в
шаблонах stage- или прод-compose в репе или на prod-vm.
- Нужен dump чужой базы — делает её владелец у себя, не из food-market.
- `deploy/shared-postgres/docker-compose.yml` в репе — это **документация**,
не исполняемый шаблон; наш `prod-deploy.sh` его не трогает.
## Бэкап и восстановление ## Бэкап и восстановление
### Расписание ### Расписание
@ -97,12 +128,20 @@ systemd-таймер `food-market-backup.timer` (см. `deploy/`) запуска
если сервер был выключен). если сервер был выключен).
Скрипт `food-market-backup.sh`: Скрипт `food-market-backup.sh`:
- `pg_dump -Fc` из контейнера `food-market-postgres` → `db-<TS>.dump`. - `pg_dump -Fc` из контейнера `food-market-prod-postgres` → `db-<TS>.dump`.
- `tar czf` каталога `/opt/food-market-data/uploads` → `uploads-<TS>.tgz`. - `tar czf` каталога `/opt/food-market-data/uploads` → `uploads-<TS>.tgz`.
- Удаляет файлы старше 30 дней (`FM_BACKUP_RETENTION_DAYS`). - Удаляет файлы старше 30 дней (`FM_BACKUP_RETENTION_DAYS`).
Папка: `/opt/food-market-data/backups/`. Папка: `/opt/food-market-data/backups/`.
> Контейнер прод-БД — `food-market-prod-postgres` (порт `127.0.0.1:5437`, том
> `food-market-prod-postgres-data`) с 2026-10-05. Соседний на той же машине
> `shared-postgres` (порт 5434, том `food-market-postgres-data` *external*) —
> **не наш**, в нём чужие боевые базы sklad/purchase/calcman/calcman\_staging/
> makesales. Любые `docker exec`/`pg_dump`/`pg_restore` в `shared-postgres` из
> наших скриптов запрещены, guards бьют. См. раздел «Postgres на prod-vm»
> ниже и `docs/shared-postgres-followup-progress.md`.
### Ручной бэкап ### Ручной бэкап
```bash ```bash
@ -111,7 +150,7 @@ ssh nns@192.168.1.190 'sudo /opt/food-market/deploy/food-market-backup.sh'
Или из репо разработчика: Или из репо разработчика:
```bash ```bash
deploy/backup.sh --remote 192.168.1.190:5434 # PG в Docker exposed на 5434 deploy/backup.sh --remote 192.168.1.190:5437 # прод-PG в Docker, exposed на 5437
``` ```
### Recovery drill (RTO ≈ 25 секунд на сегодняшних данных) ### Recovery drill (RTO ≈ 25 секунд на сегодняшних данных)
@ -131,9 +170,9 @@ Sprint 15 — verified восстановление stage'а в свежий PG-
```bash ```bash
# 1. Снять бэкап со stage'а # 1. Снять бэкап со stage'а
ssh nns@192.168.1.190 'docker exec food-market-stage-postgres-1 \ ssh nns@192.168.1.190 'docker exec food-market-stage-postgres \
pg_dump -U food_market -d food_market -Fc -f /tmp/drill.dump' pg_dump -U food_market -d food_market -Fc -f /tmp/drill.dump'
ssh nns@192.168.1.190 'docker cp food-market-stage-postgres-1:/tmp/drill.dump /tmp/drill.dump' ssh nns@192.168.1.190 'docker cp food-market-stage-postgres:/tmp/drill.dump /tmp/drill.dump'
scp nns@192.168.1.190:/tmp/drill.dump /tmp/drill.dump scp nns@192.168.1.190:/tmp/drill.dump /tmp/drill.dump
# 2. Чистый PG # 2. Чистый PG

View file

@ -13,13 +13,21 @@
| Что | Как | Файл | | Что | Как | Файл |
|---|---|---| |---|---|---|
| База данных | `pg_dump -Fc` из контейнера `food-market-postgres` | `db-<TS>.dump` (custom-format) | | База данных | `pg_dump -Fc` из контейнера `food-market-prod-postgres` | `db-<TS>.dump` (custom-format) |
| Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-<TS>.tgz` | | Загруженные файлы (картинки товаров) | `tar czf` каталога uploads | `uploads-<TS>.tgz` |
Папка назначения по умолчанию — `/opt/food-market-data/backups`. Хранение — Папка назначения по умолчанию — `/opt/food-market-data/backups`. Хранение —
30 дней (`FM_BACKUP_RETENTION_DAYS`), старые удаляются ротацией. Конфиг — 30 дней (`FM_BACKUP_RETENTION_DAYS`), старые удаляются ротацией. Конфиг —
переменными `FM_*` (см. шапку `food-market-backup.sh`). переменными `FM_*` (см. шапку `food-market-backup.sh`).
> **Контейнер прод-БД** — `food-market-prod-postgres` (с 2026-10-05, порт
> `127.0.0.1:5437`, том `food-market-prod-postgres-data`). Соседний контейнер
> `shared-postgres` (другой compose-проект, порт 5434) обслуживает чужие
> боевые базы соседних систем и food-market не принадлежит. Все `pg_dump`,
> `pg_restore`, `docker exec` в наших скриптах — только в
> `food-market-prod-postgres`. См. `docs/shared-postgres-followup-progress.md`
> и раздел «Postgres на prod-vm» в `docs/RUNBOOK.md`.
## Установка таймера на сервере (деплой-шаг) ## Установка таймера на сервере (деплой-шаг)
Предполагается, что репозиторий выложен в `/opt/food-market` (иначе скорректировать Предполагается, что репозиторий выложен в `/opt/food-market` (иначе скорректировать
@ -59,17 +67,17 @@ docker compose stop api web
DUMP=/opt/food-market-data/backups/db-YYYYMMDD-HHMMSS.dump DUMP=/opt/food-market-data/backups/db-YYYYMMDD-HHMMSS.dump
# Скопировать дамп внутрь контейнера БД # Скопировать дамп внутрь контейнера БД
docker cp "$DUMP" food-market-postgres:/tmp/restore.dump docker cp "$DUMP" food-market-prod-postgres:/tmp/restore.dump
# Вариант A — восстановить в чистую БД (рекомендуется): # Вариант A — восстановить в чистую БД (рекомендуется):
docker exec food-market-postgres psql -U food_market -d postgres -c \ docker exec food-market-prod-postgres psql -U food_market -d postgres -c \
"DROP DATABASE IF EXISTS food_market WITH (FORCE); CREATE DATABASE food_market OWNER food_market;" "DROP DATABASE IF EXISTS food_market WITH (FORCE); CREATE DATABASE food_market OWNER food_market;"
docker exec food-market-postgres pg_restore -U food_market -d food_market --no-owner /tmp/restore.dump docker exec food-market-prod-postgres pg_restore -U food_market -d food_market --no-owner /tmp/restore.dump
# Вариант B — в существующую БД, заменив объекты (без пересоздания БД): # Вариант B — в существующую БД, заменив объекты (без пересоздания БД):
# docker exec food-market-postgres pg_restore -U food_market -d food_market --clean --if-exists --no-owner /tmp/restore.dump # docker exec food-market-prod-postgres pg_restore -U food_market -d food_market --clean --if-exists --no-owner /tmp/restore.dump
docker exec food-market-postgres rm -f /tmp/restore.dump docker exec food-market-prod-postgres rm -f /tmp/restore.dump
docker compose start api web docker compose start api web
``` ```
@ -92,9 +100,9 @@ sudo tar xzf "$TGZ" -C /opt/food-market-data/
## Проверка дампа без восстановления ## Проверка дампа без восстановления
```bash ```bash
docker cp <dump> food-market-postgres:/tmp/v.dump docker cp <dump> food-market-prod-postgres:/tmp/v.dump
docker exec food-market-postgres pg_restore --list /tmp/v.dump | head # TOC валидного архива docker exec food-market-prod-postgres pg_restore --list /tmp/v.dump | head # TOC валидного архива
docker exec food-market-postgres rm -f /tmp/v.dump docker exec food-market-prod-postgres rm -f /tmp/v.dump
``` ```
Скрипт и формат проверены локально (2026-05-27): дамп `PGDMP`, custom-format, Скрипт и формат проверены локально (2026-05-27): дамп `PGDMP`, custom-format,

View file

@ -0,0 +1,24 @@
# shared-postgres follow-up: репозиторий ↔ новая раскладка postgres прода
**Задача.** 2026-10-05 координатор физически разделил два инстанса postgres на prod-vm:
- `shared-postgres` (`~/shared-postgres/docker-compose.yml`, контейнер `shared-postgres`, порт `127.0.0.1:5434`, том `food-market-postgres-data` *external*). Внутри — ЧУЖИЕ боевые базы: `sklad`, `purchase`, `calcman`, `calcman_staging`, `makesales`, плюс мусорная старая `food_market` (повреждена, не восстанавливаем). Проект compose — `shared-postgres`, не наш, живёт отдельно.
- `food-market-prod-postgres` (`~/food-market/deploy/docker-compose.yml` на prod-vm, контейнер `food-market-prod-postgres`, порт `127.0.0.1:5437`, том `food-market-prod-postgres-data`). Это НОВЫЙ собственный postgres прода food-market. Пока не запущен — прод-API лежит.
Старый compose прода (project `deploy`, контейнер `food-market-postgres`, том `food-market-postgres-data` на тех же данных) **более не существует**. Простой при разделении — 12 секунд, соседи живы. Бэкап: `docker-compose.yml.bak-20261005` на prod-vm.
Теперь нужно догнать репозиторий (шаблоны, guards, скрипты, доки), чтобы следующий деплой из main не воскресил старую раскладку, а любой `docker exec` в `shared-postgres` из кода food-market был бы невозможен.
**Правила на будущее**
- Прод food-market использует `food-market-prod-postgres` / том `food-market-prod-postgres-data` / порт `127.0.0.1:5437`.
- `shared-postgres` **не принадлежит проекту food-market**. Его `container_name`, том и порт — запрещённые паттерны в наших compose/скриптах.
- Том `food-market-postgres-data` — исторический для `shared-postgres`, в food-market compose его быть не должно (чужие данные).
## Чеклист
- [x] 1. Шаблон репо `deploy/docker-compose.yml` приведён к прод-файлу (контейнер/том/порт прода). Добавлен `deploy/shared-postgres/docker-compose.yml` как документация соседнего compose-проекта (управляется отдельно).
- [x] 2. Guards расширены: `~/deploy-stage.sh` и `~/quality-watchdog.sh` (+их копии в репо, если есть) запрещают стенду `shared-postgres`, `food-market-prod-postgres`, `food-market-prod-postgres-data`, порты `5434`/`5437`; проду — том `food-market-postgres-data`.
- [x] 3. Скрипты и доки: `deploy/food-market-backup.sh`, `deploy/anonymize-prod.sh`, `deploy/db-schema-diff.sh`, `docs/RUNBOOK.md`, `docs/backup-restore.md` указывают на `food-market-prod-postgres` вместо старого `food-market-postgres`; RUNBOOK явно говорит «shared-postgres не наш».
- [x] 4. Проверка на prod-vm: `docker compose -f ~/food-market/deploy/docker-compose.yml config` и `docker compose ps -a` не упоминают `shared-postgres`; `grep` по репе — ни один скрипт не делает `docker exec` в `shared-postgres`.
Прод не запускается, `shared-postgres` и чужие базы не трогаются, `global.json` и gateway nginx вне скоупа.