Несколько экземпляров панели
Панель можно запустить в нескольких экземплярах за балансировщиком — ради отказоустойчивости или чтобы распределить нагрузку. Для этого экземпляры должны разделять состояние: базу данных, кэш, файлы и обмен событиями.
Для большинства установок это не нужно. Одна панель справляется с сотнями игровых серверов — тяжёлую работу выполняют демоны на выделенных серверах, а не панель.
Что должно быть общим
| Компонент | Настройка | Что будет иначе |
|---|---|---|
| База данных | PostgreSQL или MySQL | SQLite не рассчитан на несколько подключённых экземпляров |
| Кэш | CACHE_DRIVER=redis |
При memory сессии и ключи установки видит только один экземпляр |
| Обмен событиями | PUBSUB_DRIVER=redis или postgres |
При memory экземпляры не узнают о событиях друг друга |
| Файлы | FILES_DRIVER=s3 |
При local у каждого экземпляра свои файлы и свои сертификаты |
Пример конфигурации:
DATABASE_DRIVER=postgres
DATABASE_URL=postgres://gameap:пароль@db.example.com:5432/gameap?sslmode=require
CACHE_DRIVER=redis
CACHE_REDIS_ADDR=redis.example.com:6379
PUBSUB_DRIVER=redis
PUBSUB_REDIS_ADDR=redis.example.com:6379
PUBSUB_INSTANCE_ID=panel-1
FILES_DRIVER=s3
FILES_S3_ENDPOINT=https://s3.example.com
FILES_S3_BUCKET=gameap
FILES_S3_ACCESS_KEY_ID=...
FILES_S3_SECRET_ACCESS_KEY=...
AUTH_SECRET и ENCRYPTION_KEY должны быть одинаковыми на всех экземплярах: иначе токен,
выданный одним, не примет другой, а зашифрованные данные окажутся нечитаемыми.
Идентификатор экземпляра
PUBSUB_INSTANCE_ID=panel-1
Значение должно быть уникальным для каждого экземпляра. По нему экземпляры отличают собственные сообщения от чужих и адресуют ответы друг другу.
Если переменную не задать, используется значение default — одинаковое у всех, и обмен между
экземплярами работать не будет. Задавайте её явно.
Как это работает
Демон подключается к одному из экземпляров — к тому, на который его направил балансировщик — и держит с ним постоянное соединение. Все остальные экземпляры к этому демону обращаться напрямую не могут.
Поэтому команда, пришедшая на экземпляр, который не владеет соединением с нужным демоном, передаётся через общий обмен событиями тому экземпляру, который им владеет; ответ возвращается тем же путём. Так же работают файловые операции, консоль и запросы метрик.
Из этого следует, что общий обмен событиями обязателен: без него панель будет управлять только теми демонами, которые подключились именно к этому экземпляру.
Задачи, появившиеся в базе, пока демон был отключён или пока его соединением владел другой экземпляр, доставляются сразу при подключении, а не при следующем переподключении.
Балансировщик и порты
Разделите два потока:
- HTTP (8025) — можно балансировать обычным образом, привязка сессии к экземпляру не нужна: токены проверяются по общему ключу, а сессионное состояние лежит в общем кэше.
- gRPC (31718) — соединения долгоживущие. Балансировщик должен уметь их держать и не рвать по таймауту простоя: собственного механизма keepalive в канале нет, живость держится на heartbeat раз в 30 секунд.
Задайте GRPC_EXTERNAL_HOST с адресом, по которому демоны видят панель через балансировщик,
и GRPC_EXTERNAL_PORT, если порт наружу опубликован под другим номером.
Сертификаты
Сертификаты gRPC должны быть общими. Они хранятся в файловом хранилище панели, поэтому при
FILES_DRIVER=s3 автоматически оказываются общими для всех экземпляров.
При FILES_DRIVER=local каждый экземпляр сгенерирует собственный центр сертификации, и демон,
зарегистрированный через один экземпляр, не сможет подключиться к другому.
HTTPS
Если сертификат панели выпускается через ACME, есть две особенности.
Хранилище ACME тоже лежит в файловом хранилище — при S3 оно общее.
Блокировка, не дающая нескольким экземплярам одновременно запрашивать сертификат, работает через
Redis. Она включается только при CACHE_DRIVER=redis; при кэше в памяти блокировка локальная,
и экземпляры будут мешать друг другу.
Подтверждение по http-01 требует, чтобы запрос центра сертификации попал на тот же экземпляр,
который начал выпуск. Проще использовать dns-01 либо завершать TLS на балансировщике.
См. HTTPS и сертификаты.
Ограничения
Счётчики попыток входа живут в кэше. При CACHE_DRIVER=redis они общие, при memory — свои
у каждого экземпляра, то есть фактический предел умножается на число экземпляров.
Журнал аудита пишется в вывод каждого экземпляра отдельно. Сводить их нужно внешним сборщиком журналов, см. Безопасность.
Задачи плагинов дедуплицируются между экземплярами распределёнными блокировками, поэтому периодическая задача плагина выполнится один раз, а не на каждом экземпляре.
Проверка
После запуска убедитесь, что:
- демон, зарегистрированный через один экземпляр, управляется и через другой;
- вход, выполненный на одном экземпляре, действует на остальных;
- файловый менеджер открывается независимо от того, на какой экземпляр попал запрос.
Если что-то из этого не работает, почти всегда причина в том, что один из четырёх общих компонентов остался локальным.