Настройка переменных в Helm chart
Для запуска ВКС в K8s используется менеджер пакетов Helm. Перед запуском Helm необходимо изменить значения переменных (Секретов, Доменных имен и IP адресов) в файле values.yaml.
# Images
jicofoImage: docker.1forma.ru/1f-meet/jicofo:latest
jvbImage: docker.1forma.ru/1f-meet/jvb:latest
prosodyImage: docker.1forma.ru/1f-meet/prosody:latest
webImage: docker.1forma.ru/1f-meet/web:v4
jibriImage: docker.1forma.ru/1f-meet/jibri:latest
# 1Forma Domain Names
domainName: 1f-meet
formaDomainName: 1f
# Web Settings
tlsCertBase64: <CertBase64>
tlsKeyBase64: <KeyBase64>
# XMPP Server URL
xmppServer: prosody.default.svc.cluster.local
# JVB Settings
advertiseIpList: 192.168.1.1
jvbPort: 10000
# Records Settings
formaRecordApi: "/app/v1.2/api/publications/action/conference-records"
recordPath: "/records/"
recordResolution: "1920x1080"
# Secrets
formaApiSecret:
formaRecordSecret:
jwtAppSecret:
jibriRecorderPassword:
jbvAuthPassword:
jicofoAuthPassword:
jigasiXmppPassword:
jibriXmppPassword:
|
Измените переменные:
# Доменное имя приложения ВКС
domainName: forma-meet.domain.ru
# Доменное имя приложения Первая Форма
formaDomainName: forma.domain.ru
# Название, которое получит сервис Prosody. В данном примере используется default namespace
xmppServer: prosody.default.svc.cluster.local
# Значение advertiseIpList - список IP адресов (через запятую) по которым будут формироваться ICE PAIRS
advertiseIpList: X.X.X.X
# Значение UDP порта для WebRTC
jvbPort: 10000
# SSL/TLS сертификат и приватный ключ в кодировке base64 (ingress)
tlsCertBase64:
tlsKeyBase64:
# Секреты
formaApiSecret: SECRET
formaRecordSecret: SECRET
jwtAppSecret: SECRET
jibriRecorderPassword: SECRET
jbvAuthPassword: SECRET
jicofoAuthPassword: SECRET
jigasiXmppPassword: SECRET
jibriXmppPassword: SECRET
Для генерации Секретов можно воспользоваться скриптом gen-passwords.sh.
#!/usr/bin/env bash
function generatePassword() {
openssl rand -hex 16
}
jicofoAuthPassword=$(generatePassword)
jbvAuthPassword=$(generatePassword)
jigasiXmppPassword=$(generatePassword)
jibriRecorderPassword=$(generatePassword)
jibriXmppPassword=$(generatePassword)
jwtAppSecret=$(generatePassword)
formaRecordSecret=$(generatePassword)
formaApiSecret=$(generatePassword)
sed -i.bak \
-e "s#jicofoAuthPassword: .*#jicofoAuthPassword: ${jicofoAuthPassword}#g" \
-e "s#jbvAuthPassword: .*#jbvAuthPassword: ${jbvAuthPassword}#g" \
-e "s#jigasiXmppPassword: .*#jigasiXmppPassword: ${jigasiXmppPassword}#g" \
-e "s#jibriRecorderPassword: .*#jibriRecorderPassword: ${jibriRecorderPassword}#g" \
-e "s#jibriXmppPassword: .*#jibriXmppPassword: ${jibriXmppPassword}#g" \
-e "s#jwtAppSecret: .*#jwtAppSecret: ${jwtAppSecret}#g" \
-e "s#formaRecordSecret: .*#formaRecordSecret: ${formaRecordSecret}#g" \
-e "s#formaApiSecret: .*#formaApiSecret: ${formaApiSecret}#g" \
"$(dirname "$0")/values.yaml"
echo "JWT SECRET: ${formaRecordSecret}"
echo "FORMA API SECRET: ${formaApiSecret}"
echo "FORMA RECORD SECRET: ${formaRecordSecret}"
|
После запуска в values.yml значения Секретов обновятся автоматически.
Шаблоны yml-файлов:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy:
type: Recreate
template:
metadata:
labels:
app: web
spec:
containers:
- env:
- name: DEFAULT_LANGUAGE
value: ru
- name: DISABLE_AUDIO_LEVELS
value: "1"
- name: DISABLE_DEEP_LINKING
value: "true"
- name: DISABLE_LOCAL_RECORDING
value: "true"
- name: ENABLE_AUTH
value: "1"
- name: ENABLE_BREAKOUT_ROOMS
value: "1"
- name: ENABLE_CALENDAR
value: "1"
- name: ENABLE_CLOSE_PAGE
value: "0"
- name: ENABLE_FILE_RECORDING_SHARING
value: "true"
- name: ENABLE_GUESTS
value: "1"
- name: ENABLE_HTTP_REDIRECT
value: "0"
- name: ENABLE_IPV6
value: "false"
- name: ENABLE_LETSENCRYPT
value: "0"
- name: LETSENCRYPT_DOMAIN
value:
- name: LETSENCRYPT_EMAIL
value:
- name: LETSENCRYPT_USE_STAGING
value: "0"
- name: ENABLE_LIVESTREAMING
value: "true"
- name: ENABLE_NOISY_MIC_DETECTION
value: "1"
- name: ENABLE_P2P
value: "false"
- name: ENABLE_PREJOIN_PAGE
value: "0"
- name: ENABLE_RECORDING
value: "true"
- name: ENABLE_REQUIRE_DISPLAY_NAME
value: "1"
- name: ENABLE_SIMULCAST
value: "false"
- name: ENABLE_STEREO
value: "false"
- name: ENABLE_WELCOME_PAGE
value: "0"
- name: FORMA_API_SECRET
value: {{ .Values.formaApiSecret }}
- name: FORMA_DOMAIN_NAME
value: {{ .Values.formaDomainName }}
- name: JIBRI_RECORDING_DIR
value: {{ .Values.recordPath }}
- name: PUBLIC_URL
value: https://{{ .Values.domainName }}
- name: START_WITH_AUDIO_MUTED
value: "true"
- name: START_WITH_VIDEO_MUTED
value: "true"
- name: TZ
value: Europe/Moscow
- name: WHITEBOARD_ENABLED
value: "false"
- name: XMPP_AUTH_DOMAIN
value: auth.{{ .Values.domainName }}
- name: XMPP_BOSH_URL_BASE
value: "http://{{ .Values.xmppServer }}:5280"
- name: XMPP_DOMAIN
value: {{ .Values.domainName }}
- name: XMPP_GUEST_DOMAIN
value: guest.{{ .Values.domainName }}
- name: XMPP_MUC_DOMAIN
value: muc.{{ .Values.domainName }}
- name: XMPP_PORT
value: "5222"
- name: XMPP_RECORDER_DOMAIN
value: recorder.{{ .Values.domainName }}
image: {{ .Values.webImage }}
name: web
ports:
- containerPort: 80
protocol: TCP
- containerPort: 443
protocol: TCP
imagePullPolicy: Always
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
namespace: default
spec:
type: ClusterIP
ports:
- name: "80"
port: 80
targetPort: 80
- name: "443"
port: 443
targetPort: 443
selector:
app: web
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: prosody
labels:
app: prosody
spec:
replicas: 1
selector:
matchLabels:
app: prosody
template:
metadata:
labels:
app: prosody
spec:
containers:
- env:
- name: AUTH_TYPE
value: jwt
- name: ENABLE_AUTH
value: "1"
- name: ENABLE_BREAKOUT_ROOMS
value: "1"
- name: ENABLE_END_CONFERENCE
value: "true"
- name: ENABLE_GUESTS
value: "1"
- name: ENABLE_IPV6
value: "false"
- name: ENABLE_LOBBY
value: "1"
- name: ENABLE_RECORDING
value: "true"
- name: JIBRI_RECORDER_PASSWORD
value: {{ .Values.jibriRecorderPassword }}
- name: JIBRI_RECORDER_USER
value: recorder
- name: JIBRI_XMPP_PASSWORD
value: {{ .Values.jibriXmppPassword }}
- name: JIBRI_XMPP_USER
value: jibri
- name: JICOFO_AUTH_PASSWORD
value: {{ .Values.jicofoAuthPassword }}
- name: JIGASI_XMPP_PASSWORD
value: {{ .Values.jvbAuthPassword }}
- name: JVB_AUTH_PASSWORD
value: {{ .Values.jbvAuthPassword }}
- name: JVB_AUTH_USER
value: jvb
- name: JWT_ALLOW_EMPTY
value: "1"
- name: JWT_APP_ID
value: jitsi1f
- name: JWT_APP_SECRET
value: {{ .Values.jwtAppSecret }}
- name: PUBLIC_URL
value: https://{{ .Values.domainName }}
- name: TZ
value: Europe/Moscow
- name: XMPP_AUTH_DOMAIN
value: auth.{{ .Values.domainName }}
- name: XMPP_DOMAIN
value: {{ .Values.domainName }}
- name: XMPP_GUEST_DOMAIN
value: guest.{{ .Values.domainName }}
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.{{ .Values.domainName }}
- name: XMPP_MODULES
value: muc_size
- name: XMPP_MUC_DOMAIN
value: muc.{{ .Values.domainName }}
- name: XMPP_MUC_MODULES
value: token_moderation,muc_size,save_room_settings
- name: XMPP_PORT
value: "5222"
- name: XMPP_RECORDER_DOMAIN
value: recorder.{{ .Values.domainName }}
image: {{ .Values.prosodyImage }}
name: prosody
ports:
- containerPort: 5222
- containerPort: 5347
- containerPort: 5280
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: prosody
spec:
selector:
app: prosody
ports:
- name: "5222"
port: 5222
targetPort: 5222
- name: "5347"
port: 5347
targetPort: 5347
- name: "5280"
port: 5280
targetPort: 5280
|
apiVersion: apps/v1
kind: Deployment
metadata:
name: jvb
labels:
app: jvb
spec:
replicas: 1
selector:
matchLabels:
app: jvb
template:
metadata:
labels:
app: jvb
spec:
containers:
- env:
- name: JVB_ADVERTISE_IPS
value: {{ .Values.advertiseIpList }}
- name: JVB_AUTH_PASSWORD
value: {{ .Values.jbvAuthPassword }}
- name: JVB_AUTH_USER
value: jvb
- name: JVB_BREWERY_MUC
value: jvbbrewery
- name: JVB_DISABLE_STUN
value: "true"
- name: JVB_PORT
value: "{{ .Values.jvbPort }}"
- name: PUBLIC_URL
value: https://{{ .Values.domainName }}
- name: SENTRY_DSN
value: '"0"'
- name: TZ
value: Europe/Moscow
- name: XMPP_AUTH_DOMAIN
value: auth.{{ .Values.domainName }}
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.{{ .Values.domainName }}
- name: XMPP_PORT
value: "5222"
- name: XMPP_SERVER
value: {{ .Values.xmppServer }}
image: {{ .Values.jvbImage }}
name: jvb
ports:
- containerPort: {{ .Values.jvbPort }}
protocol: UDP
- containerPort: 8080
protocol: TCP
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: jvb
labels:
app: jvb
spec:
selector:
app: jvb
ports:
- name: udp
protocol: UDP
port: {{ .Values.jvbPort }}
targetPort: {{ .Values.jvbPort }}
type: LoadBalancer
sessionAffinity: None
status:
loadBalancer: {}
|
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: jicofo
name: jicofo
spec:
replicas: 1
selector:
matchLabels:
app: jicofo
strategy:
type: Recreate
template:
metadata:
labels:
app: jicofo
spec:
containers:
- env:
- name: AUTH_TYPE
value: jwt
- name: ENABLE_AUTH
value: "1"
- name: ENABLE_RECORDING
value: "true"
- name: JIBRI_BREWERY_MUC
value: jibribrewery
- name: JIBRI_PENDING_TIMEOUT
value: "90"
- name: JICOFO_AUTH_PASSWORD
value: {{ .Values.jicofoAuthPassword }}
- name: JICOFO_ENABLE_HEALTH_CHECKS
value: "false"
- name: JVB_BREWERY_MUC
value: jvbbrewery
- name: SENTRY_DSN
value: '"0"'
- name: TZ
value: Europe/Moscow
- name: XMPP_AUTH_DOMAIN
value: auth.{{ .Values.domainName }}
- name: XMPP_DOMAIN
value: {{ .Values.domainName }}
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.{{ .Values.domainName }}
- name: XMPP_MUC_DOMAIN
value: muc.{{ .Values.domainName }}
- name: XMPP_PORT
value: "5222"
- name: XMPP_RECORDER_DOMAIN
value: recorder.{{ .Values.domainName }}
- name: XMPP_SERVER
value: {{ .Values.xmppServer }}
image: {{ .Values.jicofoImage }}
name: jicofo
ports:
- containerPort: 8888
protocol: TCP
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
labels:
app: jicofo
name: jicofo
namespace: default
spec:
ports:
- name: "8888"
port: 8888
targetPort: 8888
selector:
app: jicofo
|
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kompose.cmd: kompose convert -f docker-compose-resolved.yaml
kompose.version: 1.30.0 (HEAD)
creationTimestamp: null
labels:
io.kompose.service: jibri
name: jibri
namespace: default
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: jibri
strategy:
type: Recreate
template:
metadata:
annotations:
kompose.cmd: kompose convert -f docker-compose-resolved.yaml
kompose.version: 1.30.0 (HEAD)
creationTimestamp: null
labels:
io.kompose.network/yml-default: "true"
io.kompose.service: jibri
spec:
containers:
- env:
- name: CHROMIUM_FLAGS
value: --use-fake-ui-for-media-stream, --start-maximized, --kiosk, --enabled, --disable-infobars, --autoplay-policy=no-user-gesture-required, --user-agent="Jibri Chrome/109.0.1.1 "
- name: DISPLAY
value: :0
- name: FORMA_DOMAIN_NAME
value: {{ .Values.formaDomainName }}
- name: FORMA_RECORD_PUBLICATION
value: {{ .Values.formaRecordApi }}
- name: FORMA_RECORD_SECRET
value: {{ .Values.formaRecordSecret }}
- name: JIBRI_BREWERY_MUC
value: jibribrewery
- name: JIBRI_FINALIZE_RECORDING_SCRIPT_PATH
value: /etc/jitsi/jibri/finalize.sh
- name: JIBRI_RECORDER_PASSWORD
value: {{ .Values.jibriRecorderPassword }}
- name: JIBRI_RECORDER_USER
value: recorder
- name: JIBRI_RECORDING_DIR
value: {{ .Values.recordPath }}
- name: JIBRI_RECORDING_RESOLUTION
value: {{ .Values.recordResolution }}
- name: JIBRI_STRIP_DOMAIN_JID
value: muc
- name: JIBRI_XMPP_PASSWORD
value: {{ .Values.jibriXmppPassword }}
- name: JIBRI_XMPP_USER
value: jibri
- name: PUBLIC_URL
value: https://{{ .Values.domainName }}
- name: TZ
value: Europe/Moscow
- name: XMPP_AUTH_DOMAIN
value: auth.{{ .Values.domainName }}
- name: XMPP_DOMAIN
value: {{ .Values.domainName }}
- name: XMPP_INTERNAL_MUC_DOMAIN
value: internal-muc.{{ .Values.domainName }}
- name: XMPP_MUC_DOMAIN
value: muc.{{ .Values.domainName }}
- name: XMPP_PORT
value: "5222"
- name: XMPP_RECORDER_DOMAIN
value: recorder.{{ .Values.domainName }}
- name: XMPP_SERVER
value: {{ .Values.xmppServer }}
image: {{ .Values.jibriImage }}
name: jibri
securityContext:
capabilities:
add:
- SYS_ADMIN
imagePullSecrets:
- name: regcred
|
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: 1forma-ingress
spec:
ingressClassName: nginx
rules:
- host: {{ .Values.domainName }}
http:
paths:
- pathType: Prefix
backend:
service:
name: web
port:
number: 80
path: /
tls:
- hosts:
- {{ .Values.domainName }}
secretName: 1forma-tls
---
apiVersion: v1
kind: Secret
metadata:
name: 1forma-tls
data:
tls.crt: {{ .Values.tlsCertBase64 }}
tls.key: {{ .Values.tlsKeyBase64 }}
type: kubernetes.io/tls
|
Если по какой-то причине у вас нет возможности использовать Helm в вашем K8s, вы можете отредактировать yaml-файлы и работать с ними как с классическими манифестами. Для этого замените значения {{ .Values. }} на значения переменных в файле values.yaml.
Обратите внимание: в параметре advertiseIpList необходимо через запятую передать список IP адресов для формирования ICE Candidate pair в WebRTC. Как правило, это Real IP с которого проброшен 10000/UDP порт или локальный адрес Ноды.
Необходимо пробросить порт 10000 к поду JVB. В настройках нашей конфигурации мы используем сервис JVB типа Load Balancer с возможностью балансировки UDP. Для вашей конфигурации можно использовать NodePort. Описание сервиса JVB находится в файле 1f-meet-jvb.yaml (см. шаблоны выше). Доступ по протоколам HTTP/HTTPS осуществляется через Ingress, который в нашей конфигурации реализован с использованием Ingress Nginx.
Установка ВКС
Запустите команду для установки и настройки ВКС:
helm install 1f-meet 1f-meet-k8s/
Настройте сервис в приложении Первая Форма
В режиме администрирования Первой Формы перейдите в раздел "Сервисы".
Список сервисов
Если в списке существубщих сервисов есть сервис с типом "ВКС", перейдите к его настройкам. Если такого сервиса нет, создайте его по кнопке "Добавить сервис".
Окно добавления сервиса ВКС
Заполните настройки сервиса:
•Сервис: ВКС.
•Описание: Имя сервиса ВКС.
•Домен: Доменное имя сервиса ВКС.
•Секретный ключ: Значение jwtAppSecret переменной из предыдущего шага.
•Operation Address: /app/v1.2/api/publications/action/conference-actions.
•Группа пользователей с комнатами: ID группы, для которых будет доступен сервис. Обычно это группа "Все пользователи".
•Префикс комнаты: Оставьте пустым.
•Смарт-фильтр проверки модератора: создайте новый фильтр. Задайте произвольное имя (например, ВКС модератор) Выберите тип TSQL.
Смарт-выражение:
select dbo.fnIsConferenceModerator(@eventParam1, @eventParam0)
Сохраните. Выберите созданный фильтр в настраиваемом сервисе.
•Расширенные настройки (json):
{"externalModuleKey":"formaApiSecret",
"roomCreationKey":"creationKey",
"recordHost":"https://records.domain.ru",
"recordsApiKey":"formaRecordSecret"}
где:
•roomCreationKey - Ключ, необходимый для работы плагина Outlook. Он служит для аутентификации плагина при генерации временной комнаты. Cгенерируйте случайное значение.
•externalModuleKey - Ключ для доступа к api модуля ВКС. Значение formaApiSecret.
•recordHost - Адрес хоста ссылок на записи ВКС.
•recordsApiKey - Ключ аутентификации для приема событий записи ВКС. Значение formaRecordSecret.
Сохраните настройки Сервиса.
Включите сервис ВКС в настройках приложения. Для этого перейдите в раздел "Общие настройки приложения".
Найдите пункт "ВКС" и в всплывающем меню выберите созданный сервис.
Выбор сервиса ВКС в общих настройках приложения
Сохраните изменения.