7.2 KiB
Развёртывание платформы
Одна 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первым.
Установка (набросок, исполняется владельцем)
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. Всё это — работа с первым реальным деплоем, не раньше.