Stabilize staff concurrency and premium emoji; enable verified Drone deployment
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
75
docs/DRONE_DEPLOYMENT.md
Normal file
75
docs/DRONE_DEPLOYMENT.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Автодеплой через Drone
|
||||
|
||||
Drone: `https://drone.smartsoltech.kr`, цель: `trevor@192.168.40.112:/opt/new_lottery_bot`, репозиторий `trevor/new_lottery_bot`, production-ветка `master`.
|
||||
Подготовленный pipeline запускает деплой только для успешного `push` в `master` после проверок, PostgreSQL-тестов и сборки архива. Pull request запускает проверки без передачи deployment-секретов.
|
||||
|
||||
## Секреты репозитория
|
||||
|
||||
| Имя в Drone | Значение |
|
||||
| --- | --- |
|
||||
| `lottery_deploy_user` | SSH-пользователь сервера с доступом к Docker и каталогу приложения |
|
||||
| `lottery_deploy_path` | Отдельный абсолютный каталог, например `/opt/new_lottery_bot` |
|
||||
| `lottery_deploy_ssh_key` | Закрытый SSH-ключ этого пользователя, пригодный для неинтерактивного входа |
|
||||
| `lottery_deploy_known_hosts` | Проверенная запись ключа сервера для `192.168.40.112` |
|
||||
| `lottery_env` | Полный актуальный production env-файл с BOT_TOKEN, DATABASE_URL, ADMIN_IDS и остальными настройками |
|
||||
|
||||
Настройка использует [официальный API создания](https://docs.drone.io/api/secrets/secret_create/) и [обновления секретов](https://docs.drone.io/api/secrets/secret_update/). Скрипт передаёт `pull_request=false`, повторно проверяет наличие имён и не печатает значения. Учётной записи нужны права записи в репозиторий.
|
||||
|
||||
На Windows, из корня проекта, после заполнения файлов за пределами репозитория:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe scripts/configure_drone_secrets.py `
|
||||
--server https://drone.smartsoltech.kr `
|
||||
--repo trevor/new_lottery_bot `
|
||||
--token-file C:\secure\drone-token.txt `
|
||||
--ssh-key C:\secure\lottery-deploy-key `
|
||||
--known-hosts C:\secure\lottery-known-hosts `
|
||||
--env-file C:\secure\lottery-production.env `
|
||||
--deploy-user trevor `
|
||||
--deploy-path /opt/new_lottery_bot
|
||||
```
|
||||
|
||||
Пути `C:\secure\...` — примеры файлов с ограниченными правами доступа. Токены не нужно вставлять в командную строку. Отпечаток host key сверяется через доверенный доступ к серверу; автоматическое принятие неизвестного ключа отключено. Для Drone используется отдельный ключ `id_ed25519_lottery_deploy`; пользователь `trevor` имеет доступ к Docker и каталогу приложения.
|
||||
|
||||
При подготовке deployment актуальные настройки взяты из работающего контейнера: PostgreSQL 16 расположен на `192.168.20.2`, база `lottery_bot`. Локальный старый `.env.prod` не является источником production-настроек. Проверено совпадение эффективных BOT_TOKEN, DATABASE_URL, REDIS_URL, ADMIN_IDS и имён volumes с действующим Compose-проектом `new_lottery_bot`. Все пять секретов созданы в Drone с запретом передачи pull request.
|
||||
|
||||
Резервная копия рабочей БД восстановлена в изолированном PostgreSQL 16; обновление с `20260701_perf_indexes` до `20260913_staff_concurrency` и проверка схемы прошли. При обновлении PostgreSQL согласованно обновлять клиент резервного копирования: [PostgreSQL не гарантирует восстановление дампа нового клиента в более старую major-версию сервера](https://www.postgresql.org/docs/17/app-pgdump.html#APP-PGDUMP-NOTES).
|
||||
|
||||
## Перед первым деплоем
|
||||
|
||||
1. Активировать репозиторий в Drone. Runner должен получать Git-репозиторий и обращаться по SSH к `192.168.40.112`; сервер должен иметь доступ к registry/PyPI для сборки.
|
||||
2. На сервере нужны Docker Engine, Compose v2 с поддержкой `--wait`, `flock`, `tar`, `install`. Пользователь должен иметь доступ к Docker и выделенному каталогу. Подготовить ключ и проверить обычный неинтерактивный SSH-вход.
|
||||
3. Если уже существует контейнер `lottery_bot`, проверить его label `com.docker.compose.project`. Скрипт ожидает `new_lottery_bot` и остановится при другом проекте, чтобы не подменить чужой стек. Существующие volumes, каталог и внешний PostgreSQL необходимо сопоставить до переноса. Не запускать `down -v`.
|
||||
4. В `.env.prod` использовать реальные настройки из `.env.prod.example`. Для внешней БД оставить `COMPOSE_PROFILES` пустым и указать доступный из контейнера PostgreSQL в `DATABASE_URL`; POSTGRES_PASSWORD не требуется. Для БД в этом Compose задать `COMPOSE_PROFILES=local-db`, непустой POSTGRES_PASSWORD, согласованные POSTGRES_* и адрес `postgres` в URL. Спецсимволы пароля внутри URL должны быть URL-encoded. Клиент резервного копирования и PostgreSQL в Compose/CI используют major-версию 16, соответствующую рабочей БД.
|
||||
5. При использовании переменных со знаком `$` учитывать интерполяцию Compose env-файла; заключать соответствующее значение в одинарные кавычки. Проверять конфигурацию командой `docker compose --project-name new_lottery_bot --env-file .env.prod config --quiet`, чтобы значения секретов не попадали в вывод.
|
||||
6. Проверить доступ к целевой БД и возможность `pg_dump`. БД должна уже существовать. Пользователю миграций нужны права изменения принадлежащих приложению объектов. Исторические дубликаты миграция сообщает без удаления данных.
|
||||
7. Загрузить пять секретов указанным скриптом, опубликовать изменения в `master` и дождаться завершения **всего** pipeline, включая `deploy`.
|
||||
|
||||
## Последовательность deployment-скрипта
|
||||
|
||||
- Получает архив и env-файл по SSH с обязательной проверкой host key.
|
||||
- Берёт файловую блокировку деплоя и отклоняет устаревший номер сборки.
|
||||
- Создаёт каталог `releases/COMMIT-BUILD`, собирает образ с тегом commit и поднимает Redis/необходимую локальную БД.
|
||||
- Делает PostgreSQL backup в `backups/COMMIT-BUILD-UTC_TIMESTAMP.dump` с ограниченными правами. Дальнейшие действия прекращаются, если backup не получен.
|
||||
- Останавливает старого polling-бота, выполняет `alembic upgrade head` и проверку схемы.
|
||||
- Запускает новый образ, ожидает healthcheck, проверяет heartbeat приложения и только затем переключает `current` и записывает `last-build`.
|
||||
- При ошибке после остановки пытается вернуть прежний образ. **Это откат приложения:** схема БД автоматически не откатывается; используется env текущего deployment. Восстановление БД из backup требует отдельного решения. При первом запуске предыдущего образа может не быть.
|
||||
|
||||
Heartbeat обновляется после проверки БД в работающем event loop; до запуска бот проверяет Redis, схему и Telegram `getMe`. Сбой heartbeat останавливает приложение, после чего действует Docker restart policy. Один только Docker healthcheck не является проверкой каждого бизнес-сценария или факта доставки всех сообщений.
|
||||
|
||||
## Проверка результата
|
||||
|
||||
После успешного шага `deploy` проверить `/start`, админку, `/cashier` со второго Telegram-аккаунта, добавление участника и тестовый розыгрыш. В логах должны отсутствовать ошибки миграций, `Conflict: terminated by other getUpdates request` и повторяющиеся ошибки соединения с БД. Проверить сохранение FSM после штатного рестарта, содержимое backup и возможность восстановления на отдельной тестовой БД.
|
||||
|
||||
Локальные команды CI:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
|
||||
.\.venv\Scripts\python.exe -m ruff check src main.py scripts tests migrations
|
||||
.\.venv\Scripts\python.exe -m pytest -q
|
||||
.\.venv\Scripts\python.exe -m pip_audit -r requirements.txt
|
||||
.\.venv\Scripts\python.exe scripts/check_secrets.py
|
||||
.\.venv\Scripts\python.exe scripts/build_release.py
|
||||
```
|
||||
|
||||
Для PostgreSQL-тестов задаётся `TEST_DATABASE_URL` **только отдельной одноразовой тестовой БД**: тесты удаляют и создают в ней таблицы. Пользователю тестов также требуется `CREATEDB` для проверки миграций. Рабочий `DATABASE_URL` тестами не используется: `tests/conftest.py` подставляет временную SQLite БД, если `TEST_DATABASE_URL` не указан.
|
||||
Reference in New Issue
Block a user