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

Отказоустойчивость на двух нодах

Последнее обновление 23 сентября 2026Открыть как Markdown

Схема: две машины с локальным инстансом, общая внешняя PostgreSQL и балансировщик заказчика перед HTTP. Каждая нода — самостоятельный стек Docker Compose; общее у них только состояние в базе.

Порядок такой: сначала внешняя PostgreSQL, затем первая нода как обычная установка, затем вторая — с теми же секретами и адресами.

Состав схемы

Компонент Роль в схеме
Внешняя PostgreSQL Единственное общее состояние: пользователи, ресурсы, сессии панели, аренда лидера RADIUS
Балансировщик заказчика HTTP к панели и API, TLS, публичный адрес
Нода A и нода B Одинаковые стеки с разными INSTANCE_ID
RADIUS-клиенты (NAS) Обращаются к нодам напрямую: primary — host-A, secondary — host-B

Балансировать UDP RADIUS обычно нечем, поэтому отказоустойчивость для него делается на стороне NAS: в настройках RADIUS-клиента прописывают два сервера — host-A:1812 первым и host-B:1812 вторым.

Установка второй ноды

  1. Скопируйте каталог дистрибутива того же релиза на вторую машину.
  2. Перенесите с первой ноды совпадающие секреты и адреса — таблица ниже. Новые SECRET_KEY и API_KEY_* не генерировать.
  3. Задайте уникальный INSTANCE_ID, например node-b.
  4. Укажите тот же режим внешней БД и те же реквизиты подключения.
  5. Поставьте RADIUS_UDP_BINDING=all.
  6. Если HTTP идёт только через балансировщик — ставьте без nginx (--tls-mode none) и публикуйте панель и API портами; см. Внешний reverse proxy.
  7. Убедитесь, что на каждой ноде свой COMPOSE_FILE с оверлеем публикации RADIUS.
  8. Запустите ./install.sh (или подготовьте .env вручную и выполните ./update.sh).

Миграции на второй ноде выполнять не нужно: схема уже применена с первой, Flyway отработает вхолостую.

Переменные, которые должны совпадать

Переменная Зачем
API_KEY_ENCRYPTION_KEY, API_KEY_PEPPER Расшифровка ключей ресурсов и HMAC. С разными значениями вторая нода не прочитает то, что записала первая
SECRET_KEY Сессии и CSRF панели. Сессии хранятся в базе, поэтому «липкие» сессии на балансировщике не нужны
POSTGRES_* или DATABASE_URL, POSTGRES_SSL_* Одна база на обе ноды
LOCAL_PANEL_URL, CSRF_TRUSTED_ORIGINS, ALLOWED_HOSTS Публичный адрес панели за балансировщиком
LOCAL_URL Обычно http://local-backend:8080 — внутри стека своей ноды
RADIUS_UDP_BINDING, RADIUS_LEADER_* Одинаковая политика UDP на обеих нодах
DISTRIBUTED_STATE Задан в compose значением postgres. На memory не менять: ноды перестанут видеть общее состояние
Теги образов Желательно одинаковые версии

Различаются: INSTANCE_ID, при необходимости — порты на хосте и имена compose-проектов.

Новые секреты шифрования ломают вторую ноду

SECRET_KEY и API_KEY_* переносятся с первой ноды как есть. Если сгенерировать их заново, ключи ресурсов, записанные первой нодой, второй нодой не расшифруются.

RADIUS на двух нодах

Режим слушателя задаётся переменной RADIUS_UDP_BINDING:

  • leader — UDP слушает только владелец аренды. Значение по умолчанию, рассчитанное на один хост.
  • all — слушают обе ноды. Этот вариант и нужен для схемы с primary и secondary на стороне NAS.

Аренду лидера настраивают RADIUS_LEADER_LEASE_TTL_SECONDS (по умолчанию 30) и RADIUS_LEADER_RENEW_INTERVAL_MS (по умолчанию 10000).

На каждой ноде RADIUS публикуется своим оверлеем docker-compose.publish-radius.yml — он должен быть в COMPOSE_FILE обеих нод. Отдельные compose-проекты на разных машинах между собой не конфликтуют.

Не путать с репликами

Ограничение «не публиковать RADIUS при нескольких репликах» относится к --scale внутри одного хоста, а не к двум машинам. См. Несколько реплик local-backend.

Обновление

Обновляйте ноды по одной:

# на ноде A
./update.sh
# убедиться, что нода поднялась, затем на ноде B
./update.sh

Миграции применяет первая обновлённая нода, вторая получает готовую схему. Одновременный запуск на пустой базе безопасен за счёт таблицы блокировок Flyway, но при обновлении рабочего контура последовательность даёт предсказуемый результат.

Проверка

./doctor.sh запускается на каждой ноде отдельно и проверяет её собственный стек: контейнеры, связь с базой, доступ к облаку, публикацию RADIUS. Отчёт с обеих нод можно прислать в поддержку целиком.

Дополнительно проверьте на своей стороне:

  • панель открывается через балансировщик и вход проходит независимо от того, на какую ноду попал запрос;
  • вход по RADIUS проходит при остановленной ноде A — NAS должен уйти на secondary;
  • INSTANCE_ID у нод разные: их видно в журналах и в «Истории ошибок».

Резервное копирование

База общая и копируется один раз — по правилам вашей СУБД. Файлы настроек сохраняются с каждой ноды отдельно: у нод разный INSTANCE_ID. Что входит в копию и как её восстановить — «Резервное копирование и восстановление».

Смотрите также

Связаться с нами

Подберём сценарий под вашу инфраструктуру, рассчитаем стоимость и запустим бесплатный пилот на 30 дней.

Отправляя заявку, вы соглашаетесь на обработку персональных данных.