diff --git a/.forgejo/workflows/deploy-tradein.yml b/.forgejo/workflows/deploy-tradein.yml index f9980961..90b98b1a 100644 --- a/.forgejo/workflows/deploy-tradein.yml +++ b/.forgejo/workflows/deploy-tradein.yml @@ -828,8 +828,47 @@ jobs: # Re-login to GHCR (PAT может быть rotated) echo "$GHCR_PAT" | docker login ghcr.io -u lekss361 --password-stdin + # ── Набор compose-файлов (#3059) ────────────────────────────────── + # docker-compose.selectel.yml закрепляет рабочий IP api.telegram.org + # через extra_hosts у backend и tgbot. Файл существовал с 23.08, но НИ + # ОДИН вызов ниже его не подключал — то есть первый же деплой на новом + # хосте поднял бы МЕРУ без закрепления, и бот с пересылкой алертов + # умерли бы молча: у api.telegram.org семь адресов, а с Selectel + # отвечает РОВНО ОДИН (149.154.167.220), и штатный резолвер отдаёт + # мёртвый. + # + # Подключается БЕЗУСЛОВНО, на обоих хостах. Замер 25.08 с Beget: + # 149.154.167.220 -> 302 за 0.18 с + # реальный Bot API /getMe -> {"ok":false,"error_code":401} — то есть + # отвечает именно Telegram, а не заглушка + # Условная логика «оверрайд только на Selectel» была бы лишней машинерией + # ради хоста, который через переезд перестанет быть продовым. + # + # NB: файл — оверрайд стека МЕРЫ (проект gendesign-tradein). Подмешивать + # его к стеку ПТИЦЫ нельзя: там нет сервиса tgbot, и compose отвергает + # весь проект ("has neither an image nor a build context"), а сервис + # backend есть в обоих — закрепление молча легло бы на бэкенд Птицы. + COMPOSE_FILES="-f docker-compose.prod.yml" + if [ -f docker-compose.selectel.yml ]; then + COMPOSE_FILES="$COMPOSE_FILES -f docker-compose.selectel.yml" + echo "→ compose-оверрайд: docker-compose.selectel.yml подключён (пин api.telegram.org)" + else + # ПАДАЕМ, а не предупреждаем. Файл git-tracked, а шагом выше сделан + # `git reset --hard origin/main` — значит его отсутствие означает не + # штатный сценарий, а поломку (удалили/переименовали, не поправив + # это место). Предупреждение в зелёном логе здесь было бы ровно тем + # классом тихого отказа, от которого защищает сама правка: деплой + # «успешен», а бот и пересылка алертов мертвы. Тот же принцип, что у + # health-check'ов #2214 ниже по файлу. + echo "ERROR: docker-compose.selectel.yml не найден в $(pwd)." + echo "ERROR: без него api.telegram.org не закреплён → tgbot и пересылка" + echo "ERROR: алертов умрут МОЛЧА (с Selectel отвечает 1 адрес из 7)." + echo "ERROR: если файл убран намеренно — снять и эту проверку тем же PR." + exit 1 + fi + export IMAGE_TAG="$IMAGE_TAG" - docker compose -p gendesign-tradein -f docker-compose.prod.yml pull + docker compose -p gendesign-tradein $COMPOSE_FILES pull # ── Порядок деплоя (issue #2216): МИГРАЦИИ ДО НОВОГО app-кода ────────── # Раньше backend/frontend/scraper поднимались ПЕРЕД миграциями: при сбое @@ -842,7 +881,7 @@ jobs: # код на старой схеме». Откат = просто ничего не поднимали. # (1) Только БД — чтобы прогнать миграции до нового app-кода. - docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d --no-deps postgres + docker compose -p gendesign-tradein $COMPOSE_FILES up -d --no-deps postgres # (2) Ждём готовности postgres (pg_isready в цикле, НЕ тупой sleep). # @@ -1159,7 +1198,7 @@ jobs: echo "→ scraper checkpoint ts (DB clock): ${SCRAPER_STOP_TS:-unknown}" fi - docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d --no-deps $SERVICES + docker compose -p gendesign-tradein $COMPOSE_FILES up -d --no-deps $SERVICES if [ -n "$scraper_stale" ] && [ -n "${SCRAPER_STOP_TS:-}" ]; then echo "→ Startup-reap (#1951): помечаем orphaned running-строки, замороженные recreate'ом" diff --git a/tradein-mvp/docker-compose.selectel.yml b/tradein-mvp/docker-compose.selectel.yml index 466a143f..b50acc0c 100644 --- a/tradein-mvp/docker-compose.selectel.yml +++ b/tradein-mvp/docker-compose.selectel.yml @@ -1,22 +1,32 @@ -# Selectel-only override: закрепляет рабочий IP api.telegram.org для tgbot. +# Override: закрепляет рабочий IP api.telegram.org для tgbot и backend. # -# Применяется ТОЛЬКО на новом выделенном сервере (Selectel Poincare, -# 188.246.224.93, переезд 30.08.2026), поверх обычного prod-стека: +# ⚠️ ОБНОВЛЕНО 25.08 (#3059). Файл больше НЕ Selectel-only и подключается +# БЕЗУСЛОВНО — его подмешивает deploy-tradein.yml (переменная COMPOSE_FILES). +# Имя оставлено прежним, чтобы не ломать ссылки на него в раннбуке и задачах. # -# docker compose -p gendesign \ -# -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.selectel.yml up -d +# Что было не так: с 23.08 файл лежал в репозитории, но НИ ОДИН вызов compose в +# деплое его не подключал — везде было жёстко `-f docker-compose.prod.yml`. +# То есть первый же деплой на новом хосте поднял бы МЕРУ БЕЗ закрепления, и +# бот вместе с пересылкой алертов умерли бы молча. Написанный, но никем не +# подключённый оверрайд выглядит как решённая проблема, оставаясь нерешённой. # -# На Beget этот файл НЕ подключается — там резолвер api.telegram.org отдаёт -# один из рабочих адресов и закрепление не нужно (см. замер ниже). Отдельный -# override, а не правка docker-compose.prod.yml, потому что: -# 1. Это host-specific обход, а не общее свойство сервиса — размазывать его -# по общему prod-файлу значит менять поведение действующего прода -# (Beget) ради проблемы хоста, который ещё не в проде. -# 2. Нулевой риск для Beget: файл просто не передаётся в -f, никакого -# shared-состояния между хостами через этот механизм нет. -# 3. Если Selectel впоследствии станет единственным прод-хостом (после -# 30.08) и обход всё ещё нужен — тогда его можно будет слить в -# docker-compose.prod.yml осознанно, а не молча "заодно". +# Почему безусловно, а не только на Selectel (замер 25.08 С BEGET): +# 149.154.167.220 -> 302 за 0.18 с +# реальный Bot API /getMe -> {"ok":false,"error_code":401} +# то есть отвечает именно Telegram, а не заглушка +# Закрепляемый адрес живой и на старом хосте, поэтому условная логика «оверрайд +# только на новом» была бы лишней машинерией ради хоста, который после 30.08 +# перестанет быть продовым. Цена решения — на Beget пропадает запасной путь +# через резолвер (см. «ОДНА ТОЧКА ОТКАЗА» ниже); принято сознательно. +# +# ⚠️ Это оверрайд стека МЕРЫ (проект gendesign-tradein). Подмешивать его к стеку +# ПТИЦЫ НЕЛЬЗЯ: сервиса tgbot там нет, и compose отвергает весь проект — +# service "tgbot" has neither an image nor a build context specified +# а сервис backend есть в ОБОИХ стеках, так что закрепление молча легло бы на +# бэкенд Птицы. Правильный вызов — внутри проекта МЕРЫ: +# +# docker compose -p gendesign-tradein \ +# -f docker-compose.prod.yml -f docker-compose.selectel.yml up -d # # ── Почему это вообще нужно (замер 2026-08-23, с нового хоста) ───────────── # У api.telegram.org семь публикуемых адресов. С Selectel отвечает РОВНО ОДИН: