Files
new_lottery_bot/docs/DRONE_DEPLOYMENT.md
Trevor1985 d5a9c13b68
All checks were successful
continuous-integration/drone/push Build is passing
Recover stalled database connections and skip unreachable chat recipients
2026-09-13 20:21:20 +09:00

11 KiB
Raw Blame History

Автодеплой через 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 создания и обновления секретов. Скрипт передаёт pull_request=false, повторно проверяет наличие имён и не печатает значения. Учётной записи нужны права записи в репозиторий.

На Windows, из корня проекта, после заполнения файлов за пределами репозитория:

.\.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-версию сервера.

Перед первым деплоем

  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, затем ещё 120 секунд проверяет heartbeat и отсутствие перезапусков. Только после этого переключает current и записывает last-build.
  • При ошибке после остановки пытается вернуть прежний образ. Это откат приложения: схема БД автоматически не откатывается; используется env текущего deployment. Восстановление БД из backup требует отдельного решения. При первом запуске предыдущего образа может не быть.

Heartbeat обновляется после проверки БД в работающем event loop; до запуска бот проверяет Redis, схему и Telegram getMe. Отдельный watchdog-поток завершает процесс при устаревшем heartbeat, даже если завис драйвер или event loop; после этого действует Docker restart policy. На рабочем сетевом маршруте длительное повторное использование соединений зависало: в lottery_env установлен DB_POOL_RECYCLE=15, сохраняющий ограниченный пул с коротким сроком жизни соединения. Один только начальный Docker healthcheck не является проверкой длительной работы или доставки всех сообщений.

Проверка результата

После успешного шага deploy проверить /start, админку, /cashier со второго Telegram-аккаунта, добавление участника и тестовый розыгрыш. В логах должны отсутствовать ошибки миграций, Conflict: terminated by other getUpdates request и повторяющиеся ошибки соединения с БД. Проверить сохранение FSM после штатного рестарта, содержимое backup и возможность восстановления на отдельной тестовой БД.

Локальные команды CI:

.\.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 не указан.