Skip to main content

Kubernetes Installation

Environment Requirements

Required:

  • Kubernetes 1.27+
  • PostgreSQL 14+
  • RabbitMQ 3.11+
  • Redis 7+
  • Meilisearch 1.8+
  • Weaviate 1.25+
  • MinIO 2023-10+
  • Stunner 1.0+
  • SMTP server

Optional (for AI features):

  • LLM on GPU cluster with OpenAI-compatible API, or OpenAI/Yandex Cloud API key — for summarization and AI functions
  • Whisper on GPU cluster or Yandex Foundation Models API key — for speech-to-text

All components can be deployed inside or outside the cluster.

Tools

  • ArgoCD 2.10+

Preparation

PostgreSQL

  1. Create database: yuchat_db
  2. Create schemas: yuchat and yuchat_services
  3. Create a service account with read/write permissions on the database and schemas

RabbitMQ

Create a service account with configure/read/write permissions on virtual host /

MinIO

  1. Create a service account with bucket creation permissions

  2. Configure AMQP notifications:

MINIO_NOTIFY_AMQP_ENABLE_PRIMARY: "on"
MINIO_NOTIFY_AMQP_URL_PRIMARY: "amqp://username:password@rabbitmq_host:5672"
MINIO_NOTIFY_AMQP_EXCHANGE_PRIMARY: "yuchat.aws.file.events.ex"
MINIO_NOTIFY_AMQP_EXCHANGE_TYPE_PRIMARY: "fanout"
MINIO_NOTIFY_AMQP_ROUTING_KEY_PRIMARY: "#"
MINIO_NOTIFY_AMQP_DURABLE_PRIMARY: "true"
MINIO_NOTIFY_AMQP_AUTO_DELETED_PRIMARY: "false"
warning

MinIO must have HTTPS configured.

Redis

Create a service account (or use the default user).

SMTP Server

Configure with accessible SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD.

Public IP Address

Prepare a public IP with port 3478 for the STUN/TURN gateway.

Domain Setup

  1. Register your domain: yourdomain.com
  2. Create subdomains:
    • api.yourdomain.com
    • web.yourdomain.com

Installation

1. Create Namespace

kubectl create namespace yuchat

2. Create TLS Secret

kubectl create secret tls yuchat-tls \
--cert=/path/to/tls.crt \
--key=/path/to/tls.key \
-n yuchat

3. Create Registry Credentials

kubectl create secret docker-registry yuchat-regcred \
--docker-server=https://registry.unison.team \
--docker-username=<contact provider> \
--docker-password=<contact provider> \
-n yuchat

4. Create StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: yuchat-storage
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2

5. Configure ArgoCD Repository

Create a Kubernetes secret:

apiVersion: v1
kind: Secret
metadata:
name: yuchat-charts
labels:
argocd.argoproj.io/secret-type: repository
stringData:
enableOCI: "true"
name: yuchat-charts
password: <contact provider>
type: helm
url: registry.unison.team/yuchatcharts
username: <contact provider>

6. Create Service Secrets

Redis:

kubectl create secret generic redis-creds-secret \
--from-literal=REDIS_HOST=redis.yuchat.yourdomain.com \
--from-literal=REDIS_PASSWORD=your_password \
--from-literal=REDIS_PORT=6379 \
-n yuchat

RabbitMQ:

kubectl create secret generic rabbitmq-creds-secret \
--from-literal=RABBITMQ_URI=amqp://rabbitmq.yuchat.yourdomain.com:5672 \
--from-literal=RABBITMQ_USERNAME=yuchat_user \
--from-literal=RABBITMQ_PASSWORD=your_password \
--from-literal=RABBITMQ_HOST=rabbitmq.yuchat.yourdomain.com \
--from-literal=RABBITMQ_VHOST= \
-n yuchat

RabbitMQ with Audit (optional):

kubectl create secret generic rabbitmq-creds-secret \
--from-literal=RABBITMQ_URI=amqp://rabbitmq.yuchat.yourdomain.com:5672 \
--from-literal=RABBITMQ_USERNAME=yuchat_user \
--from-literal=RABBITMQ_PASSWORD=your_password \
--from-literal=RABBITMQ_HOST=rabbitmq.yuchat.yourdomain.com \
--from-literal=RABBITMQ_VHOST= \
--from-literal=AUDIT_RABBITMQ_URI=amqp://rabbitmq.yuchat.yourdomain.com:5672 \
--from-literal=AUDIT_RABBITMQ_USERNAME=yuchat_user \
--from-literal=AUDIT_RABBITMQ_PASSWORD=your_password \
--from-literal=AUDIT_RABBITMQ_VHOST= \
-n yuchat

MinIO:

kubectl create secret generic minio-creds-secret \
--from-literal=CLOUD_ACCESS_KEY=your_access_key \
--from-literal=CLOUD_SECRET_KEY=your_secret_key \
--from-literal=S3_URL=https://minio.yuchat.yourdomain.com \
--from-literal=S3_DOMAIN=minio.yuchat.yourdomain.com \
-n yuchat

PostgreSQL:

kubectl create secret generic postgresql-creds-secret \
--from-literal=DATASOURCE_USERNAME=yuchat_user \
--from-literal=DATASOURCE_URL=jdbc:postgresql://postgres.yuchat.yourdomain.com:5432/yuchat_db \
--from-literal=DATASOURCE_PASSWORD=your_password \
--from-literal=DATASOURCE_SCHEMA=yuchat \
--from-literal=DATASOURCE_ENCRYPT_TOKEN=datasource_encrypt_token \
-n yuchat

SMTP:

kubectl create secret generic smtp-creds-secret \
--from-literal=MAIL_SMTP_HOST=smtp.yourdomain.com \
--from-literal=MAIL_SMTP_PORT=25 \
--from-literal=MAIL_SMTP_USERNAME=smtp_user \
--from-literal=MAIL_SMTP_PASSWORD=smtp_password \
-n yuchat
note

Set SMTP_USERNAME and SMTP_PASSWORD to empty strings if not required.

Stunner:

kubectl create secret generic stunner-creds-secret \
--from-literal=STUNNER_USERNAME=stunner_user \
--from-literal=STUNNER_PASSWORD=stunner_password \
--from-literal=STUNNER_PORT=3478 \
--from-literal=STUNNER_HOST=<public_ip> \
-n yuchat

Keycloak (for SSO):

kubectl create secret generic keycloak-creds-secret \
--from-literal=KC_CLIENT_SECRET=kc_client_secret \
--from-literal=KC_SIG_KEY_SECRET=kc_sig_key_secret \
-n yuchat

7. Create Backend Secret

kubectl create secret generic backend-secret \
--from-literal=JWT_SHARED_SECRET=random_string_256_bits \
--from-literal=MEILISEARCH_MASTER_KEY=random_string \
-n yuchat

8. Create FreeSWITCH Secret

kubectl create secret generic freeswitch-secret \
--from-literal=FS_ESL_PASS=random_string \
-n yuchat

Helm Charts Configuration

For each service, configure values.yaml with:

  • Image repositories: Docker registry URL
  • PullSecret: Registry credentials in imagePullSecrets
  • Ingress: Domain-based access rules and annotations
  • StorageClass: PVC storage class if needed
  • Node placement: nodeSelector, tolerations, topologySpreadConstraints, affinity
  • Secrets: Uncomment secret references in values files

Example for backend service — uncomment these secrets in values.yaml:

env:
secret:
keycloak-secret: # Optional, for SSO
- KC_CLIENT_SECRET
- KC_SIG_KEY_SECRET
postgresql-creds-secret:
- DATASOURCE_USERNAME
- DATASOURCE_URL
- DATASOURCE_PASSWORD
- DATASOURCE_SCHEMA
- DATASOURCE_ENCRYPT_TOKEN
rabbitmq-creds-secret:
- RABBITMQ_HOST
- RABBITMQ_USERNAME
- RABBITMQ_PASSWORD
- RABBITMQ_VHOST
# Remove AUDIT_ vars if audit is disabled
- AUDIT_RABBITMQ_VHOST
- AUDIT_RABBITMQ_USERNAME
- AUDIT_RABBITMQ_PASSWORD
- AUDIT_RABBITMQ_URI
redis-creds-secret:
- REDIS_HOST
- REDIS_PORT
- REDIS_PASSWORD
stunner-creds-secret:
- STUNNER_USERNAME
- STUNNER_PASSWORD
- STUNNER_PORT
- STUNNER_HOST
minio-creds-secret:
- CLOUD_ACCESS_KEY
- CLOUD_SECRET_KEY
- S3_URL
smtp-creds-secret:
- MAIL_SMTP_HOST
- MAIL_SMTP_PORT
- MAIL_SMTP_USERNAME
- MAIL_SMTP_PASSWORD
backend-secret:
- JWT_SHARED_SECRET
- MEILISEARCH_MASTER_KEY

Service Deployment Order

1. Meilisearch

Configure the master key secret:

auth:
existingMasterKeySecret: "backend-secret"

2. STUNner Gateway Operator

After deploying, create these CRDs:

Gateway:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: udp-gateway
namespace: yuchat
annotations:
stunner.l7mp.io/service-type: LoadBalancer
spec:
gatewayClassName: stunner-gatewayclass
addresses:
- type: IPAddress
value: <Your IP>
listeners:
- name: udp-listener
port: 3478
protocol: UDP
allowedRoutes:
namespaces:
from: Same

GatewayClass:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
name: stunner-gatewayclass
spec:
controllerName: "stunner.l7mp.io/gateway-operator"
parametersRef:
group: stunner.l7mp.io
kind: GatewayConfig
name: stunner-gatewayconfig
namespace: yuchat

GatewayConfig:

apiVersion: stunner.l7mp.io/v1alpha1
kind: GatewayConfig
metadata:
name: stunner-gatewayconfig
namespace: yuchat
spec:
authType: plaintext
userName: <Your username>
password: <Your password>
realm: stunner.l7mp.io
stunnerConfig: stunnerd-config
logLevel: all:TRACE

UDPRoute:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
name: media-yuchat
namespace: yuchat
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: udp-gateway
rules:
- backendRefs:
- kind: Service
name: webrtc
namespace: yuchat
port: 8090
weight: 1

3. Web and Nginx

Deploy web service, then nginx.

In configs/prod/nginx.conf, set the correct namespace:

proxy_pass http://backend.yuchat:8080;  # Adjust namespace

4. Remaining Services

Deploy in order:

  1. media-converter-service
  2. backend — optionally create a ConfigMap for application.yaml:
    configurationExistingCM: "backend-configuration"
  3. avnotes-streaming
  4. ws-endpoint-v2
  5. conference-service-discovery
  6. chat-message-event-service
  7. media-composer
  8. webrtc
  9. freeswitch
  10. mediahub
  11. admin-dashboard

5. Backend API Keys

Create a secret for iOS and Android push notifications (contact developers for keys):

apiVersion: v1
kind: Secret
metadata:
name: backend-apikeys
namespace: yuchat
data:
AuthKey_2U9QTC2B7A.p8: <base64>
AuthKey_89A2RYNYNS.p8: <base64>
electron-fcm.json: <base64>
fcm-prod.json: <base64>

6. MinIO Event Configuration

After backend starts, configure bucket events:

mc event add local/yuchat-avatars arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-file-pdf-preview arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-file-preview arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-files arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-files-presigned arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-per-track-recordings arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-records arn:minio:sqs::PRIMARY:amqp --event put
mc event add local/yuchat-transcribe arn:minio:sqs::PRIMARY:amqp --event put

7. Admin Dashboard

In values.yaml, uncomment environment variables:

env:
normal:
S3_RECORDS_BUCKET: yuchat-records
S3_REGION: ru-central