# Развёртывание Клонируем репозиторий и поднимаем контур Compose-ом. Контуры `test` и `prod` разделяются именем проекта (`-p`) и файлом окружения (`--env-file`) — у каждого свои БД и volume'ы, на одной машине не пересекаются. ## 1. Клонировать ```bash git clone ssh://git@: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). ## 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=...)`), аналитика и рассылки — в нём же. Проверка контура (сервисы, миграции, 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=...`). ## Бэкап событий (забирает домашний сервер) Сырые события живут на VPS ограниченное время: раз в сутки домашний сервер **сам забирает** вчерашнюю партицию (`pull`), складывает её в `Parquet.gz`, импортирует в свой ClickHouse и сверяет количество строк — **только после сверки** на VPS удаляются партиции старше `BACKUP_GRACE_DAYS` (по умолчанию 7). На VPS остаются агрегаты (`events_daily`, `money_daily`). Входящий SSH на домашний сервер не нужен: он инициирует соединение сам. Разовая настройка: ```bash # на домашнем сервере git clone ssh://git@: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` делает дедуп, но при загрузке поверх миграций дедуп — вручную).