В данной статье будет показан процесс установки мессенджера Mattermost в связке с Jitsi для ВКС в самой простой, на мой взгляд, конфигурации в Kubernetes кластер.

Почему выбор пал именно на эти приложения:
- При необходимости все можно запустить в закрытом контуре
- Нет привязки к облачным провайдерам
Ну и главная причина, почему я начал все это настраивать:
- В моем конкретном случае связка Яндекс-Телемост/Мессенджер не позволяет аккаунтам из разных организаций Яндекс 360 работать в одном рабочем пространстве.
Обязательно уберу этот пункт, когда они исправятся :-)
- И пока что я не нашел подобной статьи на Хабре даже по отдельности :-)

Исходные данные:
- Kubernetes кластер (например yandex), c worker-нодами имеющими белый ip адрес (необходимо при работе в открытой сети Интернет).
- В кластере установлен nginx ingress controller, в статье класс определен как nginx-external
- В кластере установлен cert-manager для ssl
- Есть возможность настроить DNS записи для вашего домена
Установлен helm 3
- Есть доступ к S3 бакету (или его аналогу), известны accesskey и secretkey
- Установлена БД Postgresql, известны данные для подключения к БД c правами администратора. Связь между БД и Mattermost в данном примере без SSL.
- Есть доступ к кластеру через kubectl с правами администратора

Установка Jitsi

Скачать helm чарт

helm repo add jitsi https://jitsi-contrib.github.io/jitsi-helm/
helm pull jitsi/jitsi-meet

Скопировать values.yaml из чарта и переопределить параметры:
values-work.yaml:

enableAuth: true
enableGuests: true
# Where Jitsi Web UI is made available
# such as jitsi.example.com
publicURL: "meet.app-code.ru"

tz: Europe/Moscow

websockets:
  ## Colibri (JVB signalling):
  colibri:
    enabled: true
  ## XMPP (Prosody signalling):
  xmpp:
    enabled: true

web:
  extraEnvs:
    RESOLUTION: "720"
    RESOLUTION_MIN: "720"
    RESOLUTION_WIDTH: "1280"
    RESOLUTION_WIDTH_MIN: "1280"
    VIDEOQUALITY_PREFERRED_CODEC: VP9
    #https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-configuration/#videoquality
    VIDEOQUALITY_ENFORCE_PREFERRED_CODEC: "0" # 0 = fallback if some endpoints dont support, 1 = breaks receiving video for any endpoint that doesn't support preferred codec
    TART_BITRATE: "8000000" # 8000kbps
    #  START_AUDIO_MUTED
    #   value: "0" # if nth joiner, automute (user can toggle unmute) [moderator will only be muted AFTER first participant joins]
    #  START_VIDEO_MUTED
    #   value: "0" # if nth joiner, automute (user can toggle unmute) [moderator will only be muted AFTER first participant joins]
    # 0 = automute on join, user can toggle unmute #https://github.com/jitsi/jitsi-meet/issues/8144 (2021-Q1: pre-join page overrides start muted)
    START_WITH_AUDIO_MUTED: "1"
    # 0 = automute on join, user can toggle unmute #https://github.com/jitsi/jitsi-meet/issues/8144 (2021-Q1: pre-join page overrides start muted)
    # START_WITH_VIDEO_MUTED: "1"
    # 'distracting'
    ENABLE_NOISY_MIC_DETECTION: "false"
    ENABLE_NO_AUDIO_DETECTION: "true"
    TOOLBAR_BUTTONS: "microphone,camera,desktop,fullscreen,chat,recording,localrecording,settings,raisehand,filmstrip,invite,shortcuts,tileview,videobackgroundblur,download,help,hangup,select-background"

  ingress:
    enabled: true
    ingressClassName: "nginx-external"
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
    hosts:
    - host: meet.app-code.ru
      paths: ['/']
    tls:
      - secretName: jitsi-web-certificate
        hosts:
          - meet.app-code.ru
  nodeSelector:
    node-group: public


jicofo:
  xmpp:
    password: y7d75Aj2FSocL98V9wb6PXF5NzWw47ncscmYbwjgnEBYj9r7mP
  nodeSelector:
    node-group: public


jvb:
  xmpp:
    user: jvb
    password: upEH3JFsBHeFzQPirREWdT8c5CAHgzcma3ck5RpXg

  useNodeIP: true
  ## UDP transport port:
  UDPPort: 30000
  ## Use a pre-defined external port for NodePort or LoadBalancer service,
  #  if needed. Will allocate a random port from allowed range if unset.
  #  (Default NodePort range for K8s is 30000-32767)
  nodePort: 30000
  service:
    enabled: true
    type: NodePort
    externalTrafficPolicy: ~

  nodeSelector:
    node-group: public

extraCommonEnvs:
  XMPP_CROSS_DOMAIN: "true"
  AUTH_TYPE: "jwt"
  JWT_APP_ID: "jitsimeet"
  JWT_ALLOW_EMPTY: "false"

prosody:
  enabled: true
  persistence:
    enabled: true
    size: 4Gi
    storageClassName: yc-network-ssd
  extraEnvs:
  - name: JWT_APP_SECRET
    value: "e8pFe6QQYdwuVh6tEdxeFkMR9aFnTkCuWSfVurrQz"
  nodeSelector:
    node-group: public

Некоторые пояснения к содержимому:

publicURL - Урл по которому будет доступен Jitsi
web.extraEnvs - Параметры, которые на мой взгляд оптимальны для первого запуска
web.ingress.annotations - Необходимо указать параметры вашего cert-manager для запроса сертификата

В блоке jvb необходимые параметры, чтобы заработал UDP трафик при звонках. Важно так же понимать, что необходимо открыть указанные порты в Группах безопасности (фаервол), если это применимо к вашей инфраструктуре. Также указать nodeSelector если у вас отдельная группа нод с белыми IP адресами:

jvb:
  useNodeIP: true
  ## UDP transport port:
  UDPPort: 30000
  ## Use a pre-defined external port for NodePort or LoadBalancer service,
  #  if needed. Will allocate a random port from allowed range if unset.
  #  (Default NodePort range for K8s is 30000-32767)
  nodePort: 30000
  service:
    enabled: true
    type: NodePort
    externalTrafficPolicy: ~

  nodeSelector:
    node-group: public

Блок extraCommonEnvs включает авторизацию по JWT токену и задает App ID:

extraCommonEnvs:
  XMPP_CROSS_DOMAIN: "true"
  AUTH_TYPE: "jwt"
  JWT_APP_ID: "jitsimeet"
  JWT_ALLOW_EMPTY: "false"

В блоке prosody задается JWT токен:

prosody:
  enabled: true
  persistence:
    enabled: true
    size: 4Gi
    storageClassName: yc-network-ssd
  extraEnvs:
  - name: JWT_APP_SECRET
    value: "e8pFe6QQYdwuVh6tEdxeFkMR9aFnTkCuWSfVurrQz"

Параметры publicURL, extraCommonEnvs.JWT_APP_ID, prosody.extraEnvs.JWT_APP_SECRET будут ипользованы при настройке интеграции с mattermost

Все пароли и токены замените на свои!.

Установить jitsi:

helm -n jitsi-ext upgrade --install --create-namespace \
    jitsi \
    -f values-work.yaml \
    jitsi/jitsi-meet

Проверить, что все запущено, должно быть примерно такое состояние:

$ kubectl -n jitsi-ext get pods,service,ingress
NAME                                           READY   STATUS    RESTARTS   AGE
pod/jitsi-jitsi-meet-jicofo-86cb554b75-dnn6k   1/1     Running   0          49s
pod/jitsi-jitsi-meet-jvb-675db788db-2svt2      1/1     Running   0          49s
pod/jitsi-jitsi-meet-web-b677f9f88-wkszq       1/1     Running   0          49s
pod/jitsi-prosody-0                            1/1     Running   0          49s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                        AGE
service/jitsi-jitsi-meet-jvb   NodePort    10.21.90.27     <none>        30000:30000/UDP                                5d22h
service/jitsi-jitsi-meet-web   ClusterIP   10.21.189.115   <none>        80/TCP                                         5d22h
service/jitsi-prosody          ClusterIP   10.21.84.50     <none>        5280/TCP,5281/TCP,5347/TCP,5222/TCP,5269/TCP   5d22h

NAME                                             CLASS            HOSTS              ADDRESS           PORTS     AGE
ingress.networking.k8s.io/jitsi-jitsi-meet-web   nginx-external   meet.app-code.ru                     80, 443   25h

Установка Mattermost

Самый простой вариант, на мой взгляд, при установке Mattermost это использовать operator.

Добавить helm репозиторий:

helm repo add mattermost https://helm.mattermost.com

Установить оператор:

helm -n mattermost-operator upgrade --install --create-namespace \
    mattermost-operator \
    mattermost/mattermost-operator

Данные для подключения к БД нужно сформировать в определенном формате, так же нужны данные для подключения к S3, для этого можно использовать небольшой скрипт:

#!/bin/bash

### БД
username="mostuser"
password="password"
database="mattermost"
db_url="postgres.host"

url="postgres://${username}:${password}@${db_url}:5432/${database}?connect_timeout=10&sslmode=disable"

pg_url_base64=$(echo -n "${url}" | base64 -w0)

echo "pg_url_base64: ${pg_url_base64}"

### S3
accesskey="accesskey"
secretkey="secretkey"

accesskey_base64=$(echo -n "${accesskey}" | base64 -w0)
secretkey_base64=$(echo -n "${secretkey}" | base64 -w0)

echo "accesskey_base64: ${accesskey_base64}"
echo "secretkey_base64: ${secretkey_base64}"

Создать secret с данными для подключения к БД most-postgres-connection.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: most-postgres-connection
type: Opaque
data:
  DB_CONNECTION_CHECK_URL: <pg_url_base64>
  DB_CONNECTION_STRING: <pg_url_base64>
  MM_SQLSETTINGS_DATASOURCEREPLICAS: <pg_url_base64>

Создать secret с данными для подключения к S3 mattermost-filestore-secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: most-s3-sa-key
type: Opaque
data:
  accesskey: <accesskey_base64>
  secretkey: <secretkey_base64>

Создать yaml фаил с описанием mattermost.yaml:

apiVersion: installation.mattermost.com/v1beta1
kind: Mattermost
metadata:
  name: mattermost
spec:
  image: mattermost/mattermost-team-edition
  version: 10.1.2

  imagePullPolicy: Always
  licenseSecret: ""
  replicas: 1
  ingress:
    enabled: true
    host: most.app-code.ru
    annotations:
      kubernetes.io/ingress.class: nginx-external
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
      nginx.ingress.kubernetes.io/proxy-body-size: 500m
    tlsSecret: most.app-code.ru-tls

  database:
    external:
        secret: most-postgres-connection
  fileStore:
    external:
        url: s3.yandexcloud.net
        bucket: most-s3-bucket-test
        secret: most-s3-sa-key
  scheduling:
    nodeSelector:
        node-group: public

Установить все в кластер:

kubectl create ns mattermost
kubectl -n mattermost apply -f mattermost-filestore-secret.yaml
kubectl -n mattermost apply -f postgresql_conn_secret.yaml
kubectl -n mattermost apply -f mattermost.yaml

Проверить, что все запустилось:

$ kubectl -n mattermost get pods,ingress
NAME                             READY   STATUS    RESTARTS   AGE
pod/mattermost-6788fb845-frmfl   1/1     Running   0          8m7s

NAME                                   CLASS    HOSTS              ADDRESS           PORTS     AGE
ingress.networking.k8s.io/mattermost   <none>   most.app-code.ru                     80, 443   8m7s

Зайти через веб интерфейс, сделать начальные настройки.

Скачать архив с плагином Jitsi:

wget https://github.com/mattermost-community/mattermost-plugin-jitsi/releases/download/v2.0.1/jitsi-2.0.1.tar.gz

В системных настройках: System Console -> Plugin Managment загрузить скачанный архив:

Включить плагин и перейти в его настройки:

Внести настройки для связи с Jitsi, которые указывали ранее, это Jitsi URL, App ID и JWT токен:

Перейти в любой канал или персональный чат, справа на панели появится кнопка Jitsi:

Либо в любом диалоге вызвать командой /jitsi

Перейти по созданной ссылке, присоединиться к видео встрече:

Важно, при переходе по этой ссылке все получают права Модератора. Если считаете, что так не надо делать - не публикуйте эту ссылку, а приглашайте к конференции через кнопку приглашения:

Удачного пользования! :-)

Комментарии (5)


  1. chihca1488
    15.11.2024 17:52

    Благодарю за тутор!


    1. vsb2007 Автор
      15.11.2024 17:52

      Надеюсь, будет полезным :-)


  1. Maunty
    15.11.2024 17:52

    Немного офтопный вопрос, ММ стартует какое-то неприличное количество времени, поэтому есть некоторые опасения втыкать его в такую динамичную среду как k8s. Не сталкивались с подобным?


    1. vsb2007 Автор
      15.11.2024 17:52

      Здравствуйте!

      Нет, у меня стартует быстро, на мой взгляд...
      Буквально несколько секунд.
      Возможно вам стоит разобраться со стадиями старта, из личного опыта:
      - есть проблемы у облаков при скачивании образов как из публичных репозиториев типа hub.docker.io, так и из собственных - тот же яндекс из своих реджестри скачивает иногда очень медленно, при этом, если прибить под, то при рестарте скачается очень быстро.
      - есть проблема с тем, что pvc очень долго перецепляет с одной ноды на другую, но тут в MM я pvc не использую - все в S3.

      Сам старт пода ММ проходит максимально быстро.


      1. Maunty
        15.11.2024 17:52

        Мы буквально на днях обновляли кластер PG и после обновления ММ стартовал порядка 35 минут.

        P.S. для точности, контейнер/под то создается, от начала создания то момента когда сервер начинает слушать порт и отвечать на полезную нагрузку проходит неприлично много времени. Ну и если быть честными не исследовался этот вопрос как следует, видимо какая-то наша проблема и не является wellknow ошибкой.