Jitsi: k8s-топология и взаимодействие с бэкендом
Как саморазмещённый Jitsi разворачивается для PIN и как stateless .NET-сервис messenger с ним
взаимодействует. Right-sized под целевую нагрузку (ADR-0056: 1–10k активных, конференции редки). Контракт
домена/API остаётся нейтральным — здесь конкретика инфраструктуры Jitsi.
Набор компонентов
| Компонент | Роль | Тип | Реплики (target) | Заметки |
|---|---|---|---|---|
| prosody | XMPP-сервер: MUC-комнаты, presence, JWT-auth, reservations | stateful (in-memory rooms) | 1 (HA — 2, sticky) | несёт кастомные PIN-модули (token/reservations/presence) |
| jicofo | focus: создание конференций, выбор моста, оркестрация jibri | stateless | 1 | одна на кластер; управляет brewery JVB/jibri |
| JVB (SFU) | jitsi-videobridge: маршрутизация медиа | stateless | 1–2 (HPA по нагрузке) | публичный UDP 10000; без Octo (octo.enabled=false) |
| jibri | запись сессии (file mode) → финализация | stateful (диск /mnt/recordings) | 0–2 (по числу параллельных записей) | 1 сессия на инстанс; SYS_ADMIN, headless Chrome |
| coturn | TURN/STUN — обход NAT | stateless | 1–2 | use-auth-secret, TLS на 443 |
| jigasi | SIP-шлюз | — | 0 (будущее) | не разворачиваем в MVP (телефонный вход/транскрипция — роадмап) |
Веб-SPA jitsi-meet не разворачивается: фронт PIN — нативный клиент на lib-jitsi-meet
(jitsi-client.md), не iframe. Разворачиваются только серверные компоненты + библиотека.
Порты и ingress
| Поток | Endpoint | Транспорт |
|---|---|---|
| Клиент → prosody (сигналинг) | /xmpp-websocket (secure WebSocket) за TLS-ingress | wss://<MediaDomain> |
| Клиент → JVB (медиа) | UDP 10000 (публичный, per-node) | SRTP/ICE |
| Клиент → coturn (TURN relay) | TCP/UDP 443 (use-auth-secret) | TURN over TLS |
messenger → prosody | — | не подключается (см. ниже) |
prosody → messenger (reservation/presence) | HTTP на api/internal/* | HTTP + HMAC/mTLS |
jibri → messenger (ingest записи) | HTTP на api/internal/call-recordings/{sessionId}/ingest | multipart HTTP |
SignalingUrl/MediaDomain из MediaJoinModel указывают на prosody
WebSocket-endpoint и домен развёртывания; IceServers — на coturn.
Как взаимодействует stateless-бэкенд
messenger не участник XMPP-плоскости и не держит медиа-состояния. Его роль:
- Минтит JWT входа (jitsi-jwt.md) — HS256 на общем
app_secret; клиент предъявляет его prosody при подключении к комнате. Токен короткоживущий, в БД не хранится (INV-CALL-6/INV-CONF-7). - Принимает admission-вебхук
mod_reservations(POST /internal/jitsi/reservations) — авторизует комнату по имени и возвращает конфиг (jitsi-rooms.md);DELETE …/{roomName}— финализация. - Принимает presence-вебхук кастомного prosody-модуля (
POST /internal/jitsi/events) — join/leave — авторитет ростера (call-participant.md INV-CPART-5). - Принимает ingest записи от jibri finalize-скрипта (recording-pipeline.md).
Обратно к Jitsi бэкенд не ходит императивно (не создаёт комнаты по XMPP): комната поднимается, когда
клиент с валидным JWT входит по имени, а admission решается reservation-вебхуком. Единственный императивный
жест — старт/стоп записи инициируется клиентом-модератором через lib-jitsi-meet
(jitsi-client.md), не бэкендом.
Env-матрица (перенос из Nomad-референса в Helm/k8s)
Мета-репозиторий Jitsi поставляет Nomad-IaC (thirdparty/jitsi/infra-provisioning/nomad/*) как
референс конфигурации; PIN авторит собственные Helm/k8s-манифесты, перенося оттуда ключи. Ниже — полная
env-матрица по компонентам (значения <domain> = MediaRoom.Domain = домен развёртывания медиа, напр.
media.pin.ru). Секреты (*_SECRET, *_PASSWORD, static-auth-secret) — только из vault, не в манифесте.
| Компонент | Переменная | Значение / источник |
|---|---|---|
| prosody | ENABLE_AUTH | 1 — включить аутентификацию главного vhost |
| prosody | AUTH_TYPE | jwt — authentication = "token" (см. mod_auth_token.lua) |
| prosody | JWT_APP_ID | pin_messenger (== aud/iss токена, jitsi-jwt.md) |
| prosody | JWT_APP_SECRET | общий HS256-секрет (vault) — prosody проверяет подпись JWT входа |
| prosody | XMPP_DOMAIN | <domain> — публичный домен, muc_mapper_domain_base |
| prosody | XMPP_AUTH_DOMAIN | auth.<domain> — vhost аутентифицированных сервисов (focus/jvb) |
| prosody | XMPP_MUC_DOMAIN | conference.<domain> — MUC-компонент комнат |
| prosody | XMPP_INTERNAL_MUC_DOMAIN | internal.auth.<domain> — brewery-MUC для JVB/jibri |
| prosody | XMPP_RECORDER_DOMAIN | recorder.<domain> — hidden-домен рекордера (jibri) |
| prosody | (config) reservations_api_prefix | <messenger>/api/internal/jitsi (jitsi-rooms.md) |
| prosody | ports | 5222 (c2s, internal), 5280 (http/websocket, за ingress 443) |
| jicofo | XMPP_AUTH_DOMAIN / JICOFO_AUTH_USER / JICOFO_AUTH_PASSWORD | focus-пользователь на auth.<domain> (vault пароль) |
| jicofo | (config) jibri.brewery-jid | jibribrewery@internal.auth.<domain> (reference.conf:305) |
| jicofo | (config) conference.enable-moderator-checks | true — запись/привилегии только модератору (reference.conf:219) |
| JVB | JVB_AUTH_USER / JVB_AUTH_PASSWORD | jvb-пользователь на auth.<domain> (vault пароль) |
| JVB | JVB_PORT | 10000/udp — публичный медиапорт (per-node) |
| JVB | DOCKER_HOST_ADDRESS | публичный IP ноды (кандидат ICE для клиента) |
| JVB | JVB_OCTO_BIND_ADDRESS | не задаём — octo.enabled=false (один регион, ADR-0056) |
| jibri | ENABLE_RECORDING | true при RECORDINGS_ENABLED (nomad/jibri.hcl:213) |
| jibri | JIBRI_FINALIZE_RECORDING_SCRIPT_PATH | /usr/bin/pin_finalize.sh (замена jitsi_uploader.sh, recording-pipeline.md) |
| jibri | JIBRI_RECORDING_DIR | /mnt/recordings (emptyDir/PV, nomad/jibri.hcl:214) |
| jibri | JIBRI_USAGE_TIMEOUT | 61 minutes — авто-shutdown простаивающего (nomad/jibri.hcl:219) |
| jibri | JIBRI_RECORDER_USER / JIBRI_RECORDER_PASSWORD | рекордер на recorder.<domain> (vault пароль) |
| jibri | JIBRI_XMPP_USER / JIBRI_XMPP_PASSWORD | control-пользователь на auth.<domain> (vault пароль) |
| jibri | XMPP_RECORDER_DOMAIN / XMPP_INTERNAL_MUC_DOMAIN | recorder.<domain> / internal.auth.<domain> |
| coturn | (config) static-auth-secret | общий TURN-секрет (vault) — тем же секретом messenger минтит TURN-креды |
| coturn | (config) realm | <domain> |
| coturn | ports | 443/tcp+udp (TURN over TLS), 9641 (/metrics) |
Полный инвентарь изменённых файлов — jitsi-modifications.md. YAML-манифесты развёртывания — jitsi-manifests.md.
prosody: main-vhost .cfg.lua (SKETCH)
Главный vhost авторится PIN (не берётся из образа as-is): включаем только нужные модули, точка входа в
контракт messenger — reservations_api_prefix + presence-модуль. Сокращённый набросок:
VirtualHost "media.pin.ru" -- = XMPP_DOMAIN = MediaRoom.Domain
authentication = "token" -- ENABLE_AUTH=1 / AUTH_TYPE=jwt
app_id = "pin_messenger" -- JWT_APP_ID (== aud/iss)
app_secret = os.getenv("JWT_APP_SECRET") -- из vault-смонтированного секрета
modules_enabled = {
"token_verification"; -- room-claim обязан совпадать с именем комнаты
"token_affiliation"; -- context.user.moderator/affiliation=owner → moderator
"reservations"; -- authoritative admission через messenger
"jibri_session"; -- обогащение app_data записи (session_id/initiator)
"pin_muc_presence"; -- НОВЫЙ: presence join/leave → messenger
}
muc_mapper_domain_base = "media.pin.ru"
-- authoritative admission (mod_reservations)
reservations_api_prefix = "https://messenger.pin.internal/api/internal/jitsi"
reservations_api_timeout = 20 -- секунд
reservations_api_retry_count = 3
reservations_api_headers = { -- аутентификация вебхука (HMAC/Bearer)
["Authorization"] = "Bearer "..os.getenv("JITSI_WEBHOOK_TOKEN");
}
-- presence-модуль (свой) читает тот же токен из env
pin_muc_presence_api_url = "https://messenger.pin.internal/api/internal/jitsi/events"
Отключаются неиспользуемые модули открытой поставки (breakout-rooms, lobby, av-moderation, polls). Формат
reservations_api_* — штатные опции mod_reservations.lua; заголовок Authorization кладётся в каждый вызов
(http_headers, строки 130–138 модуля).
jicofo: override-конфиг (SKETCH)
Значения задаются override-jicofo.conf/env поверх reference.conf (сам reference не правим):
jicofo {
jibri {
brewery-jid = "jibribrewery@internal.auth.media.pin.ru" # reference.conf:305
pending-timeout = 90 seconds
}
conference {
enable-moderator-checks = true # reference.conf:219
}
# transcription { url-template = ... } # НЕ задаём в MVP (transcription-roadmap.md)
}
Хранение и эксплуатация
- jibri пишет на persistent volume
/mnt/recordings; после успешного ingest finalize-скрипт удаляет локальную директорию (2xx отmessenger). Диск — на время захвата+выгрузки, не долговременно. - prosody держит комнаты в памяти — при рестарте активные комнаты рвутся; клиент реконнектит по REST (persist-then-push не источник истины для медиа). HA — 2 реплики со sticky-сессиями.
- Здоровье: jibri
/jibri/api/v1.0/health; JVB/jicofo/coturn —/metrics(Prometheus). Алерты — нет свободного jibri при запросе записи (MSG_RECORDING_PROVISION_FAILED).
Секреты, сеть, health/readiness
- Секреты — только vault.
JWT_APP_SECRET, focus/JVB/jibri XMPP-пароли,static-auth-secretcoturn,JITSI_WEBHOOK_TOKEN— монтируются из vault (External Secrets / CSI), не в ConfigMap и не в git. Тот жеJWT_APP_SECRETдержит иmessenger(минт JWT входа), тот жеstatic-auth-secret— для TURN-кред (jitsi-jwt.md). - Публичный UDP на JVB.
UDP 10000должен быть достижим клиентом снаружи:hostPort/hostNetworkилиService type=LoadBalancerc UDP;DOCKER_HOST_ADDRESS= публичный IP ноды (иначе ICE не соберёт кандидатов). coturn слушает публичный443для обхода строгого NAT (jitsi-modifications.md). - NetworkPolicy. Внутрь пускаем: клиент → prosody (ingress 443/wss), клиент → JVB (UDP 10000), клиент →
coturn (443). Внутрикластерно: jicofo ↔ prosody (5222), JVB/jibri ↔ prosody (5222 internal-MUC). Egress
prosody/jibri →
messenger(reservation/presence/ingest) — единственные исходящие к бэкенду; всё прочее egress закрыто (self-host,disableThirdPartyRequests). - Health/readiness. prosody — c2s-порт +
/http-bindliveness; jicofo/JVB —/about/health; jibri —/jibri/api/v1.0/health(readiness=idle перед приёмом записи); coturn —/metrics. Реадинес jibri влияет на доступность записи (нетidle-инстанса →MSG_RECORDING_PROVISION_FAILED).
Обратные ссылки
Автоссылки: где используется этот документ.
- index.md (1): Messenger Service
- calls (9): Медиа-звонки и запись на Jitsi — интеграционный гид (messenger), Медиа-звонки на Jitsi: план поставки (playbook аналитик → разработчик), Предусловия в file storage для хранения записей звонков, Jitsi-звонки: план верификации и приёмки, Jitsi: инвентарь изменений в thirdparty/jitsi, Jitsi: минтинг JWT входа в .NET, Jitsi: роадмап транскрипции и конспектов (будущая фаза), Jitsi: сквозной пайплайн авто-записи, Jitsi: k8s/Helm-манифесты (SKETCH)
Связанные документы
- Гид: README.md; JWT: jitsi-jwt.md; комнаты: jitsi-rooms.md; запись: recording-pipeline.md; изменения: jitsi-modifications.md; манифесты: jitsi-manifests.md.
- Вебхуки: ../api/internal/; дескриптор входа: MediaJoinModel.
- Решения: ADR-0062, ADR-0056 simplicity-first.