Перейти к содержанию
Панель

Деплой

Система развёрнута по split-topology: удалённый сервер (данные + веб) и локальный сервер (воркеры + Telegram). Единый скрипт deploy.sh управляет деплоем на оба сервера.

Серверы

Сервер IP Сервисы Код
Удалённый 2.59.170.200 nginx, api, db, redis /opt/chat_bot/
Локальный -- dialog-orchestrator, admin-bot, celery-*, emulator/embedding workers рабочая директория
graph LR
    subgraph "Remote (fin-boost.com)"
        NGINX[nginx :443] --> API[api :8000]
        API --> DB[PostgreSQL :5432]
        API --> REDIS[Redis :6379]
    end

    subgraph "Local"
        ORCH[dialog-orchestrator]
        ADMIN[admin-bot]
        CELERY[celery workers]
    end

    ORCH -->|"5434 → 5432"| DB
    ORCH -->|"6381 → 6379"| REDIS

Домен и SSL

Параметр Значение
Домен fin-boost.com + www.fin-boost.com
DNS A @ --> 2.59.170.200, CNAME www --> fin-boost.com
SSL Let's Encrypt (certbot + nginx plugin)
Сертификат /etc/letsencrypt/live/fin-boost.com/
Nginx 443 --> 127.0.0.1:8000, HTTP --> HTTPS redirect

deploy.sh -- единая точка деплоя

./scripts/deploy.sh                          # Всё (local + remote)
./scripts/deploy.sh api                      # Только remote API (full rebuild)
./scripts/deploy.sh web                      # Только фронтенд (~15 сек)
./scripts/deploy.sh dialog-orchestrator      # Только local orchestrator
./scripts/deploy.sh dialog-orchestrator api  # Оба сервера

Full API Deploy

./scripts/deploy.sh api выполняет полный цикл:

flowchart TD
    A[git diff --quiet HEAD] -->|clean| B[rsync кода на remote]
    A -->|dirty| A1{DEPLOY_ALLOW_DIRTY=1?}
    A1 -->|нет| FAIL[Деплой отменён]
    A1 -->|да| B
    B --> C[pg_dump backup]
    C --> D["docker compose build<br>(BUILD_COMMIT baked in)"]
    D --> E[alembic upgrade head]
    E --> F["docker compose up -d"]
    F --> G[nginx reload]
    G --> H[Health check]
  1. Dirty Worktree Guard -- remote deploys блокируются при uncommitted файлах. Override: DEPLOY_ALLOW_DIRTY=1
  2. rsync кода на /opt/chat_bot/ (excludes: .git, __pycache__, .venv, sessions/, logs/, memories/, datasets/, .env, node_modules)
  3. Pre-migration backup -- pg_dump | gzip > /tmp/pre_deploy_{commit}_{ts}.sql.gz. Failure = non-fatal WARN
  4. Docker build -- BUILDKIT_PROGRESS=plain, BUILD_COMMIT (git short SHA) --> Docker ARG --> GIT_COMMIT env
  5. Миграции -- alembic upgrade head
  6. Запуск -- docker compose up -d + nginx reload + health check

BUILD_COMMIT

Все сервисы регистрируют commit в Redis. /api/health/ready проверяет consistency -- несовпадение версий = warning.

Frontend-only Deploy (быстрый)

./scripts/deploy.sh web -- только фронтенд (~15 сек вместо ~3 мин):

  1. npm ci + vite build локально
  2. rsync web/dist/ на удалённый сервер
  3. docker compose restart api

Работает благодаря volume mount ./web/dist:/app/web/dist:ro -- контейнер читает SPA-файлы с хоста.

Backend-only Deploy

Для изменений только в Python-коде (без frontend rebuild):

rsync -az --delete \
  --exclude='.git' --exclude='__pycache__' --exclude='web/' \
  ./ root@2.59.170.200:/opt/chat_bot/

ssh root@2.59.170.200 \
  "cd /opt/chat_bot && BUILD_COMMIT=\$(git rev-parse --short HEAD) \
   docker compose up -d --build api"

Volume Mounts (удалённый сервер)

API-контейнер использует volume mounts для файлов, обновляемых без rebuild:

Volume Назначение
./logs:/app/logs Централизованные логи
./web/dist:/app/web/dist:ro SPA -- обновляется через rsync
./memories:/app/memories Персональная память клиентов
./.env:/app/.env:ro Конфигурация

Локальный деплой

Локальные сервисы подключаются к удалённой БД и Redis через mapped порты:

DATABASE_URL=postgresql+asyncpg://postgres:postgres@2.59.170.200:5434/debt_collector
REDIS_URL=redis://2.59.170.200:6381/0
CELERY_BROKER_URL=redis://2.59.170.200:6381/1

Два .env файла

Remote .env: внутренние Docker-адреса (redis:6379, db:5432). Local .env: внешние mapped порты (2.59.170.200:6381, 2.59.170.200:5434).

Деплой локальных сервисов:

BUILD_COMMIT=$(git rev-parse --short HEAD) docker compose up -d --build dialog-orchestrator
docker compose up -d --build admin-bot celery-worker celery-worker-warming celery-beat

Firewall (удалённый сервер)

Порт Доступ
80/443 Публичный (nginx)
5432 Только IP локального сервера
6379 Только IP локального сервера
8000 Только localhost (nginx proxy)

GPU

GPU deploy-секции убраны из базового docker-compose.yml (remote сервер без GPU). На локальном сервере GPU подключается через docker-compose.override.yml (gitignored, не попадает в rsync).

Operator Suggestions (split-topology)

Remote API не имеет Claude CLI/SDK. Для AI suggestions:

  1. API пытает вызвать AI --> fallback
  2. Диспатчит generate_operator_suggestions Celery task на локальный воркер
  3. Возвращает source: "fallback_pending" (30s cache)
  4. Локальный celery-worker генерирует AI suggestions
  5. Записывает результат в Redis (600s cache)
  6. Следующий poll фронтенда подхватывает AI-результат

Логи

./scripts/logs.sh                      # Все сервисы (local + remote merged)
./scripts/logs.sh api                  # Только remote API
./scripts/logs.sh dialog-orchestrator  # Только local
./scripts/logs.sh -n 50               # Последние 50 строк

Post-Deploy Checks

# Remote
curl -s https://fin-boost.com/api/health/live
ssh root@2.59.170.200 "docker ps"

# Local
docker compose ps

# Автоматическая проверка
python scripts/post_deploy_check.py            # Полная проверка
python scripts/post_deploy_check.py --local    # Только локальные
python scripts/post_deploy_check.py --quiet    # Console-only

Типичные проблемы

Проблема Причина Решение
Фронт не обновился Кеш Docker layer Убедиться что rsync прошёл до docker compose up --build
401 на всех API-запросах Контейнер пересоздан, сессии в Redis Перелогиниться
Migration failure Ошибка при alembic upgrade Восстановить из backup: /tmp/pre_deploy_*.sql.gz
Dirty worktree Uncommitted файлы git add && git commit или DEPLOY_ALLOW_DIRTY=1
Stale Celery code docker compose restart не пересобирает Использовать up -d --build или deploy.sh