Отказоустойчивость на двух нодах
Схема: две машины с локальным инстансом, общая внешняя 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 вторым.
Установка второй ноды
- Скопируйте каталог дистрибутива того же релиза на вторую машину.
- Перенесите с первой ноды совпадающие секреты и адреса — таблица ниже. Новые
SECRET_KEYиAPI_KEY_*не генерировать. - Задайте уникальный
INSTANCE_ID, напримерnode-b. - Укажите тот же режим внешней БД и те же реквизиты подключения.
- Поставьте
RADIUS_UDP_BINDING=all. - Если HTTP идёт только через балансировщик — ставьте без nginx (
--tls-mode none) и публикуйте панель и API портами; см. Внешний reverse proxy. - Убедитесь, что на каждой ноде свой
COMPOSE_FILEс оверлеем публикации RADIUS. - Запустите
./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. Что входит в копию и как её восстановить — «Резервное копирование и восстановление».