feat(ops): лёгкий Postgres на Beget под forgejo и glitchtip (вариант А) #3080

Merged
lekss361 merged 1 commit from fix/3061-infra-postgres-split into main 2026-08-24 16:31:13 +00:00

1 commit

Author SHA1 Message Date
bot-backend
7d98a674c9 feat(ops): лёгкий Postgres на Beget под forgejo и glitchtip
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Переезд ломает сам Forgejo. Базы forgejo (265 МБ) и glitchtip (729 МБ)
физически лежат внутри gendesign-postgres-1, который уезжает целиком вместе
с 15 ГБ Site Finder. В момент переезда легли бы веб, git по HTTP и Actions —
то есть CI, из которого мы деплоим, ровно тогда, когда он нужнее всего.
Отдельно обидно, что Forgejo заявлен компенсацией риска «всё в одном
аккаунте Selectel»: падая вместе с переездом, он эту роль не выполняет.

Владелец выбрал вариант А — отдельный лёгкий кластер на Beget. PostGIS тут
не нужен, обе схемы обычные реляционные: postgres:16-alpine против
postgis/postgis:16-3.4 ради одного гигабайта данных.

Мерж и деплой ничего не меняют. Сервис под профилем "infra", которого нет
ни в одном окружении на Beget, поэтому docker compose его не видит;
GLITCHTIP_DB_HOST имеет дефолт postgres, то есть строка подключения
GlitchTip рендерится байт-в-байт как сегодня. Переключение — правка одной
переменной на VM после переноса данных, откат — правка обратно.

Первая версия этого не держала: сервис стоял в профиле glitchtip, который
на Beget уже активен, и мерж поднял бы кластер с пустым INFRA_PG_PASSWORD
в вечный restart-loop при зелёном деплое. Поймано ревью.

Healthcheck проверяет не приём соединений, а наличие ОБЕИХ баз. Иначе
отравленный том — когда bootstrap-скрипт упал уже после инициализации
PGDATA и больше никогда не запустится — выглядел бы здоровым, а
обнаружился бы в ночь переезда как «role forgejo does not exist».

backup-forgejo.sh больше не хардкодит контейнер: ищет тот, где база forgejo
реально есть, и при двух кандидатах останавливается с exit 1. Это ровно
окно миграции, когда база лежит в обоих: молча выбрать один означает с
вероятностью 1/2 бэкапить труп, а порог MIN_DB_DUMP_BYTES протухший дамп
не поймает — он нормального размера.

ops/split-infra-postgres.sh — перенос: dry-run по умолчанию, снимок числа
строк после останова писателей, восстановление целевой ролью (суперюзер
забрал бы таблицы себе и выдал permission denied уже после переключения),
сверка построчных карт из pg_class. Ревью нашло два сценария бесшумной
потери, оба закрыты: писатель с несовпавшим именем больше не пропускается
молча (имя контейнера Forgejo — догадка, его compose вне репозитория), а
--force-restore отказывается работать, если переключение уже сделано.
Дампы под umask 077 и chmod 600: в дампе forgejo хеши паролей и токены.

Проверено на живом Docker, не по YAML: матрица профилей через compose
config, healthcheck исполнен в postgres:16-alpine (обе базы → 0, после DROP
одной → 1), bootstrap реально завёл роли и базы, пароль со спецсимволами
логинится, в docker logs его нет.

Refs #3061, #3057, #3075, #2989, #2203
2026-08-24 19:28:59 +03:00