textmachine/platform/deploy/README.md

90 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Развёртывание платформы
Одна VM, systemd, бинари артефактами CI (`PLATFORM_DIRECTION.md` §3). Не Kubernetes: дети-`tmctl`
живут часами и держат эксклюзивный лок на файлах книги на локальном диске — оркестратор, способный
переселить под посреди прогона, этой нагрузке враждебен.
## Файлы
- `tmplatformd.service` — юнит контрольной панели. Тело юнита проверено `systemd-analyze verify`
(systemd 259) — exit 0, без замечаний. ⚠ Проверять надо с ПОДСТАВЛЕННЫМ существующим `ExecStart=`:
дословно юнит даёт exit 1, потому что `verify` проверяет и наличие бинаря, а `/usr/local/bin/tmplatformd`
на стенде нет. ⚠ **юнит целиком под systemd не запускался** — нет sudo и нет бинаря на стенде.
Отдельные свойства песочницы при этом проверены ЖИВЫМ прогоном в пользовательском systemd 259
(`systemd-run --user --wait`), а не вычитаны из доки:
`ProtectSystem=strict` + `ReadWritePaths=` на несуществующем пути → **`226/NAMESPACE`, юнит не
стартует**; тот же путь созданным → `0/SUCCESS`; префикс `-` на несуществующем → `0/SUCCESS`
(строка игнорируется — потому мы её и не префиксуем);
`ProtectHome=yes``/home` пуст, чтение `/home/<user>` даёт `Permission denied`;
`ProtectHome=tmpfs` + `BindPaths=<каталог>` → каталог виден. Ресурсные потолки
(`MemoryMax=80%`, `OOMPolicy=continue`) живьём не проверялись — вывод из
`systemd.resource-control(5)`/`systemd.service(5)`.
## Откат релиза: не ниже версии 5
`goose down` до версии 4 и ниже НЕ РАБОТАЕТ на живой базе: down-путь `00005` восстанавливает
`users_email_key` и `email NOT NULL`, а обе формы нарушают строки, которые пишет боевой код
(неподтверждённая личность даёт `email = NULL`; один адрес законно принадлежит двум аккаунтам).
Откат транзакционный, поэтому падение ничего не портит — но планировать откат ниже 5 нельзя,
план отката — накатить вперёд. Разбор: `docs/STACK_DECISIONS.md` §8.
## Что юнит закрывает содержательно
- **PD-13 (осиротевшие процессы движка).** Каждый `tmctl` живёт в cgroup ЭТОГО юнита, поэтому падение
или рестарт платформы не оставляет прогон без присмотра. Обычную остановку делает супервизор
(группа процессов, `internal/ingest/procgroup_unix.go`); cgroup — это ответ на случай, когда
супервизора уже нет, чтобы попросить.
- **`TimeoutStopSec=90`** больше, чем дренаж платформы (15 с) плюс grace движка (30 с). Меньше —
и systemd прибьёт `tmctl` посреди остановки, оставив лок проекта.
- **Секреты через `LoadCredential=`,** а не через окружение: переменная окружения видна в
`/proc/<pid>/environ` и наследуется каждым ребёнком-`tmctl`. Конфиг читает `*_FILE` первым.
## Установка (набросок, исполняется владельцем)
```sh
useradd --system --home-dir /srv/textmachine tmplatform
# ⚠ Каталог создаём ЯВНО: --system не создаёт домашний каталог, а `ReadWritePaths=/srv/textmachine`
# при `ProtectSystem=strict` на несуществующем пути валит сборку mount-namespace — юнит не стартует
# вовсе (PD-91, systemd.exec(5)). Это первая команда, которую пропускают, читая набросок сверху вниз.
install -d -m0750 -o tmplatform -g tmplatform /srv/textmachine
install -D -m0755 tmplatformd /usr/local/bin/tmplatformd
install -D -m0755 tmplatformctl /usr/local/bin/tmplatformctl
install -d -m0700 -o root -g root /etc/tmplatform
printf '%s' 'postgres://...' > /etc/tmplatform/dsn && chmod 0400 /etc/tmplatform/dsn
printf '%s' '<oauth client secret>' > /etc/tmplatform/oidc_client_secret && chmod 0400 /etc/tmplatform/oidc_client_secret
```
`/etc/tmplatform/env` — несекретное окружение:
```
TM_PLATFORM_ADDR=127.0.0.1:8080
TM_PLATFORM_TRUSTED_ORIGINS=https://app.example.org
TM_PLATFORM_OIDC_ISSUER=https://accounts.google.com
TM_PLATFORM_OIDC_CLIENT_ID=...
TM_PLATFORM_OIDC_REDIRECT_URL=https://app.example.org/auth/callback
TM_PLATFORM_AFTER_LOGIN=/library
TM_PLATFORM_SIGNUP_GRANT_USD=5
```
Миграции выкатываются ОДИН раз, не каждой репликой: `TM_PLATFORM_MIGRATE=1 tmplatformd` разово
либо отдельный шаг деплоя. `goose` держит advisory-лок, так что параллельный запуск не гонка,
но и не норма.
## Где на сервере лежат книги
`/srv/textmachine` — корень библиотеки НА СЕРВЕРЕ. Решение владельца «книги живут в `~/books`»
относится к машине разработки: под этим юнитом домашние каталоги недоступны вовсе
(`ProtectHome=yes` подставляет пустой `/home` и детям-`tmctl` тоже), поэтому библиотека под
домашним каталогом на сервере просто не откроется — не «сработает медленнее», а не найдётся.
Оператору, которому это нужно, юнит называет ровно две строки замены (`ProtectHome=tmpfs` +
`BindPaths=`); других изменений не требуется.
⚠ Выбирающего путь кода ещё нет: `Supervisor.Workdir` задаёт вызывающий, а вызывающий — воркер,
которого нет (строка 103 единого бэклога). Когда он появится, корень становится настройкой, и её
дефолт — этот каталог.
## Чего здесь ещё нет
TLS и домен (перед юнитом предполагается edge-прокси), ограничитель соединений на edge,
ротация логов, бэкап Postgres. Всё это — работа с первым реальным деплоем, не раньше.