184 lines
9.4 KiB
Markdown
184 lines
9.4 KiB
Markdown
# Развёртывание
|
||
|
||
Клонируем репозиторий и поднимаем контур Compose-ом. Контуры `test` и `prod`
|
||
разделяются именем проекта (`-p`) и файлом окружения (`--env-file`) — у каждого
|
||
свои БД и volume'ы, на одной машине не пересекаются.
|
||
|
||
## 1. Клонировать
|
||
|
||
```bash
|
||
git clone ssh://git@<gitea-host>:2222/mpakobecex/DispelEvilBot.git
|
||
cd DispelEvilBot
|
||
```
|
||
|
||
## 2. Подготовить окружение
|
||
|
||
```bash
|
||
cp env/test.env.example env/test.env
|
||
# заполнить: BOT_TOKEN, DB_PASSWORD, CHAT_ID (основной чат), ALERT_CHAT_ID (опц.),
|
||
# ADMIN_IDS (опц.), CLICKHOUSE_PASSWORD (аналитика событий)
|
||
```
|
||
|
||
Порт ClickHouse на хосте (`CLICKHOUSE_HTTP_PORT`) у контуров должен различаться:
|
||
`prod` — `8123`, `test` — `8124` (иначе контейнеры конфликтуют на одной VPS).
|
||
Порт админки (`ADMIN_HTTP_PORT`) — так же: `prod` — `8000`, `test` — `8001`.
|
||
|
||
## 3. Логин в registry (если пакет приватный)
|
||
|
||
```bash
|
||
docker login git.mpakosrv.ru -u mpakobecex -p <ТОКЕН с read:package>
|
||
```
|
||
|
||
Если пакет сделать публичным — логин не нужен.
|
||
|
||
## 4. Запуск
|
||
|
||
```bash
|
||
# тестовый контур
|
||
docker compose -p test --env-file env/test.env -f docker-compose.prod.yml up -d
|
||
|
||
# прод (когда понадобится)
|
||
cp env/prod.env.example env/prod.env
|
||
docker compose -p prod --env-file env/prod.env -f docker-compose.prod.yml up -d
|
||
```
|
||
|
||
Логи:
|
||
```bash
|
||
docker compose -p test --env-file env/test.env -f docker-compose.prod.yml logs -f
|
||
```
|
||
|
||
## Что происходит при старте
|
||
|
||
1. `postgres` поднимается и проходит healthcheck;
|
||
2. `migrate` (**Flyway**) накатывает миграции из `sql/` — для пустой БД с нуля;
|
||
3. `clickhouse` поднимается и применяет `clickhouse/init/001_events.sql` —
|
||
**только при первой инициализации** пустого data-каталога;
|
||
4. `bot` стартует (`Запуск DispelEvilBot v<версия> (APP_ENV=...)`), аналитика и рассылки — в нём же;
|
||
5. `admin` стартует и отвечает на `GET /healthz` (порт на loopback хоста).
|
||
|
||
Проверка контура (сервисы, миграции, Postgres, ClickHouse):
|
||
|
||
```bash
|
||
make check E=test
|
||
```
|
||
|
||
## ClickHouse (аналитика событий)
|
||
|
||
События всех действий бота пишутся в `analytics.events` (контракт — [`docs/events.md`](docs/events.md)).
|
||
ClickHouse наружу **не публикуется**: только loopback хоста (`127.0.0.1:${CLICKHOUSE_HTTP_PORT}`).
|
||
|
||
```bash
|
||
make ch E=test # clickhouse-client контура
|
||
# пример: события за сегодня по типам
|
||
docker compose -p test --env-file env/test.env -f docker-compose.prod.yml exec -T clickhouse \
|
||
sh -lc 'clickhouse-client --user "$CLICKHOUSE_USER" --password "$CLICKHOUSE_PASSWORD" \
|
||
--query "SELECT event_type, count() FROM analytics.events WHERE toDate(event_time) = today() GROUP BY event_type"'
|
||
```
|
||
|
||
Если ClickHouse недоступен, бот продолжает работать: события уходят в stdout (WARNING),
|
||
полностью выключить можно флагом `CLICKHOUSE_ENABLED=false`.
|
||
|
||
Изменения схемы: `clickhouse/init/*.sql` применяются лишь на пустом data-каталоге,
|
||
поэтому на существующем контуре DDL нужно применить вручную (`make ch E=...`).
|
||
|
||
## Админка (FastAPI)
|
||
|
||
Сервис `admin` — отдельный образ `mpakobecex/dispelevilbot-admin`, общий пакет `common`.
|
||
Наружу пока **не публикуется**: только loopback хоста (`127.0.0.1:${ADMIN_HTTP_PORT}`).
|
||
Домен и TLS появятся вместе с входом через Telegram (Блоки 2.4/4.2).
|
||
|
||
```bash
|
||
# проверка живости
|
||
curl -s http://127.0.0.1:8001/healthz # test
|
||
curl -s http://127.0.0.1:8000/healthz # prod
|
||
```
|
||
|
||
Локально без Docker: `pip install -r requirements-admin.txt && python -m admin`
|
||
(по умолчанию `0.0.0.0:8000`, переопределяется `ADMIN_HOST`/`ADMIN_PORT`).
|
||
|
||
## Бэкап событий (забирает домашний сервер)
|
||
|
||
Сырые события живут на VPS ограниченное время: раз в сутки домашний сервер **сам забирает**
|
||
вчерашнюю партицию (`pull`), складывает её в `Parquet.gz`, импортирует в свой ClickHouse и
|
||
сверяет количество строк — **только после сверки** на VPS удаляются партиции старше
|
||
`BACKUP_GRACE_DAYS` (по умолчанию 7). На VPS остаются агрегаты (`events_daily`, `money_daily`).
|
||
|
||
Входящий SSH на домашний сервер не нужен: он инициирует соединение сам.
|
||
|
||
Разовая настройка:
|
||
|
||
```bash
|
||
# на домашнем сервере
|
||
git clone ssh://git@<gitea-host>:2222/mpakobecex/DispelEvilBot.git
|
||
cd DispelEvilBot
|
||
cp env/backup.env.example env/backup.env # VPS_SSH, VPS_PORT, VPS_PROJECT_DIR, VPS_SSH_KEY, BACKUP_DIR, CLICKHOUSE_*
|
||
```
|
||
|
||
Требования: на VPS — пользователь с доступом к `docker` и каталог с репозиторием
|
||
(`VPS_PROJECT_DIR`, там запускается `docker compose`); на домашнем сервере — `clickhouse-client`
|
||
и локальный ClickHouse. Настройка SSH-доступа — `deploy/ssh-access.md`.
|
||
|
||
Если ставить `clickhouse-client` на хост не хочется, укажите в `env/backup.env` переменную
|
||
`CLICKHOUSE_CLIENT` — путь к обёртке, которая выполняет клиент внутри контейнера:
|
||
|
||
```bash
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
cd "$(dirname "$0")/.."
|
||
exec docker compose --env-file env/backup.env -f docker-compose.yml exec -T clickhouse clickhouse-client "$@"
|
||
```
|
||
|
||
Проверочный прогон (без cron): `make backup E=test` или `./scripts/clickhouse_backup.sh test`.
|
||
|
||
Cron на домашнем сервере (вчерашний день уже закрыт, время московское):
|
||
|
||
```cron
|
||
0 4 * * * cd /srv/DispelEvilBot && ./scripts/clickhouse_backup.sh test >> /var/log/clickhouse-backup-test.log 2>&1
|
||
```
|
||
|
||
Ошибка на любом шаге оставляет данные на VPS (партиции не удаляются) и пишет понятный лог.
|
||
Импорт дня идемпотентен: повторный прогон не дублирует строки.
|
||
|
||
Если контур на VPS не запущен (нет работающего `clickhouse` или не найден каталог проекта),
|
||
скрипт пишет об этом в лог и завершается с кодом 0 — для cron это не ошибка.
|
||
|
||
## Обновление и откат
|
||
|
||
```bash
|
||
# обновление: поменять IMAGE_TAG в env/<контур>.env, затем
|
||
docker compose -p <контур> --env-file env/<контур>.env -f docker-compose.prod.yml pull
|
||
docker compose -p <контур> --env-file env/<контур>.env -f docker-compose.prod.yml up -d
|
||
```
|
||
|
||
Откат — вернуть предыдущий `IMAGE_TAG` (например, commit-sha) и повторить.
|
||
|
||
## Контуры
|
||
|
||
| Контур | env-файл | БД | APP_ENV | Бот |
|
||
| --- | --- | --- | --- | --- |
|
||
| test | `env/test.env` | `dispel_evil_test` | `dev` | тестовый |
|
||
| prod | `env/prod.env` | `dispel_evil` | `prod` | боевой |
|
||
|
||
## Переменные окружения
|
||
|
||
См. `env/prod.env.example` / `env/test.env.example` (контуры) и `env/backup.env.example` (бэкап событий).
|
||
|
||
## Дашборд (позже)
|
||
|
||
Superset поднимается на домашнем сервере и читает **локальный** ClickHouse с полной
|
||
историей событий (сюда ежедневно приезжают архивы). Отдельный read-only пользователь
|
||
ClickHouse и сам дашборд — финальный этап, в этот контур не входят.
|
||
|
||
## Перенос данных на прод (позже, короткое окно простоя)
|
||
|
||
1. Остановить старого бота.
|
||
2. `pg_dump -Fc -f dump.pgc <старая_бд>`.
|
||
3. Поднять прод-контур (миграции создадут чистую схему).
|
||
4. Загрузить данные: `pg_restore --data-only --disable-triggers -d dispel_evil dump.pgc`.
|
||
5. Сверить: число пользователей, `SUM(money.amount)`, число сообщений.
|
||
6. Переключить бота, проверить команды.
|
||
|
||
Бэкап старой БД обязателен. Дубли в `tg_users`/`de_users`/`unsubscribe` при загрузке
|
||
нужно устранить до создания PK (миграция `V12` делает дедуп, но при загрузке поверх
|
||
миграций дедуп — вручную).
|