Практикум: группа central в Docker¶
Резервирование объясняет, как устроена группа central, а Группа central на нескольких серверах — как её развернуть. Эта страница — про то, чтобы увидеть её работу своими глазами: на одной машине, из контейнеров, за десять минут и без единого арендованного сервера.
Стенд одноразовый. На нём можно и нужно делать то, чего не делают на работающей инсталляции: гасить процессы посреди работы и смотреть, что из этого выйдет.
Что понадобится¶
- Docker с compose — больше ничего ставить не нужно.
- Ключ лицензии. Он нужен каждому процессу: и обоим central, и обоим стримерам.
- Образ с группой central. Практикуму нужна сборка, в консоли которой есть раздел Кластер → Central. Если раздела нет, образ старше группы central, и стенд не соберётся.
- Свободные порты 8081 и 8082 на локальной машине.
Из чего собран стенд¶
Пять контейнеров:
- postgres — одна база на всю группу.
- central-a и central-b — два инстанса управления над этой базой, консоли на портах 8081 и 8082.
- streamer-1 и streamer-2 — два стримера, разведённые по разным инстансам: первый ходит в central-a, второй — в central-b.
Разведение стримеров по инстансам — не украшение стенда, а его смысл. Картина «прямо сейчас» одна на всю группу, и весь парк обязан быть виден с любого из двух адресов, хотя отчитываются машины в разные.
Скачайте docker-compose.yaml и положите в пустой каталог. Ниже — те его куски, ради которых он написан; остальное в нём — обычная обвязка.
Первый инстанс заявляет все четыре роли, включая migrate:
central:
admin_keys:
- lab-admin-key
roles: [run, migrate, layouter, stats]
advertise_url: http://central-a
Второй — то же самое без migrate: схему накатывает один процесс, иначе два погонят миграции наперегонки.
central:
admin_keys:
- lab-admin-key
roles: [run, layouter, stats]
advertise_url: http://central-b
Роли layouter и stats заявлены у обоих, и это не двойной запуск: роль — притязание, а исполнителя выбирает мандат.
Стример получает не адрес инстанса, а список адресов группы; порядок — порядок предпочтения:
managed_by:
name: streamer-1
url:
- http://central-a
- http://central-b
join_token: ${JOIN_TOKEN}
У второго стримера тот же список в обратном порядке.
Подъём¶
Стенд не собирается одним docker compose up: окно присоединения открывает живой central, и join-токен появляется только после его старта.
Сначала база и оба инстанса управления:
export CATENA_VERSION=latest
export LICENSE_KEY='ваш ключ'
docker compose up -d postgres central-a central-b
Дождитесь, пока консоль откроется на http://127.0.0.1:8081, и войдите как admin с паролем pass. При первом входе консоль попросит завести именную учётную запись — заведите.
Откройте Кластер → Стримеры, нажмите Разрешить присоединение и скопируйте join-токен. Поднимите стримеры с ним:
JOIN_TOKEN=jt-... docker compose up -d streamer-1 streamer-2
Обе машины появятся в списке стримеров за несколько секунд. Окно присоединения после этого закройте — парк собран.
Заведите несколько стримов, чтобы в кластере было что раскладывать. Вход syntetic — встроенный генератор, внешний источник стенду не нужен:
for i in 1 2 3 4 5 6; do
curl -s -X PUT -H 'Authorization: Bearer lab-admin-key' \
-H 'Content-Type: application/json' \
-d '{"inputs":[{"syntetic":{}}]}' \
"http://127.0.0.1:8081/central/api-v4/streams/configs/cam$i"
done
Группа целиком¶
Откройте Кластер → Central.

В таблице две строки — вся группа, и её одинаково показывает любой инстанс: реестр лежит в общей базе.
- Притязания у обоих почти одинаковы:
migrateзаявлен только уcentral-a, всё остальное — у обеих машин. - Держит мандаты заполнено только у одной. Это и есть ответ на вопрос «кто в группе главный»: главного нет, есть держатели отдельных мандатов.
- У второй строки написано нет — только обслуживает запросы. Такой инстанс не запасной и не спящий: он полноценно отвечает консоли, API и стримерам, просто фоновую работу сейчас делает не он.
На вашем стенде мандаты могут лежать иначе — оба у одной машины или по одному у каждой. Мандаты независимы, и их расстановка зависит от того, кто успел первым; неправильной расстановки здесь не бывает.
Парк виден с любого адреса¶
Не уходя с инстанса, откройте Кластер → Стримеры.

Обе машины в эфире, хотя отчитывается в этот инстанс только одна из них. Вторая шлёт синхронизацию соседу, а видна здесь потому, что картина «прямо сейчас» одна на группу: инстанс без мандата stats ходит к ней по сети — по тому самому объявленному адресу.
Откройте ту же страницу на http://127.0.0.1:8082 — увидите то же самое. Это и есть проверка, ради которой стримеры разведены по разным инстансам.
Гасим держателя мандата¶
Теперь то, ради чего стенд одноразовый. Погасите инстанс, который держит мандаты, — на снимках выше это central-b:
docker compose stop central-b
Вернитесь на Кластер → Central живого инстанса и подождите несколько секунд.

Три вещи изменились:
- Строка погашенного инстанса не исчезла, а помечена: «молчит — процесс, скорее всего, умер». Группа помнит свой состав, а не только живых.
- Мандаты перешли к живому инстансу. Никто их не передавал: мандат живёт на отдельном соединении с PostgreSQL и освобождается вместе со смертью сессии, а сосед приходит за освободившимся сам.
- Номер эпохи вырос. Он растёт при каждой смене держателя и едет вместе с каждой записью: инстанс, очнувшийся уже не держателем, получит отказ на записи, а не испортит размещение задним числом.
Переезд занимает секунды. Руками подтверждать его не нужно и нечем.
Эфир этого не заметил¶
Откройте Стримы.

Все шесть стримов идут. Половина из них живёт на стримере, который отчитывался в погашенный инстанс: он ушёл на второй адрес из своего списка за один неудавшийся запрос, и central даже не успел счесть его пропавшим.
Ровно из-за этого второй адрес в списке обязателен. Уберите его, повторите опыт — и через полторы минуты увидите, как лейаутер уводит стримы с живой машины, потому что она перестала подавать признаки жизни.
Возвращаем инстанс¶
docker compose start central-b
Строка снова загорается, но обратного переезда не происходит — и это не недоделка, а решение.
- Мандаты остаются у живого инстанса. Отбирать их незачем: держатель работает, а смена держателя стоит новой инкарнации картины «прямо сейчас».
- Стример остаётся на том адресе, куда ушёл. Пока адрес отвечает, менять его незачем; порядок в списке — стартовое предпочтение, а не постоянная привязка.
Вернуть исходную расстановку можно перезапуском — стенд для того и одноразовый, — но в бою этого не требуется: группа работает в любой расстановке.
Убираем стенд¶
docker compose down -v
Ключ -v сносит и тома: база, состояние стримеров и их идентичность в кластере. Без него следующий подъём получит наполовину чужое состояние.
Чего этот стенд не показывает¶
- Отказ базы. Здесь она одна и без реплики: погасите её — и управление встанет целиком, а эфир продолжится. Это правда, но резервирование базы — задача самой базы.
- Сеть. Все контейнеры в одной docker-сети, потерь и задержек между ними нет.
- Нагрузку. Шесть синтетических стримов не говорят ничего о том, как группа ведёт себя на настоящем парке.
- Точку входа оператора. На стенде их две — по адресу на инстанс; в бою нужен один адрес с переключением.