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
116 lines
10 KiB
YAML
116 lines
10 KiB
YAML
# 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.
|