Jitsi: k8s/Helm-манифесты (SKETCH)
YAML-наброски развёртывания медиа-компонентов для PIN. Вынесено из jitsi-deployment.md
(там — топология, env-матрица, prosody/jicofo-конфиги, сеть/секреты), чтобы держать оба документа обозримыми.
Это иллюстративные наброски, не production-чарт: показывают форму (реплики, порты, тома, права), а не
полный values.yaml. Right-sized под ADR-0056 (1–10k активных, конференции редки). Секреты — из vault
(External Secrets/CSI), в манифесте — только ссылки на secretKeyRef.
Обзор
| Компонент | Kind | Реплики | Публичная точка | Особенности |
|---|---|---|---|---|
| prosody | Deployment + ConfigMap + Secret | 1 (HA 2, sticky) | — (за ingress) | кастомные модули, JWT-секрет |
| jicofo | Deployment + ConfigMap | 1 | — | override jicofo.conf |
| JVB | Deployment + Service(UDP) + HPA | 1–2 | UDP 10000 hostPort/LB | DOCKER_HOST_ADDRESS = публичный IP |
| jibri | Deployment | 0–2 | — | emptyDir /mnt/recordings, SYS_ADMIN, shm 2Gi |
| coturn | Deployment + Service(LB) | 1–2 | 443 tcp+udp | static-auth-secret, TLS |
| ingress | Ingress (TLS 443) | — | wss://<domain>/xmpp-websocket | → prosody 5280 |
prosody
Несёт кастомные PIN-модули (mod_pin_muc_presence.lua + vhost-конфиг) через ConfigMap; JWT/webhook-секреты —
из Secret. Комнаты — in-memory, поэтому sticky-балансировка при HA.
apiVersion: apps/v1
kind: Deployment
metadata: { name: jitsi-prosody, namespace: media }
spec:
replicas: 1 # HA: 2 + sticky (по XMPP-сессии)
selector: { matchLabels: { app: jitsi-prosody } }
template:
metadata: { labels: { app: jitsi-prosody } }
spec:
containers:
- name: prosody
image: jitsi/prosody:stable # + слой с mod_pin_muc_presence.lua
ports: [ { containerPort: 5222 }, { containerPort: 5280 } ]
envFrom: [ { configMapRef: { name: jitsi-prosody-env } } ]
env:
- name: JWT_APP_SECRET
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: jwt-app-secret } }
- name: JITSI_WEBHOOK_TOKEN
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: webhook-token } }
volumeMounts:
- { name: pin-modules, mountPath: /prosody-plugins-custom } # mod_pin_muc_presence.lua
- { name: vhost-cfg, mountPath: /config/conf.d } # main-vhost .cfg.lua
readinessProbe: { tcpSocket: { port: 5222 }, initialDelaySeconds: 10 }
livenessProbe: { tcpSocket: { port: 5222 }, periodSeconds: 15 }
volumes:
- { name: pin-modules, configMap: { name: jitsi-prosody-modules } }
- { name: vhost-cfg, configMap: { name: jitsi-prosody-vhost } }
---
apiVersion: v1
kind: ConfigMap
metadata: { name: jitsi-prosody-env, namespace: media }
data: # см. env-матрицу в jitsi-deployment.md
ENABLE_AUTH: "1"
AUTH_TYPE: "jwt"
JWT_APP_ID: "pin_messenger"
XMPP_DOMAIN: "media.pin.ru"
XMPP_AUTH_DOMAIN: "auth.media.pin.ru"
XMPP_MUC_DOMAIN: "conference.media.pin.ru"
XMPP_INTERNAL_MUC_DOMAIN: "internal.auth.media.pin.ru"
XMPP_RECORDER_DOMAIN: "recorder.media.pin.ru"
---
apiVersion: v1
kind: Secret # смонтирован из vault; здесь — форма
metadata: { name: jitsi-secrets, namespace: media }
type: Opaque
stringData:
jwt-app-secret: "<vault>"
webhook-token: "<vault>"
jitsi-prosody-modules несёт mod_pin_muc_presence.lua, jitsi-prosody-vhost — main-vhost .cfg.lua
(jitsi-deployment.md, sketch prosody). Ingress ниже терминирует TLS и проксирует
websocket на 5280.
jicofo
Override-jicofo.conf (brewery-jid + moderator-checks) кладётся ConfigMap-ом; focus-пароль — из Secret.
apiVersion: apps/v1
kind: Deployment
metadata: { name: jitsi-jicofo, namespace: media }
spec:
replicas: 1 # одна на кластер
selector: { matchLabels: { app: jitsi-jicofo } }
template:
metadata: { labels: { app: jitsi-jicofo } }
spec:
containers:
- name: jicofo
image: jitsi/jicofo:stable
env:
- { name: XMPP_AUTH_DOMAIN, value: "auth.media.pin.ru" }
- { name: JICOFO_AUTH_USER, value: "focus" }
- name: JICOFO_AUTH_PASSWORD
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: jicofo-auth-password } }
volumeMounts:
- { name: jicofo-override, mountPath: /config/jicofo.conf, subPath: jicofo.conf }
readinessProbe: { httpGet: { path: /about/health, port: 8888 } }
volumes:
- { name: jicofo-override, configMap: { name: jitsi-jicofo-conf } } # brewery-jid, enable-moderator-checks
JVB (SFU)
Публичный UDP 10000 — hostPort (или Service type=LoadBalancer c UDP). DOCKER_HOST_ADDRESS = публичный
IP ноды (кандидат ICE). HPA по CPU — под редкие пики конференций.
apiVersion: apps/v1
kind: Deployment
metadata: { name: jitsi-jvb, namespace: media }
spec:
replicas: 1
selector: { matchLabels: { app: jitsi-jvb } }
template:
metadata: { labels: { app: jitsi-jvb } }
spec:
containers:
- name: jvb
image: jitsi/jvb:stable
ports:
- { name: media, containerPort: 10000, protocol: UDP, hostPort: 10000 }
env:
- { name: JVB_AUTH_USER, value: "jvb" }
- name: JVB_AUTH_PASSWORD
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: jvb-auth-password } }
- name: DOCKER_HOST_ADDRESS # публичный IP ноды (ICE)
valueFrom: { fieldRef: { fieldPath: status.hostIP } } # либо явный external-IP
readinessProbe: { httpGet: { path: /about/health, port: 8080 } }
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: jitsi-jvb, namespace: media }
spec:
scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: jitsi-jvb }
minReplicas: 1
maxReplicas: 2 # ADR-0056: конференции редки
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } }
При hostPort UDP-порт per-node уникален — на одной ноде один JVB (или разные внешние порты). Альтернатива —
Service type=LoadBalancer c protocol: UDP и externalTrafficPolicy: Local (сохранение source-IP для ICE).
jibri
Записывающий под: emptyDir под /mnt/recordings (запись эфемерна — после ingest удаляется), SYS_ADMIN
для headless-Chrome, 2Gi shm. Реплики 0–2 по числу параллельных записей. Образ несёт pin_finalize.sh
(jitsi-modifications.md).
apiVersion: apps/v1
kind: Deployment
metadata: { name: jitsi-jibri, namespace: media }
spec:
replicas: 1 # 0..2 (1 запись на инстанс)
selector: { matchLabels: { app: jitsi-jibri } }
template:
metadata: { labels: { app: jitsi-jibri } }
spec:
containers:
- name: jibri
image: pin/jibri:stable # jitsi/jibri + /usr/bin/pin_finalize.sh
securityContext: { capabilities: { add: [ "SYS_ADMIN" ] } }
env:
- { name: ENABLE_RECORDING, value: "true" }
- { name: JIBRI_FINALIZE_RECORDING_SCRIPT_PATH, value: "/usr/bin/pin_finalize.sh" }
- { name: JIBRI_RECORDING_DIR, value: "/mnt/recordings" }
- { name: JIBRI_USAGE_TIMEOUT, value: "61 minutes" }
- { name: XMPP_RECORDER_DOMAIN, value: "recorder.media.pin.ru" }
- { name: XMPP_INTERNAL_MUC_DOMAIN, value: "internal.auth.media.pin.ru" }
- name: JIBRI_RECORDER_PASSWORD
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: jibri-recorder-password } }
- name: JIBRI_XMPP_PASSWORD
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: jibri-xmpp-password } }
- name: JITSI_WEBHOOK_TOKEN # для pin_finalize.sh (ingest)
valueFrom: { secretKeyRef: { name: jitsi-secrets, key: webhook-token } }
volumeMounts:
- { name: recordings, mountPath: /mnt/recordings }
- { name: shm, mountPath: /dev/shm }
readinessProbe: { httpGet: { path: /jibri/api/v1.0/health, port: 2222 } }
volumes:
- { name: recordings, emptyDir: {} } # эфемерно (после ingest rm -rf)
- { name: shm, emptyDir: { medium: Memory, sizeLimit: 2Gi } }
emptyDir достаточно: pin_finalize.sh при 2xx от messenger удаляет директорию, долговременное
хранилище — file storage (recording-pipeline.md). PV нужен лишь если требуется
переживать рестарт пода при незавершённой выгрузке — вне MVP.
coturn
Публичный 443 (tcp+udp) через LoadBalancer; static-auth-secret и TLS-серт — из vault.
apiVersion: apps/v1
kind: Deployment
metadata: { name: jitsi-coturn, namespace: media }
spec:
replicas: 1
selector: { matchLabels: { app: jitsi-coturn } }
template:
metadata: { labels: { app: jitsi-coturn } }
spec:
containers:
- name: coturn
image: coturn/coturn:4.6.3
args: [ "-c", "/local/coturn.conf" ]
ports: [ { containerPort: 443, protocol: TCP }, { containerPort: 443, protocol: UDP } ]
volumeMounts:
- { name: coturn-conf, mountPath: /local/coturn.conf, subPath: coturn.conf }
- { name: tls, mountPath: /secrets, readOnly: true }
volumes:
- { name: coturn-conf, configMap: { name: jitsi-coturn-conf } } # realm, use-auth-secret
- { name: tls, secret: { secretName: jitsi-coturn-tls } }
---
apiVersion: v1
kind: Service
metadata: { name: jitsi-coturn, namespace: media }
spec:
type: LoadBalancer
externalTrafficPolicy: Local # сохранить source-IP
selector: { app: jitsi-coturn }
ports:
- { name: turns-tcp, port: 443, protocol: TCP }
- { name: turns-udp, port: 443, protocol: UDP }
coturn.conf — из nomad/coturn.hcl (denied-peer-ip, no-tlsv1*, static-auth-secret, realm); секрет и
серты в манифесте лишь ссылками.
ingress
TLS-терминация 443 → prosody websocket (5280, /xmpp-websocket). Медиа (UDP 10000) и TURN (443) минуют
ingress — идут напрямую на JVB/coturn.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jitsi-signaling
namespace: media
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # долгие wss
spec:
tls: [ { hosts: [ "media.pin.ru" ], secretName: jitsi-signaling-tls } ]
rules:
- host: media.pin.ru
http:
paths:
- path: /xmpp-websocket
pathType: Prefix
backend: { service: { name: jitsi-prosody, port: { number: 5280 } } }
Обратные ссылки
Автоссылки: где используется этот документ.
- calls (3): Медиа-звонки и запись на Jitsi — интеграционный гид (messenger), Jitsi: инвентарь изменений в thirdparty/jitsi, Jitsi: k8s-топология и взаимодействие с бэкендом
Связанные документы
- Топология/env/сеть/секреты: jitsi-deployment.md; изменения (модуль/скрипт): jitsi-modifications.md; запись: recording-pipeline.md; гид: README.md.
- Референс-IaC (Nomad):
thirdparty/jitsi/infra-provisioning/nomad/{jibri,coturn}.hcl— источник env/портов. - Решения: ADR-0062, ADR-0056 simplicity-first.