gendesign/tradein-mvp/docker-compose.selectel.yml
lekss361 729e9acc52
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Successful in 2m42s
Deploy Trade-In / build-browser (push) Successful in 3m16s
Deploy Trade-In / deploy (push) Successful in 3m15s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 9s
Deploy Trade-In / test (push) Successful in 3m52s
Deploy Trade-In / build-backend (push) Successful in 34s
fix(tradein/deploy): подключить selectel-оверрайд — иначе после переезда бот умрёт молча (#3093)
2026-08-25 16:39:40 +00:00

116 lines
10 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Override: закрепляет рабочий IP api.telegram.org для tgbot и backend.
#
# ⚠️ ОБНОВЛЕНО 25.08 (#3059). Файл больше НЕ Selectel-only и подключается
# БЕЗУСЛОВНО — его подмешивает deploy-tradein.yml (переменная COMPOSE_FILES).
# Имя оставлено прежним, чтобы не ломать ссылки на него в раннбуке и задачах.
#
# Что было не так: с 23.08 файл лежал в репозитории, но НИ ОДИН вызов compose в
# деплое его не подключал — везде было жёстко `-f 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 отвечает РОВНО ОДИН:
#
# 149.154.167.220 -> 302 за 0.11 с (единственный живой)
# 149.154.166.110 -> 000 <- именно его отдаёт резолвер хоста!
# 149.154.167.99 -> 000
# 149.154.175.100 -> 000
# 149.154.171.5 -> 000
# 91.108.4.5 -> 000
# 91.108.56.130 -> 000
#
# Сканом всей подсети 149.154.167.0/24 с этого же хоста подтверждено, что
# 149.154.167.220 — единственный отвечающий адрес Telegram во всём блоке, не
# только среди этих семи. Это НЕ блокировка Selectel и не наш файрвол: с
# Beget отвечают три адреса из тех же семи (включая тот, что отдаёт DNS там),
# т.е. Telegram частично фильтруется у ОБОИХ провайдеров по-разному — Beget
# просто попадает на живой адрес через штатный резолвер, а Selectel нет.
#
# Через прокси (ASocks, все четыре узла) Telegram тоже не проходит — все
# запросы 000, узлы российские. Этот путь закрыт, обход только через IP.
#
# Проверено закрепление (прежде чем закреплять в compose):
# - на хосте через /etc/hosts: curl https://api.telegram.org/ -> 302, 0.11 с
# - настоящий Bot API (/bot<fake>/getMe) -> {"ok":false,"error_code":401} за
# 0.11 с (для сравнения — с Beget тот же ответ приходит за 0.25 с, т.е.
# закреплённый адрес не просто живой, а ещё и быстрее дефолтного пути)
# - В КОНТЕЙНЕРЕ через docker --add-host -> 302 за 0.125 с (подтверждает,
# что extra_hosts ниже — не отличается от прямой проверки на хосте)
# - стабильность: 5 запросов подряд -> 302 302 302 302 302, без единого сбоя
#
# ── Что ломается без этого обхода ───────────────────────────────────────────
# tradein-tgbot — long-polling воркер (см. docker-compose.prod.yml, сервис
# tgbot): он не слушает входящих соединений, а сам постоянно ходит наружу к
# api.telegram.org. Если резолвер отдаёт мёртвый адрес, httpx виснет на
# таймауте long-poll'а и процесс тихо умирает — restart: unless-stopped его
# поднимает заново, он снова резолвит тот же мёртвый адрес и снова виснет.
# Никакого явного краша или строки в логе, по которой это легко поймать —
# отсюда и требование закрепить адрес ДО переезда, а не разбираться постфактum.
#
# Вместе с ботом молча ложатся:
# - ops/lib-backup.sh — уведомления об успехе/провале бэкапов в Telegram
# - ops/uptime-healthcheck.sh — uptime-нотификации
# (обаХОСТ-скрипты, не контейнеры; extra_hosts на них не действует, этот
# файл их не чинит — см. TODO в конце файла).
#
# ── TELEGRAM_API_IP: почему переменная, а не жёсткий IP ─────────────────────
# Google/Cloudflare-класса анycast у Telegram нет: их адреса — обычные
# датацентровые IP, которые Telegram время от времени меняет. Если
# 149.154.167.220 однажды тоже станет мёртвым (или Selectel поменяет
# маршрутизацию и он перестанет быть единственным живым), правка — это
# одна строка в .env.runtime (TELEGRAM_API_IP=<новый адрес>) и
# `docker compose ... up -d --force-recreate --no-deps tgbot`, БЕЗ релиза и
# без правки этого файла. Дефолт ниже (:-149.154.167.220) — текущий
# подтверждённый живой адрес, применяется если переменная не задана.
# ── Почему ДВА сервиса, а не только бот ─────────────────────────────────────
# В api.telegram.org ходит не только tgbot. Внутри контейнера backend это
# делают ещё два пути:
# - app/api/v1/glitchtip.py — пересылка алертов GlitchTip в Telegram-тему
# - app/api/v1/support.py — support-чат
# Оба бьют httpx напрямую в api.telegram.org из того же контейнера, что и
# API. Ломаются они ЗАМЕТНЕЕ бота (не long-poll, а per-request: конкретный
# запрос отваливается по таймауту), но ломаются — и, что важнее, ломается
# пересылка алертов, то есть ещё один канал, которым мы узнали бы о беде.
# Закреплять адрес только боту значило бы починить треть и выглядеть готовым.
services:
tgbot:
extra_hosts:
- "api.telegram.org:${TELEGRAM_API_IP:-149.154.167.220}"
backend:
extra_hosts:
- "api.telegram.org:${TELEGRAM_API_IP:-149.154.167.220}"
# ── Хостовая половина — закрыта в ops/selectel-bootstrap.sh ─────────────────
# ops/lib-backup.sh и ops/uptime-healthcheck.sh исполняются НА ХОСТЕ (cron,
# не в docker), поэтому extra_hosts им не помогает. Их закрывает шаг 11
# bootstrap-скрипта: он кладёт ту же запись в системный /etc/hosts, идемпотентно
# и с той же переменной TELEGRAM_API_IP. Итого закреплены все три потребителя:
# tgbot, backend и хостовые скрипты.
#
# ⚠️ ОДНА ТОЧКА ОТКАЗА, ЗАФИКСИРОВАНА ОСОЗНАННО. 149.154.167.220 — единственный
# живой адрес во всём 149.154.167.0/24 с этого хоста. Если он умрёт, бот снова
# умрёт молча, а канал оповещения об этом сам идёт через Telegram — поломка
# скрывает сама себя. Поэтому закрепление НЕОБХОДИМО, НО НЕ ДОСТАТОЧНО: нужен
# независимый канал алертов. Проверено, что с нового хоста доступен
# smtp.beget.com:465 (порт 587 закрыт), плюс GlitchTip остаётся на Beget и
# доступен по имени. Отдельная задача, см. #3059.