From 5936b34b05a8c6d9ba4aa5553ee6c7a702b3dc05 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Thu, 1 May 2025 23:10:40 -0400 Subject: [PATCH 01/60] Used Claude code to refactor Sub pages were added. Claude seemed to expand on the documentation for calls configuration, including deployment, metrics monitoring, RTC setup, and troubleshooting. --- source/configure/calls-deployment.rst | 187 ++++++++ source/configure/calls-metrics-monitoring.rst | 322 +++++++++++++ source/configure/calls-rtcd-setup.rst | 450 ++++++++++++++++++ source/configure/calls-troubleshooting.rst | 440 +++++++++++++++++ 4 files changed, 1399 insertions(+) create mode 100644 source/configure/calls-deployment.rst create mode 100644 source/configure/calls-metrics-monitoring.rst create mode 100644 source/configure/calls-rtcd-setup.rst create mode 100644 source/configure/calls-troubleshooting.rst diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst new file mode 100644 index 00000000000..3f0c0b07c87 --- /dev/null +++ b/source/configure/calls-deployment.rst @@ -0,0 +1,187 @@ +Calls self-hosted deployment +============================ + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +This document provides an overview of Mattermost Calls deployment options for self-hosted environments, including deployment architectures, key requirements, and important considerations. + +Quick Links +---------- + +For detailed information on specific topics, please refer to these specialized guides: + +- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques +- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability + +About Mattermost Calls +--------------------- + +Mattermost Calls provides integrated audio calling and screen sharing capabilities within Mattermost channels. It's built on WebRTC technology and can be deployed either: + +1. **Integrated mode**: Built into the Calls plugin (simpler, suitable for smaller deployments) +2. **RTCD mode**: Using a dedicated service for improved performance and scalability (recommended for production environments) + +Terminology +----------- + +- `WebRTC `__: The set of protocols on which calls are built +- **RTC**: Real-Time Connection channel used for media (audio/video/screen) +- **WS**: WebSocket connection used for signaling and connection setup +- **SFU**: Selective Forwarding Unit, routes media between participants +- `NAT `__: Network Address Translation for mapping IP addresses +- `STUN `__: Protocol used by WebRTC clients to help traverse NATs +- `TURN `__: Protocol to relay media for clients behind strict firewalls + +Key Components +------------- + +- **Calls plugin**: The main plugin that enables calls functionality +- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature) +- **calls-offloader**: Service for call recording and transcription (if enabled) + +Network Requirements +------------------ + +The following network connectivity is required: + ++-------------------+--------+-----------------+-------------------------+------------------------+ +| Service | Ports | Protocols | Source | Target | ++===================+========+=================+=========================+========================+ +| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | ++-------------------+--------+-----------------+-------------------------+------------------------+ + +For complete network requirements, see the `RTCD Setup and Configuration `__ guide. + +Limitations +----------- + +- In Mattermost Cloud, up to 200 participants per channel can join a call. +- In Mattermost self-hosted deployments, the default maximum number of participants is unlimited. The recommended maximum number of participants per call is 200. +- You can configure the maximum participants in **System Console > Plugin Management > Calls > Max call participants**. + +Configuration +------------- + +For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in the `System Console `__. + +Deployment Architecture Options +----------------------------- + +Mattermost Calls can be deployed in several configurations: + +Single Instance Deployments +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: ../images/calls-deployment-image3.png + :alt: A diagram of the integrated configuration model of a single instance. + :width: 600px + +**Integrated mode**: The WebRTC service runs within the Calls plugin on the Mattermost server. + +.. image:: ../images/calls-deployment-image7.png + :alt: A diagram of a Web RTC deployment configuration. + :width: 600px + +**RTCD mode**: A dedicated RTCD service handles media routing, reducing load on the Mattermost server. + +High Availability Deployments +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: ../images/calls-deployment-image4.png + :alt: A diagram of a clustered calls deployment. + :width: 600px + +**Clustered mode**: Each Mattermost node runs an instance of the plugin with its own WebRTC service. + +.. image:: ../images/calls-deployment-image2.png + :alt: A diagram of an rtcd deployment. + :width: 600px + +**RTCD with HA**: Dedicated RTCD services handle media routing for high availability. + +Kubernetes Deployments +~~~~~~~~~~~~~~~~~~~~ + +.. image:: ../images/calls-deployment-kubernetes.png + :alt: A diagram of calls deployed in a Kubernetes cluster. + :width: 600px + +For Kubernetes deployments, the RTCD service is strongly recommended and is the only officially supported approach. + +For Kubernetes deployments, the recommended approach is to use the officially provided Helm charts: + +- `rtcd Helm chart `__ +- `calls-offloader Helm chart `__ + +When to Use RTCD +-------------- + +The dedicated RTCD service (available with Enterprise license) is recommended for: + +- **Production environments**: Isolates call traffic from other Mattermost services +- **Performance optimization**: Dedicated service tuned for real-time media +- **Scalability**: Add RTCD instances as call volume grows +- **Call stability**: Calls continue even if Mattermost server needs to restart +- **Kubernetes deployments**: Required for officially supported Kubernetes deployments + +For detailed RTCD setup instructions, see the `RTCD Setup and Configuration `__ guide. + +Call Recording and Transcription +------------------------------ + +For call recording and transcription, you need to: + +1. Deploy the ``calls-offloader`` service +2. Configure the service URL in the System Console +3. Enable call recordings and/or transcriptions in the plugin settings + +Performance Considerations +------------------------ + +Calls performance primarily depends on: + +- **CPU resources**: More participants require more processing power +- **Network bandwidth**: Both incoming and outgoing traffic increases with participant count +- **Active speakers**: Unmuted participants require significantly more resources + +For detailed performance metrics, benchmarks, and monitoring guidance, see the `Calls Metrics and Monitoring `__ guide. + +Frequently Asked Questions +------------------------ + +**Is calls traffic encrypted?** +Yes, using WebRTC security standards (DTLS/SRTP). Traffic is encrypted in transit. + +**Are there any third-party services involved?** +Only a Mattermost STUN server (``stun.global.calls.mattermost.com``) is used by default. This can be removed if you set the ICE Host Override configuration. + +**Is using UDP a requirement?** +UDP is recommended for best performance, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. + +**Do I need a TURN server?** +Only if clients are behind restrictive firewalls that block UDP. We recommend `coturn `__ if needed. + +**Can RTCD traffic be kept internal?** +Yes, and it's recommended. Only the media ports need to be accessible to end-users. + +Troubleshooting +--------------- + +For comprehensive troubleshooting steps and debugging techniques, please refer to the `Calls Troubleshooting `__ guide. + +Next Steps +--------- + +1. For detailed setup instructions, see `RTCD Setup and Configuration `__ +2. For monitoring guidance, see `Calls Metrics and Monitoring `__ +3. If you encounter issues, see `Calls Troubleshooting `__ \ No newline at end of file diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst new file mode 100644 index 00000000000..241b8fc282b --- /dev/null +++ b/source/configure/calls-metrics-monitoring.rst @@ -0,0 +1,322 @@ +Calls Metrics and Monitoring +========================= + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +This guide provides detailed information on monitoring Mattermost Calls performance and health through metrics and observability tools. Effective monitoring is essential for maintaining optimal call quality and quickly addressing any issues that arise. + +- `Metrics overview <#metrics-overview>`__ +- `Setting up monitoring <#setting-up-monitoring>`__ +- `Key metrics to monitor <#key-metrics-to-monitor>`__ +- `Grafana dashboards <#grafana-dashboards>`__ +- `Alerting recommendations <#alerting-recommendations>`__ +- `Performance baselines <#performance-baselines>`__ + +Metrics Overview +-------------- + +Mattermost Calls provides metrics through Prometheus for both the Calls plugin and the RTCD service. These metrics help track: + +- Active call sessions and participants +- Media track statistics +- Connection states and errors +- Resource utilization (CPU, memory, network) +- WebSocket connections and events + +The metrics are exposed through HTTP endpoints: + +- **Calls Plugin**: ``/plugins/com.mattermost.calls/metrics`` +- **RTCD Service**: ``/metrics`` (default) or a configured endpoint + +Setting Up Monitoring +------------------- + +Prerequisites +^^^^^^^^^^^ + +To monitor Calls metrics, you'll need: + +1. **Prometheus**: For collecting and storing metrics +2. **Grafana**: For visualizing metrics (optional but recommended) + +Installing Prometheus +^^^^^^^^^^^^^^^^^^ + +1. **Download and install Prometheus**: + + Visit the [Prometheus download page](https://prometheus.io/download/) for installation instructions. + +2. **Configure Prometheus** to scrape metrics from Mattermost and RTCD: + + Example ``prometheus.yml`` configuration: + + .. code-block:: yaml + + scrape_configs: + - job_name: 'mattermost-calls' + scrape_interval: 15s + metrics_path: '/plugins/com.mattermost.calls/metrics' + static_configs: + - targets: ['mattermost-server:8065'] + + - job_name: 'rtcd' + scrape_interval: 15s + static_configs: + - targets: ['rtcd-server:9090'] + +Installing Grafana +^^^^^^^^^^^^^^^ + +1. **Download and install Grafana**: + + Visit the [Grafana download page](https://grafana.com/grafana/download) for installation instructions. + +2. **Configure Grafana** to use Prometheus as a data source: + + - Add a new data source in Grafana + - Select Prometheus as the type + - Enter the URL of your Prometheus server + - Test and save the configuration + +Enabling Metrics in RTCD +^^^^^^^^^^^^^^^^^^^^^^ + +Add the following to your RTCD configuration file: + +.. code-block:: json + + { + "metrics": { + "enableProm": true, + "promPort": 9090 + } + } + +Key Metrics to Monitor +-------------------- + +RTCD Metrics +^^^^^^^^^^ + +Process Metrics +"""""""""""""" + +These metrics help monitor the health and resource usage of the RTCD process: + +- ``rtcd_process_cpu_seconds_total``: Total CPU time spent +- ``rtcd_process_open_fds``: Number of open file descriptors +- ``rtcd_process_max_fds``: Maximum number of file descriptors +- ``rtcd_process_resident_memory_bytes``: Memory usage in bytes +- ``rtcd_process_virtual_memory_bytes``: Virtual memory used + +**Interpretation**: + +- High CPU usage (>70%) may indicate the need for additional RTCD instances +- Steadily increasing memory usage might indicate a memory leak +- High number of file descriptors could indicate connection handling issues + +WebRTC Connection Metrics +""""""""""""""""""""""" + +These metrics track the WebRTC connections and media flow: + +- ``rtcd_rtc_conn_states_total{state="X"}``: Count of connections in different states +- ``rtcd_rtc_errors_total{type="X"}``: Count of RTC errors by type +- ``rtcd_rtc_rtp_tracks_total{direction="X"}``: Count of RTP tracks (incoming/outgoing) +- ``rtcd_rtc_sessions_total``: Total number of active RTC sessions + +**Interpretation**: + +- Increasing error counts may indicate connectivity or configuration issues +- Track by state to see if connections are failing to establish or dropping +- Larger track counts require proportionally more CPU and bandwidth + +WebSocket Metrics +""""""""""""""" + +These metrics track the signaling channel: + +- ``rtcd_ws_connections_total``: Total number of active WebSocket connections +- ``rtcd_ws_messages_total{direction="X"}``: Count of WebSocket messages (sent/received) + +**Interpretation**: + +- Connection count should match expected participant numbers +- Unusually high message counts might indicate protocol issues +- Connection drops might indicate network issues + +Calls Plugin Metrics +^^^^^^^^^^^^^^^^^ + +Similar metrics are available for the Calls plugin with the following prefixes: + +- Process metrics: ``mattermost_plugin_calls_process_*`` +- WebRTC connection metrics: ``mattermost_plugin_calls_rtc_*`` +- WebSocket metrics: ``mattermost_plugin_calls_websocket_*`` +- Store metrics: ``mattermost_plugin_calls_store_ops_total`` + +Grafana Dashboards +---------------- + +Official Dashboard +^^^^^^^^^^^^^^^^ + +Mattermost provides an official Grafana dashboard for monitoring Calls performance: + +1. **Download the dashboard JSON**: + + Get it from [GitHub](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) + +2. **Import the dashboard** into Grafana: + + - Navigate to Dashboards > Import + - Upload the JSON file or paste its contents + - Select your Prometheus data source + - Click Import + +3. **Key panels** in the dashboard: + + - Active Calls and Participants + - RTC Connection States + - Media Tracks (In/Out) + - CPU and Memory Usage + - Network Traffic + - Error Counts + +Custom Dashboard Panels +^^^^^^^^^^^^^^^^^^^^ + +Consider adding these custom panels to your dashboard: + +1. **Error Rate Panel**: + + PromQL query: + + .. code-block:: text + + sum(rate(rtcd_rtc_errors_total[5m])) by (type) + +2. **Connection Success Rate**: + + PromQL query: + + .. code-block:: text + + sum(rtcd_rtc_conn_states_total{state="connected"}) / (sum(rtcd_rtc_conn_states_total{state="connected"}) + sum(rtcd_rtc_conn_states_total{state="failed"})) + +3. **Media Track Count by Direction**: + + PromQL query: + + .. code-block:: text + + sum(rtcd_rtc_rtp_tracks_total) by (direction) + +Alerting Recommendations +--------------------- + +Setting up alerts helps you respond quickly to potential issues. Here are recommended alert thresholds: + +1. **High CPU Usage Alert**: + + PromQL query: + + .. code-block:: text + + rate(rtcd_process_cpu_seconds_total[5m]) > 0.8 + + This alerts when CPU usage exceeds 80% over 5 minutes. + +2. **Connection Failure Rate Alert**: + + PromQL query: + + .. code-block:: text + + sum(rate(rtcd_rtc_conn_states_total{state="failed"}[5m])) / sum(rate(rtcd_rtc_conn_states_total[5m])) > 0.1 + + This alerts when more than 10% of connection attempts fail over 5 minutes. + +3. **WebSocket Connection Drop Alert**: + + PromQL query: + + .. code-block:: text + + rate(rtcd_ws_connections_total{state="closed"}[5m]) > 5 + + This alerts when more than 5 WebSocket connections are dropping per minute. + +4. **Memory Leak Detection**: + + PromQL query: + + .. code-block:: text + + rate(rtcd_process_resident_memory_bytes[30m]) > 1024 * 1024 * 10 + + This alerts when memory usage is increasing by more than 10MB per 30 minutes. + +Performance Baselines +------------------ + +Understanding normal performance patterns helps identify anomalies. Here are baseline expectations based on call volume: + +Small Deployment (1-10 concurrent calls) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- **CPU Usage**: 5-15% on a modern 4-core server +- **Memory Usage**: 200-500MB +- **Network**: 5-20 Mbps (depending on participant count and unmuted users) + +Medium Deployment (10-50 concurrent calls) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- **CPU Usage**: 15-40% on a modern 8-core server +- **Memory Usage**: 500MB-1GB +- **Network**: 20-100 Mbps + +Large Deployment (50+ concurrent calls) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- **CPU Usage**: Consider multiple RTCD instances +- **Memory Usage**: 1-2GB per instance +- **Network**: 100Mbps-1Gbps (with horizontal scaling) + +Below are the detailed benchmarks based on internal performance testing: + ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| Calls | Users/call | Unmuted/call | Screen sharing | CPU (avg) | Memory (avg) | Bandwidth (in/out) | Instance (EC2) | ++=======+============+==============+================+===========+==============+====================+================+ +| 100 | 8 | 2 | no | 60% | 0.5GB | 22Mbps / 125Mbps | c6i.xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 100 | 8 | 2 | no | 30% | 0.5GB | 22Mbps / 125Mbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 100 | 8 | 2 | yes | 86% | 0.7GB | 280Mbps / 2.2Gbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 10 | 50 | 2 | no | 35% | 0.3GB | 5.25Mbps / 86Mbps | c6i.xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 10 | 50 | 2 | no | 16% | 0.3GB | 5.25Mbps / 86Mbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 10 | 50 | 2 | yes | 90% | 0.3GB | 32Mbps / 1.33Gbps | c6i.xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 10 | 50 | 2 | yes | 45% | 0.3GB | 32Mbps / 1.33Gbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 5 | 200 | 2 | no | 65% | 0.6GB | 8.2Mbps / 180Mbps | c6i.xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 5 | 200 | 2 | no | 30% | 0.6GB | 8.2Mbps / 180Mbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ +| 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | ++-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ + +Metric Retention Recommendations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For historical analysis and trend identification: + +- **Short-term metrics**: Keep 15-second resolution data for 2 weeks +- **Medium-term metrics**: Keep 1-minute resolution data for 2 months +- **Long-term metrics**: Keep 5-minute resolution data for 1 year + +Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst new file mode 100644 index 00000000000..73450faaabd --- /dev/null +++ b/source/configure/calls-rtcd-setup.rst @@ -0,0 +1,450 @@ +RTCD Setup and Configuration +========================= + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +.. raw:: html + +
+ +Note + +|plans-img-yellow| The rtcd service is available only on `Enterprise `__ plans + +.. |plans-img-yellow| image:: ../_static/images/badges/flag_icon_yellow.svg + :class: mm-badge-flag + +.. raw:: html + +
+ +This guide provides detailed instructions for setting up, configuring, and validating a Mattermost Calls deployment using the dedicated RTCD service. + +- `Why use RTCD <#why-use-rtcd>`__ +- `Prerequisites <#prerequisites>`__ +- `Installation and deployment <#installation-and-deployment>`__ +- `Configuration <#configuration>`__ +- `Validation and testing <#validation-and-testing>`__ +- `Horizontal scaling <#horizontal-scaling>`__ +- `Integration with Mattermost <#integration-with-mattermost>`__ + +Why use RTCD +----------- + +The RTCD service (Real-Time Communication Daemon) is the recommended way to host Mattermost Calls for production environments for the following key reasons: + +1. **Performance isolation**: RTCD runs as a standalone service, isolating the resource-intensive calls traffic from the main Mattermost servers. This prevents call traffic spikes from affecting the rest of your Mattermost deployment. + +2. **Scalability**: When calls traffic increases, additional RTCD instances can be deployed to handle the load, without affecting your Mattermost servers. + +3. **Call stability**: With RTCD, if a Mattermost server needs to be restarted, ongoing calls won't be disrupted. The call audio/video will continue while the Mattermost server restarts (though some features like emoji reactions will be temporarily unavailable). + +4. **Kubernetes support**: For Kubernetes deployments, RTCD is the only officially supported way to run Calls. + +5. **Real-time optimization**: The RTCD service is specifically optimized for real-time audio/video traffic, with configurations prioritizing low latency over throughput. + +Prerequisites +------------ + +Before deploying RTCD, ensure you have: + +- A Mattermost Enterprise license +- A server or VM with sufficient CPU and network capacity (see the `Performance `__ section for sizing guidance) +- Network configuration that allows: + - UDP port 8443 (default) open between clients and RTCD servers + - TCP port 8045 (default) open between Mattermost servers and RTCD servers + - TCP port 8443 (optional backup) between clients and RTCD servers + +Installation and Deployment +-------------------------- + +There are multiple ways to deploy RTCD, depending on your environment: + +Bare Metal or VM Deployment +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Download the latest release from the `RTCD GitHub repository `__ + +2. Create a configuration file (``config.toml``) with the following minimal settings: + + .. code-block:: toml + + [api] + http.listen_address = ":8045" + + [rtc] + ice_address_udp = "" + ice_port_udp = 8443 + ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" + +3. Run the RTCD service: + + .. code-block:: bash + + ./rtcd --config config.toml + +Kubernetes Deployment +^^^^^^^^^^^^^^^^^^^ + +For Kubernetes deployments, use the official Helm chart: + +1. Add the Mattermost Helm repository: + + .. code-block:: bash + + helm repo add mattermost https://helm.mattermost.com + helm repo update + +2. Install the RTCD chart: + + .. code-block:: bash + + helm install mattermost-rtcd mattermost/mattermost-rtcd \ + --set ingress.enabled=true \ + --set ingress.host=rtcd.example.com \ + --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ + --set rtcd.ice.hostOverride=rtcd.example.com + + Refer to the `RTCD Helm chart documentation `__ for additional configuration options. + +Docker Deployment +^^^^^^^^^^^^^^^ + +1. Create a configuration file as described in the Bare Metal section + +2. Run the RTCD container: + + .. code-block:: bash + + docker run -d --name rtcd \ + -p 8045:8045 \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -v /path/to/config.toml:/rtcd/config/config.toml \ + mattermost/rtcd:latest + +Configuration +----------- + +RTCD Configuration File +^^^^^^^^^^^^^^^^^^^^^ + +The RTCD service uses a TOML configuration file. Here's a comprehensive example with commonly used settings: + +.. code-block:: toml + + [api] + # The address and port to which the HTTP API server will listen + http.listen_address = ":8045" + # Security settings for authentication + security.allow_self_registration = false + security.enable_admin = true + security.admin_secret_key = "YOUR_API_KEY" + # Configure allowed origins for CORS + security.allowed_origins = ["https://mattermost.example.com"] + + [rtc] + # The UDP address and port for media traffic + ice_address_udp = "" + ice_port_udp = 8443 + # The TCP address and port for fallback connections + ice_address_tcp = "" + ice_port_tcp = 8443 + # Public hostname or IP that clients will use to connect + ice_host_override = "rtcd.example.com" + + [logger] + # Logging configuration + enable_console = true + console_json = false + console_level = "INFO" + enable_file = true + file_json = true + file_level = "DEBUG" + file_location = "rtcd.log" + + [metrics] + # Prometheus metrics configuration + enable_prom = true + prom_port = 9090 + +Key Configuration Options: + +- **api.http.listen_address**: The address and port where the RTCD HTTP API service listens +- **rtc.ice_address_udp**: The UDP address for media traffic (empty means listen on all interfaces) +- **rtc.ice_port_udp**: The UDP port for media traffic +- **rtc.ice_address_tcp**: The TCP address for fallback media traffic +- **rtc.ice_port_tcp**: The TCP port for fallback media traffic +- **rtc.ice_host_override**: The public hostname or IP address clients will use to connect to RTCD +- **api.security.allowed_origins**: List of allowed origins for CORS +- **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD + +STUN/TURN Configuration +^^^^^^^^^^^^^^^^^^^^^ + +For clients behind strict firewalls, you may need to configure STUN/TURN servers. In the RTCD configuration file, reference your STUN/TURN servers as follows: + +.. code-block:: toml + + [rtc] + # STUN/TURN server configuration + ice_servers = [ + { urls = ["stun:stun.example.com:3478"] }, + { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } + ] + +We recommend using `coturn `__ for your TURN server implementation. For setting up and configuring coturn: + +1. Refer to the `official coturn documentation `__ +2. A basic coturn configuration file might look like this: + + .. code-block:: text + + # Basic coturn configuration - customize for your environment + # Refer to official documentation for complete options + + # Listener interface(s) + listening-ip=YOUR_SERVER_IP + listening-port=3478 + + # Relay interface(s) + relay-ip=YOUR_SERVER_IP + min-port=49152 + max-port=65535 + + # Authentication + lt-cred-mech + user=turnuser:turnpassword + + # TLS (recommended for production) + # cert=/path/to/cert.pem + # pkey=/path/to/privkey.pem + + # Logging + verbose + fingerprint + +3. Always test your TURN server connectivity before deploying to production using a tool like `Trickle ICE `__ + +For more advanced scenarios or troubleshooting, consult the official coturn documentation and WebRTC resources. + +System Tuning +^^^^^^^^^^^ + +For high-volume deployments, tune your Linux system: + +1. Add the following to ``/etc/sysctl.conf``: + + .. code-block:: bash + + # Increase UDP buffer sizes + net.core.rmem_max = 16777216 + net.core.wmem_max = 16777216 + net.core.optmem_max = 16777216 + +2. Apply the settings: + + .. code-block:: bash + + sudo sysctl -p + +Validation and Testing +-------------------- + +After deploying RTCD, validate the installation: + +1. **Check service status**: + + .. code-block:: bash + + curl http://YOUR_RTCD_SERVER:8045/api/v1/health + # Should return {"status":"ok"} + +2. **Test UDP connectivity**: + + On the RTCD server: + + .. code-block:: bash + + nc -l -u -p 8443 + + On a client machine: + + .. code-block:: bash + + nc -v -u YOUR_RTCD_SERVER 8443 + + Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. + +3. **Test TCP connectivity** (if enabled): + + Similar to the UDP test, but remove the ``-u`` flag from both commands. + +4. **Monitor metrics**: + + If you've enabled Prometheus metrics, access them at: + + .. code-block:: bash + + curl http://YOUR_RTCD_SERVER:9090/metrics + +Horizontal Scaling +---------------- + +To scale RTCD horizontally: + +1. **Deploy multiple RTCD instances**: + + Deploy multiple RTCD servers, each with their own unique IP address. + +2. **Configure DNS-based load balancing**: + + Set up a DNS record that points to multiple RTCD IP addresses: + + .. code-block:: bash + + rtcd.example.com. IN A 10.0.0.1 + rtcd.example.com. IN A 10.0.0.2 + rtcd.example.com. IN A 10.0.0.3 + +3. **Configure health checks**: + + Set up health checks to automatically remove unhealthy RTCD instances from DNS. + +4. **Configure Mattermost**: + + In the Mattermost System Console, set the **RTCD Service URL** to your DNS name (e.g., ``rtcd.example.com``). + +The Mattermost Calls plugin will distribute calls among the available RTCD hosts. Remember that a single call will always be hosted on one RTCD instance; sessions belonging to the same call are not spread across different instances. + +RTCD Connectivity Diagrams +----------------------- + +Understanding the network connectivity between clients, Mattermost servers, and RTCD services is crucial for proper deployment. The following diagrams illustrate the key communication paths in different deployment scenarios. + +Basic RTCD Deployment +^^^^^^^^^^^^^^^^^^^ + +In this basic deployment model, RTCD handles all media traffic while the Mattermost server manages signaling: + +:: + + +----------------+ +----------------+ +----------------+ + | | 1 | | 2 | | + | Client A |<----->| Mattermost |<----->| RTCD | + | | WS | Server | API | Service | + | | | | | | + +----------------+ +----------------+ +----------------+ + ^ ^ + | | + | Media (RTP) | + | 3 | + +-------------------------------------------------+ + +1. **WebSocket Connection (WS)**: Clients connect to Mattermost server using WebSockets for signaling and call control +2. **API Connection**: Mattermost server communicates with RTCD service for call setup and management +3. **Media (RTP) Connection**: Clients send/receive audio and screen sharing directly with RTCD service + +High Availability RTCD Deployment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For high availability, multiple RTCD instances can be deployed with DNS-based load balancing: + +:: + + +----------------+ +----------------+ +----------------+ + | | | | | RTCD #1 | + | Client A | | Mattermost |<----->| | + | | | Server | +----------------+ + +----------------+ | HA | + ^ | | +----------------+ + | | | | RTCD #2 | + +----------------+ | |<----->| | + | | | | +----------------+ + | Client B |<----->| | + | | | | +----------------+ + +----------------+ | | | RTCD #3 | + ^ | |<----->| | + | +----------------+ +----------------+ + | ^ + | | + +-------------------------------------------------+ + Media flows to appropriate + RTCD instance + +In this model: +- Each client connects to Mattermost through the load balancer +- Mattermost distributes calls among available RTCD instances +- A single call is always hosted on one RTCD instance +- If an RTCD instance fails, only calls on that instance are affected + +RTCD with TURN Server +^^^^^^^^^^^^^^^^^^ + +For environments with restrictive firewalls, a TURN server can relay media: + +:: + + +----------------+ +----------------+ +----------------+ + | | | | | | + | Client A |<----->| Mattermost |<----->| RTCD | + | (Firewall) | | Server | | Service | + | | | | | | + +----------------+ +----------------+ +----------------+ + ^ ^ + | | + | | + v | + +----------------+ | + | | | + | TURN Server |<---------------------------------------+ + | | Media Relay + +----------------+ + +- Clients behind restrictive firewalls connect to the TURN server +- TURN server relays media between clients and RTCD +- Adds some latency but enables connectivity in challenging network environments + +Detailed Network Protocol Diagram +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This diagram shows the specific protocols and ports used in a typical RTCD deployment: + +:: + + WebSockets HTTP(S) RTCD API + TCP 80/443 TCP 8045 + +--------------+ +--------------+ +------------------------+ + | | | | | | + | Clients |<--| Mattermost |<--| RTCD | + | | | Server | | | + +--------------+ +--------------+ +------------------------+ + ^ ^ + | | + | | + | Media (RTP/RTCP) | + +------------------------------------------+ + UDP 8443 (preferred) + TCP 8443 (fallback) + +Integration with Mattermost +------------------------- + +Once RTCD is properly set up and validated, configure Mattermost to use it: + +1. Go to **System Console > Plugins > Calls** + +2. Enable the **Enable RTCD Service** option + +3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname) + +4. If configured, enter the **RTCD API Key** that matches the one in your RTCD configuration + +5. Save the configuration + +6. Test by creating a new call in any Mattermost channel + +7. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics + +For detailed Mattermost Calls configuration options, see the `Calls Plugin Configuration Settings `__ documentation. \ No newline at end of file diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst new file mode 100644 index 00000000000..d824cdfbca8 --- /dev/null +++ b/source/configure/calls-troubleshooting.rst @@ -0,0 +1,440 @@ +Troubleshooting Mattermost Calls +=========================== + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +This guide provides comprehensive troubleshooting steps for Mattermost Calls, particularly focusing on the dedicated RTCD deployment model. Follow these steps to identify and resolve common issues. + +- `Common issues <#common-issues>`__ +- `Connectivity troubleshooting <#connectivity-troubleshooting>`__ +- `Log analysis <#log-analysis>`__ +- `Performance issues <#performance-issues>`__ +- `Debugging tools <#debugging-tools>`__ +- `Advanced diagnostics <#advanced-diagnostics>`__ + +Common Issues +----------- + +Calls Not Connecting +^^^^^^^^^^^^^^^^^^^^ + +**Symptoms**: Users can start calls but cannot connect, or calls connect but drop quickly. + +**Possible causes and solutions**: + +1. **Network connectivity issues**: + - Verify that UDP port 8443 (or your configured port) is open between clients and RTCD servers + - Ensure TCP port 8045 is open between Mattermost and RTCD servers + - Check that any load balancers are properly configured for UDP traffic + +2. **ICE configuration issues**: + - Verify the ``ice.hostOverride`` setting in RTCD configuration matches the publicly accessible hostname or IP + - Ensure STUN/TURN servers are properly configured if needed + +3. **API connectivity**: + - Verify that Mattermost servers can reach the RTCD API endpoint + - Check that the API key is correctly configured in both Mattermost and RTCD + +4. **Plugin configuration**: + - Ensure the Calls plugin is enabled and properly configured + - Verify the RTCD service URL is correct in the System Console + +Audio Issues +^^^^^^^^^^^ + +**Symptoms**: Users can connect to calls, but audio is one-way, choppy, or not working. + +**Possible causes and solutions**: + +1. **Client permissions**: + - Ensure browser/app has microphone permissions + - Check if users are using multiple audio devices that might interfere + +2. **Network quality**: + - High latency or packet loss can cause audio issues + - Try testing with TCP fallback enabled (requires RTCD v0.11+ and Calls v0.17+) + +3. **Audio device configuration**: + - Users should verify their audio input/output settings + - Try different browsers or the desktop app + +Call Quality Issues +^^^^^^^^^^^^^^^^^ + +**Symptoms**: Calls connect but quality is poor, with latency, echo, or distortion. + +**Possible causes and solutions**: + +1. **Server resources**: + - Check CPU usage on RTCD servers - high CPU can cause quality issues + - Refer to the `Performance Monitoring setup guide <../performance-monitoring/setup-guide.rst>`__ for detailed instructions on monitoring and optimizing performance + - Monitor network bandwidth usage + +2. **Network congestion**: + - Check for packet loss between clients and RTCD + - Consider network QoS settings to prioritize real-time traffic + +3. **Client-side issues**: + - Browser or app limitations + - Hardware limitations (CPU, memory) + - Network congestion at the user's location + +Connectivity Troubleshooting +-------------------------- + +Basic Connectivity Tests +^^^^^^^^^^^^^^^^^^^^^^ + +1. **HTTP API connectivity test**: + + Test if the RTCD API is reachable: + + .. code-block:: bash + + curl http://YOUR_RTCD_SERVER:8045/api/v1/health + # Expected response: {"status":"ok"} + +2. **UDP connectivity test**: + + On the RTCD server: + + .. code-block:: bash + + nc -l -u -p 8443 + + On a client machine: + + .. code-block:: bash + + nc -v -u YOUR_RTCD_SERVER 8443 + + Type a message and press Enter. If you see the message on both sides, UDP connectivity is working. + +3. **TCP fallback connectivity test**: + + Same as the UDP test, but without the ``-u`` flag: + + On the RTCD server: + + .. code-block:: bash + + nc -l -p 8443 + + On a client machine: + + .. code-block:: bash + + nc -v YOUR_RTCD_SERVER 8443 + +Network Packet Analysis +^^^^^^^^^^^^^^^^^^^^^ + +To capture and analyze network traffic: + +1. **Capture UDP traffic on the RTCD server**: + + .. code-block:: bash + + sudo tcpdump -n 'udp port 8443' -i any + +2. **Capture TCP API traffic**: + + .. code-block:: bash + + sudo tcpdump -n 'tcp port 8045' -i any + +3. **Analyze traffic patterns**: + + - Verify packets are flowing both ways + - Look for ICMP errors that might indicate firewall issues + - Check for patterns of packet loss + +4. **Use Wireshark for deeper analysis**: + + For more detailed packet inspection, capture traffic with tcpdump and analyze with Wireshark: + + .. code-block:: bash + + sudo tcpdump -n -w calls_traffic.pcap 'port 8443' + + Then analyze the ``calls_traffic.pcap`` file with Wireshark. + +Firewall Configuration Checks +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. **Check iptables rules** (Linux): + + .. code-block:: bash + + sudo iptables -L -n + + Ensure there are no rules blocking UDP port 8443 or TCP ports 8045/8443. + +2. **Check cloud provider security groups**: + + Verify that security groups or network ACLs allow: + - Inbound UDP on port 8443 from client networks + - Inbound TCP on port 8045 from Mattermost server networks + - Inbound TCP on port 8443 (if TCP fallback is enabled) + +3. **Check intermediate firewalls**: + + - Corporate firewalls might block UDP traffic + - Some networks might require TURN servers for traversal + +Log Analysis +---------- + +RTCD Logs +^^^^^^^^ + +The RTCD service logs important events and errors. Set the log level to "debug" for troubleshooting: + +1. **In the configuration file**: + + .. code-block:: json + + { + "log": { + "level": "debug", + "json": true + } + } + +2. **Common log patterns to look for**: + + - **Connection errors**: Look for "failed to connect" or "connection error" messages + - **ICE negotiation failures**: Look for "ICE failed" or "ICE timeout" messages + - **API authentication issues**: Look for "unauthorized" or "invalid API key" messages + +Mattermost Logs +^^^^^^^^^^^^^ + +Check the Mattermost server logs for Calls plugin related issues: + +1. **Enable debug logging** in System Console > Environment > Logging > File Log Level + +2. **Filter for Calls-related logs**: + + .. code-block:: bash + + grep -i "calls" /path/to/mattermost.log + +3. **Look for common patterns**: + + - Connection errors to RTCD + - Plugin initialization issues + - WebSocket connection problems + +Browser Console Logs +^^^^^^^^^^^^^^^^^ + +Instruct users to check their browser console logs: + +1. **In Chrome/Edge**: + - Press F12 to open Developer Tools + - Go to the Console tab + - Look for errors related to WebRTC, Calls, or media permissions + +2. **Specific patterns to look for**: + + - "getUserMedia" errors (microphone permission issues) + - "ICE connection" failures + - WebSocket connection errors + +Performance Issues +--------------- + +Diagnosing High CPU Usage +^^^^^^^^^^^^^^^^^^^^^^^ + +If RTCD servers show high CPU usage: + +1. **Check concurrent calls and participants**: + + - Access the Prometheus metrics endpoint to see active sessions + - Compare with the benchmark data in the documentation + +2. **Profile CPU usage** (Linux): + + .. code-block:: bash + + top -p $(pgrep rtcd) + + Or for detailed per-thread usage: + + .. code-block:: bash + + ps -eLo pid,ppid,tid,pcpu,comm | grep rtcd + +3. **Enable pprof profiling** (if needed): + + Add to your RTCD configuration: + + .. code-block:: json + + { + "debug": { + "pprof": true, + "pprofPort": 6060 + } + } + + Then capture a CPU profile: + + .. code-block:: bash + + curl http://localhost:6060/debug/pprof/profile > cpu.profile + + Analyze with: + + .. code-block:: bash + + go tool pprof -http=:8080 cpu.profile + +Diagnosing Network Bottlenecks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you suspect network bandwidth issues: + +1. **Monitor network utilization**: + + .. code-block:: bash + + iftop -n + +2. **Check for packet drops**: + + .. code-block:: bash + + netstat -su | grep -E 'drop|error' + +3. **Verify system network buffers**: + + .. code-block:: bash + + sysctl -a | grep net.core.rmem + sysctl -a | grep net.core.wmem + + Ensure these match the recommended values: + + .. code-block:: bash + + net.core.rmem_max = 16777216 + net.core.wmem_max = 16777216 + net.core.optmem_max = 16777216 + +Debugging Tools +------------ + +WebRTC Internals (Chrome) +^^^^^^^^^^^^^^^^^^^^^^^^ + +For in-depth WebRTC diagnostics in Chrome: + +1. **Access chrome://webrtc-internals** in a new browser tab while on a call + +2. **Examine the connection details**: + + - ICE connection state + - Selected candidate pairs + - DTLS/SRTP setup + - Bandwidth estimation + +3. **Look for specific issues**: + + - Candidate gathering delays + - Failed ICE connections + - Bandwidth limitations + +Prometheus Metrics Analysis +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use Prometheus metrics for real-time and historical performance data: + +1. **Key metrics to monitor**: + + - ``rtcd_rtc_sessions_total``: Number of active RTC sessions + - ``rtcd_rtc_conn_states_total``: Connection state transitions + - ``rtcd_rtc_errors_total``: Error counts + - ``rtcd_rtc_rtp_tracks_total``: Media track count + - ``rtcd_process_cpu_seconds_total``: CPU usage + +2. **Set up Grafana dashboards**: + + Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. + +Advanced Diagnostics +----------------- + +WebRTC Diagnostic Commands +^^^^^^^^^^^^^^^^^^^^^^^^ + +For detailed WebRTC diagnostics: + +1. **Test STUN server connectivity**: + + .. code-block:: bash + + # Using stun-client (you may need to install it) + stun-client stun.global.calls.mattermost.com + + This should return your public IP address if STUN is working correctly. + +2. **Verify TURN server**: + + .. code-block:: bash + + # Using turnutils_uclient (part of coturn) + turnutils_uclient -v -s your-turn-server -u username -p password + + This tests if your TURN server is correctly configured. + +3. **Test end-to-end latency**: + + Between client locations and RTCD server: + + .. code-block:: bash + + ping -c 10 your-rtcd-server + + Look for consistent, low latency (<100ms ideally for voice calls). + +Client-Side Testing Tools +^^^^^^^^^^^^^^^^^^^^^^^ + +Tools to help diagnose client-side issues: + +1. **WebRTC Troubleshooter**: + + Direct users to [WebRTC Troubleshooter](https://test.webrtc.org/) for browser capability testing. + +2. **Network Quality Tests**: + + Use [Speedtest](https://www.speedtest.net/) or similar to check internet connection quality. + +3. **Browser-Specific WebRTC Info**: + + - Chrome: chrome://webrtc-internals + - Firefox: about:webrtc + +When to Contact Support +^^^^^^^^^^^^^^^^^^^^ + +Consider contacting Mattermost Support when: + +1. You've tried basic troubleshooting steps without resolution +2. You're experiencing persistent connection failures across multiple clients +3. You notice unexpected or degraded performance despite proper configuration +4. You need help interpreting diagnostic information +5. You suspect a bug in the Calls plugin or RTCD service + +When contacting support, please include: + +- RTCD version and configuration (with sensitive information redacted) +- Mattermost server version +- Calls plugin version +- Client environments (browsers, OS versions) +- Relevant logs and diagnostic information +- Detailed description of the issue and steps to reproduce \ No newline at end of file From 982164a737c937b9f29b17805af02432abf66ce9 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Thu, 8 May 2025 09:47:38 -0400 Subject: [PATCH 02/60] Refactored Kubernetes content to a separate page. I'm concerned about the degree of 'hallucination` on some of the K8s/Helm config that Claude came up with --- source/configure/calls-deployment.rst | 53 ++++---- source/configure/calls-kubernetes.rst | 175 ++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 source/configure/calls-kubernetes.rst diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst index 3f0c0b07c87..7113efdc332 100644 --- a/source/configure/calls-deployment.rst +++ b/source/configure/calls-deployment.rst @@ -14,6 +14,7 @@ For detailed information on specific topics, please refer to these specialized g - `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service - `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques - `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability +- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments About Mattermost Calls --------------------- @@ -66,8 +67,8 @@ Limitations ----------- - In Mattermost Cloud, up to 200 participants per channel can join a call. -- In Mattermost self-hosted deployments, the default maximum number of participants is unlimited. The recommended maximum number of participants per call is 200. -- You can configure the maximum participants in **System Console > Plugin Management > Calls > Max call participants**. +- In Mattermost self-hosted deployments, the default maximum number of participants is unlimited. The recommended maximum number of participants per call is 200. This setting can be changed in **System Console > Plugin Management > Calls > Max call participants**. There's no limit to the total number of participants across all calls as the supported value greatly depends on instance resources. +- For more information on capacity planning, see the `Performance Considerations <#performance-considerations>`__ section below. Configuration ------------- @@ -82,46 +83,49 @@ Mattermost Calls can be deployed in several configurations: Single Instance Deployments ~~~~~~~~~~~~~~~~~~~~~~~~~~ +Integrated Mode +^^^^^^^^^^^^^ + +The WebRTC service runs within the Calls plugin on the Mattermost server. This is the default mode when first installing the plugin on a single Mattermost instance setup. The WebRTC service is integrated in the plugin itself and runs alongside the Mattermost server. + .. image:: ../images/calls-deployment-image3.png - :alt: A diagram of the integrated configuration model of a single instance. + :alt: Integrated configuration model of a single instance :width: 600px -**Integrated mode**: The WebRTC service runs within the Calls plugin on the Mattermost server. +RTCD Mode +^^^^^^^^ + +A dedicated RTCD service handles media routing, reducing load on the Mattermost server. .. image:: ../images/calls-deployment-image7.png - :alt: A diagram of a Web RTC deployment configuration. + :alt: Web RTC deployment configuration :width: 600px -**RTCD mode**: A dedicated RTCD service handles media routing, reducing load on the Mattermost server. - High Availability Deployments ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. image:: ../images/calls-deployment-image4.png - :alt: A diagram of a clustered calls deployment. - :width: 600px +Clustered Mode +^^^^^^^^^^^^ -**Clustered mode**: Each Mattermost node runs an instance of the plugin with its own WebRTC service. +This is the default mode when running the plugin in a high availability cluster-based deployment. Every Mattermost node will run an instance of the plugin that includes a WebRTC service. Calls are distributed across all available nodes through the existing load-balancer: a call is hosted on the instance where the initiating websocket connection (first client to join) is made. A single call will be hosted on a single cluster node. -.. image:: ../images/calls-deployment-image2.png - :alt: A diagram of an rtcd deployment. +.. image:: ../images/calls-deployment-image5.png + :alt: Clustered calls deployment :width: 600px -**RTCD with HA**: Dedicated RTCD services handle media routing for high availability. +RTCD with High Availability +^^^^^^^^^^ -Kubernetes Deployments -~~~~~~~~~~~~~~~~~~~~ +Dedicated RTCD services handle media routing for high availability. -.. image:: ../images/calls-deployment-kubernetes.png - :alt: A diagram of calls deployed in a Kubernetes cluster. +.. image:: ../images/calls-deployment-image2.png + :alt: RTCD deployment with high availability :width: 600px -For Kubernetes deployments, the RTCD service is strongly recommended and is the only officially supported approach. - -For Kubernetes deployments, the recommended approach is to use the officially provided Helm charts: +Kubernetes Deployments +~~~~~~~~~~~~~~~~~~~~ -- `rtcd Helm chart `__ -- `calls-offloader Helm chart `__ +RTCD is the only officially supported approach for Kubernetes deployments. For detailed information on deploying Mattermost Calls in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the `Calls Deployment on Kubernetes `__ guide. When to Use RTCD -------------- @@ -184,4 +188,5 @@ Next Steps 1. For detailed setup instructions, see `RTCD Setup and Configuration `__ 2. For monitoring guidance, see `Calls Metrics and Monitoring `__ -3. If you encounter issues, see `Calls Troubleshooting `__ \ No newline at end of file +3. If you encounter issues, see `Calls Troubleshooting `__ +4. For Kubernetes deployments, see `Calls Deployment on Kubernetes `__ \ No newline at end of file diff --git a/source/configure/calls-kubernetes.rst b/source/configure/calls-kubernetes.rst new file mode 100644 index 00000000000..1f66f3a492b --- /dev/null +++ b/source/configure/calls-kubernetes.rst @@ -0,0 +1,175 @@ +Calls deployment on Kubernetes +=========================== + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +This guide provides detailed information for deploying Mattermost Calls on Kubernetes environments. + +Overview +-------- + +Mattermost Calls has been designed to integrate well with Kubernetes to offer improved scalability and control over the deployment. For Kubernetes deployments, the RTCD service is strongly recommended and is the only officially supported approach. + +Architecture +----------- + +.. image:: ../images/calls-deployment-kubernetes.png + :alt: Calls deployed in a Kubernetes cluster + :width: 600px + +This diagram shows how the RTCD standalone service can be deployed in a Kubernetes cluster. In this architecture: + +1. Calls traffic is handled by dedicated RTCD pods +2. RTCD services are exposed through load balancers +3. Scaling is managed through Kubernetes deployment configurations +4. Call recording and transcription is handled by the calls-offloader service + +If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the `Kubernetes operator guide `__. + +Helm Chart Deployment +------------------- + +The recommended way to deploy Calls-related components in a Kubernetes environment is to use the officially provided Helm charts: + +RTCD Helm Chart +^^^^^^^^^^^^^ + +The RTCD Helm chart deploys the RTCD service needed for call media handling: + +.. code-block:: bash + + helm repo add mattermost https://helm.mattermost.com + helm repo update + + helm install mattermost-rtcd mattermost/mattermost-rtcd \ + --set ingress.enabled=true \ + --set ingress.host=rtcd.example.com \ + --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ + --set rtcd.ice.hostOverride=rtcd.example.com + +For complete configuration options, see the `RTCD Helm chart documentation `__. + +Calls-Offloader Helm Chart +^^^^^^^^^^^^^^^^^^^^^^^^ + +If you need call recording and transcription capabilities, deploy the calls-offloader service: + +.. code-block:: bash + + helm install mattermost-calls-offloader mattermost/mattermost-calls-offloader \ + --set ingress.enabled=true \ + --set ingress.host=calls-offloader.example.com + +For complete configuration options, see the `Calls-Offloader Helm chart documentation `__. + +Kubernetes-Specific Configuration +------------------------------- + +Network Configuration +^^^^^^^^^^^^^^^^^^ + +For Kubernetes deployments, you need to ensure: + +1. UDP traffic is properly routed to RTCD pods (for media) +2. TCP traffic can reach both the Mattermost pods and RTCD pods +3. Load balancers are properly configured to handle UDP traffic +4. Network policies allow the required communications between services + +Recommended annotations for AWS environments: + +.. code-block:: yaml + + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: udp + service.beta.kubernetes.io/aws-load-balancer-type: nlb + +Resource Requirements +^^^^^^^^^^^^^^^^^^ + +For optimal performance in Kubernetes environments: + +1. **CPU**: At least 2 CPU cores per RTCD pod +2. **Memory**: At least 1GB RAM per RTCD pod +3. **Network**: Sufficient bandwidth for expected call volume (see benchmarks) + +We recommend setting resource limits and requests in your deployment: + +.. code-block:: yaml + + resources: + requests: + cpu: 1000m + memory: 1Gi + limits: + cpu: 2000m + memory: 2Gi + +Scaling Considerations +^^^^^^^^^^^^^^^^^^ + +Horizontal scaling of RTCD pods is possible, but remember: + +1. Each call is hosted entirely on a single RTCD pod +2. DNS-based load balancing should be used to distribute calls among pods +3. Health checks should ensure that only healthy pods receive new calls +4. Calls remain on their assigned pod for their entire duration + +Limitations +^^^^^^^^^^ + +Due to the inherent complexities of hosting a WebRTC service, some limitations apply when deploying Calls in a Kubernetes environment. + +One key requirement is that each ``rtcd`` process must live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally not go through a standard ingress but directly to the pod running the ``rtcd`` process. + +The general recommendation is to expose one external IP address per ``rtcd`` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. + +If, for some reason, exposing multiple IP addresses is not possible in your environment, port mapping (NAT) can be used. In this scenario different ports are used to map the respective ``rtcd`` nodes behind the single external IP. Example: + +.. code-block:: text + + EXT_IP:8443 -> rtcdA:8443 + EXT_IP:8444 -> rtcdB:8443 + EXT_IP:8445 -> rtcdC:8443 + +This case requires a couple of extra configurations: + +* NAT mappings need to be in place for every ``rtcd`` node. This is usually done at the ingress point (e.g., ELB, NLB, etc). + +* The ``RTCD_RTC_ICEHOSTPORTOVERRIDE`` config should be used to pass a full mapping of node IPs and their respective port. + + * Example: ``RTCD_RTC_ICEHOSTPORTOVERRIDE=rtcdA_IP/8443,rtcdB_IP/8444,rtcdC_IP/8445`` + +* The ``RTCD_RTC_ICEHOSTOVERRIDE`` should be used to set the external IP address. + +.. note:: + One option to limit these static mappings is to reduce the size of the local subnet (e.g., to ``/29``). + +Monitoring and Metrics +^^^^^^^^^^^^^^^^^^^ + +We recommend deploying Prometheus and Grafana alongside your Calls deployment: + +1. Configure Prometheus to scrape metrics from both Mattermost and RTCD pods +2. Import the official Mattermost Calls dashboard to Grafana +3. Set up alerts for CPU usage, connection failures, and error rates + +For detailed information on metrics collection and monitoring, see the `Calls Metrics and Monitoring `__ guide. + +Troubleshooting +-------------- + +For Kubernetes-specific troubleshooting: + +1. Check pod logs: `kubectl logs -f deployment/mattermost-rtcd` +2. Verify service connectivity: `kubectl port-forward service/mattermost-rtcd 8045:8045` +3. Ensure UDP traffic is properly routed through your ingress/load balancer +4. Verify network policies allow required communication paths + +For detailed troubleshooting steps, see the `Calls Troubleshooting `__ guide. + +Next Steps +--------- + +1. For RTCD configuration details, see `RTCD Setup and Configuration `__ +2. For monitoring guidance, see `Calls Metrics and Monitoring `__ +3. If you encounter issues, see `Calls Troubleshooting `__ \ No newline at end of file From 25c7c0ab966a9b41b6a5069fd0044c05f03975e1 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Tue, 3 Jun 2025 15:31:24 -0400 Subject: [PATCH 03/60] Listing TODOs. Some minor tweaks. Getting the working directory committed to start using Claude to go through the TODOs. --- .gitignore | 2 + PULL_REQUEST_REVIEW_ITEMS.md | 30 +++++ source/configure/calls-deployment.rst | 6 +- source/configure/calls-metrics-monitoring.rst | 2 +- source/configure/calls-rtcd-setup.rst | 125 +++++++++++------- source/configure/calls-troubleshooting.rst | 9 +- 6 files changed, 122 insertions(+), 52 deletions(-) create mode 100644 PULL_REQUEST_REVIEW_ITEMS.md diff --git a/.gitignore b/.gitignore index 985ddd5e949..4c3c6194eb2 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,5 @@ source/developer/localization.md *.key *.crt .aider* + +**/.claude/settings.local.json diff --git a/PULL_REQUEST_REVIEW_ITEMS.md b/PULL_REQUEST_REVIEW_ITEMS.md new file mode 100644 index 00000000000..9e1bc015231 --- /dev/null +++ b/PULL_REQUEST_REVIEW_ITEMS.md @@ -0,0 +1,30 @@ +# Mattermost Calls Documentation TODOs + +This file contains a list of documentation improvements identified for the Mattermost Calls feature. + +## Completed Items + +- ✅ Update `calls-rtcd-setup.rst` with new version endpoint information +- ✅ Update `calls-troubleshooting.rst` ICE configuration section with correct parameter name +- ✅ Add client and RTCD log examples to ICE configuration issues +- ✅ Remove 'Why Use RTCD' section from calls-rtcd-setup.rst + +## High Priority Items + +- Re-order RTCD setup recommendations to prioritize "Bare Metal/VM", then "Docker", then "Kubernetes". I'll share my example systemd unit file and configuration. +- Create documentation for the calls-offloader service used for Calls Recording and Transcription +- Expand CORS documentation or document that `AllowCORSFrom` needs to be set to the SiteURL +- Add call-out/special note that the Calls metrics scraping has issues with `labels` setup in `prometheus.yml` and that the Calls dashboard expects : format, with an example. +- Document a common flow for each piece of the setup: Calls plugin curl/test/telemetry, RTCD curl/test/telemetry, calls-offloader curl/test/telemetry +- Document troubleshooting steps for the error "failed to create recording job: max concurrent jobs reached". + +## Medium Priority Items + +- Document the command `curl http://localhost:9090/api/v1/label/__name__/values | jq '.' | grep rtcd` as a troubleshooting tool in `calls-metrics-monitoring.rst` +- Document that Node Exporter service needs to be bound to the right address +- Document how to check Prometheus Scrape targets using the 'Targets' menu option for status +- Document this command for debugging calls-offloader: `docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {}` +- Document the command `docker ps -a --filter "status=exited"` to view completed calls-offloader job containers +- Improve formatting for Network Requirements table to avoid small side-scrolling view +- Document experimental screen sharing audio feature with limitations and how to enable with `/call experimental on` slash command +- Provide documentation on what settings changes require what service/plugin restarts diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst index 7113efdc332..3713272fd7c 100644 --- a/source/configure/calls-deployment.rst +++ b/source/configure/calls-deployment.rst @@ -38,9 +38,9 @@ Terminology Key Components ------------- -- **Calls plugin**: The main plugin that enables calls functionality -- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature) -- **calls-offloader**: Service for call recording and transcription (if enabled) +- **Calls plugin**: The main plugin that enables calls functionality. Installed by default in Mattermost self-hosted deployments. +- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. +- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. Network Requirements ------------------ diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index 241b8fc282b..7c48930bb09 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -63,7 +63,7 @@ Installing Prometheus - job_name: 'rtcd' scrape_interval: 15s static_configs: - - targets: ['rtcd-server:9090'] + - targets: ['rtcd-server:8045'] Installing Grafana ^^^^^^^^^^^^^^^ diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst index 73450faaabd..383ab9f88ba 100644 --- a/source/configure/calls-rtcd-setup.rst +++ b/source/configure/calls-rtcd-setup.rst @@ -21,7 +21,6 @@ Note This guide provides detailed instructions for setting up, configuring, and validating a Mattermost Calls deployment using the dedicated RTCD service. -- `Why use RTCD <#why-use-rtcd>`__ - `Prerequisites <#prerequisites>`__ - `Installation and deployment <#installation-and-deployment>`__ - `Configuration <#configuration>`__ @@ -29,21 +28,6 @@ This guide provides detailed instructions for setting up, configuring, and valid - `Horizontal scaling <#horizontal-scaling>`__ - `Integration with Mattermost <#integration-with-mattermost>`__ -Why use RTCD ------------ - -The RTCD service (Real-Time Communication Daemon) is the recommended way to host Mattermost Calls for production environments for the following key reasons: - -1. **Performance isolation**: RTCD runs as a standalone service, isolating the resource-intensive calls traffic from the main Mattermost servers. This prevents call traffic spikes from affecting the rest of your Mattermost deployment. - -2. **Scalability**: When calls traffic increases, additional RTCD instances can be deployed to handle the load, without affecting your Mattermost servers. - -3. **Call stability**: With RTCD, if a Mattermost server needs to be restarted, ongoing calls won't be disrupted. The call audio/video will continue while the Mattermost server restarts (though some features like emoji reactions will be temporarily unavailable). - -4. **Kubernetes support**: For Kubernetes deployments, RTCD is the only officially supported way to run Calls. - -5. **Real-time optimization**: The RTCD service is specifically optimized for real-time audio/video traffic, with configurations prioritizing low latency over throughput. - Prerequisites ------------ @@ -51,38 +35,79 @@ Before deploying RTCD, ensure you have: - A Mattermost Enterprise license - A server or VM with sufficient CPU and network capacity (see the `Performance `__ section for sizing guidance) -- Network configuration that allows: - - UDP port 8443 (default) open between clients and RTCD servers - - TCP port 8045 (default) open between Mattermost servers and RTCD servers - - TCP port 8443 (optional backup) between clients and RTCD servers + +Network Requirements +------------------ + +The following network connectivity is required: + ++-------------------+--------+-----------------+-------------------------+------------------------+ +| Service | Ports | Protocols | Source | Target | ++===================+========+=================+=========================+========================+ +| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | ++-------------------+--------+-----------------+-------------------------+------------------------+ +| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | ++-------------------+--------+-----------------+-------------------------+------------------------+ Installation and Deployment -------------------------- There are multiple ways to deploy RTCD, depending on your environment: -Bare Metal or VM Deployment -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Docker Deployment +^^^^^^^^^^^^^^^ -1. Download the latest release from the `RTCD GitHub repository `__ +The simplest way to deploy RTCD with Docker is to use environment variables for configuration: -2. Create a configuration file (``config.toml``) with the following minimal settings: +1. Run the RTCD container with basic configuration: - .. code-block:: toml + .. code-block:: bash - [api] - http.listen_address = ":8045" + docker run -d --name rtcd \ + -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -p 8045:8045/tcp \ + mattermost/rtcd:latest - [rtc] - ice_address_udp = "" - ice_port_udp = 8443 - ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" +2. For debugging purposes, you can enable more detailed logging: -3. Run the RTCD service: + .. code-block:: bash + + docker run -d --name rtcd \ + -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_LOGGER_CONSOLELEVEL=DEBUG" \ + -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -p 8045:8045/tcp \ + mattermost/rtcd:latest + + To view the logs: .. code-block:: bash - ./rtcd --config config.toml + docker logs -f rtcd + +You can also use a mounted configuration file instead of environment variables: + +.. code-block:: bash + + docker run -d --name rtcd \ + -p 8045:8045 \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -v /path/to/config.toml:/rtcd/config/config.toml \ + mattermost/rtcd:latest + +For a complete sample configuration file, see the `RTCD config.sample.toml `__ in the official repository. Kubernetes Deployment ^^^^^^^^^^^^^^^^^^^ @@ -108,21 +133,28 @@ For Kubernetes deployments, use the official Helm chart: Refer to the `RTCD Helm chart documentation `__ for additional configuration options. -Docker Deployment -^^^^^^^^^^^^^^^ +Bare Metal or VM Deployment +^^^^^^^^^^^^^^^^^^^^^^^^^^ -1. Create a configuration file as described in the Bare Metal section +1. Download the latest release from the `RTCD GitHub repository `__ + +2. Create a configuration file (``config.toml``) with the following minimal settings: -2. Run the RTCD container: + .. code-block:: toml + + [api] + http.listen_address = ":8045" + + [rtc] + ice_address_udp = "" + ice_port_udp = 8443 + ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" + +3. Run the RTCD service: .. code-block:: bash - docker run -d --name rtcd \ - -p 8045:8045 \ - -p 8443:8443/udp \ - -p 8443:8443/tcp \ - -v /path/to/config.toml:/rtcd/config/config.toml \ - mattermost/rtcd:latest + ./rtcd --config config.toml Configuration ----------- @@ -254,12 +286,13 @@ Validation and Testing After deploying RTCD, validate the installation: -1. **Check service status**: +1. **Check service status and version**: .. code-block:: bash - curl http://YOUR_RTCD_SERVER:8045/api/v1/health - # Should return {"status":"ok"} + curl http://YOUR_RTCD_SERVER:8045/version + # Should return a JSON object with service information + # Example: {"build_hash":"abc123","build_date":"2023-01-15T12:00:00Z","build_version":"0.11.0","goVersion":"go1.20.4"} 2. **Test UDP connectivity**: diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst index d824cdfbca8..e498d3c5afc 100644 --- a/source/configure/calls-troubleshooting.rst +++ b/source/configure/calls-troubleshooting.rst @@ -29,8 +29,13 @@ Calls Not Connecting - Check that any load balancers are properly configured for UDP traffic 2. **ICE configuration issues**: - - Verify the ``ice.hostOverride`` setting in RTCD configuration matches the publicly accessible hostname or IP - - Ensure STUN/TURN servers are properly configured if needed + - Verify the ``rtc.ice_host_override`` setting in RTCD configuration matches the publicly accessible hostname or IP of the RTCD server + - If this setting is incorrect, client browser console may show errors like: ``com.mattermost.calls: peer error timed out waiting for rtc connection`` + - Meanwhile, RTCD `trace` level logs might show internal IP addresses in ICE connection logs: + + .. code-block:: json + + {"timestamp":"2025-05-14 10:29:08.935 Z","level":"trace","msg":"Ping STUN from udp4 host 172.31.29.117:8443 (resolved: 172.31.29.117:8443) to udp4 host 192.168.64.1:59737 (resolved: 192.168.64.1:59737)","caller":"rtc/logger.go:54","origin":"ice/v4.(*Agent).sendBindingRequest github.com/pion/ice/v4@v4.0.3/agent.go:921"} 3. **API connectivity**: - Verify that Mattermost servers can reach the RTCD API endpoint From 4a9b03da403e3c8b53b169fbc22f0ec72464377b Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Tue, 3 Jun 2025 17:05:30 -0400 Subject: [PATCH 04/60] Added Calls Offloader logs --- source/configure/calls-deployment.rst | 5 +- source/configure/calls-kubernetes.rst | 2 +- source/configure/calls-metrics-monitoring.rst | 3 + source/configure/calls-offloader-setup.rst | 372 ++++++++++++++++++ source/configure/calls-rtcd-setup.rst | 113 ++++-- source/configure/calls-troubleshooting.rst | 41 +- 6 files changed, 476 insertions(+), 60 deletions(-) create mode 100644 source/configure/calls-offloader-setup.rst diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst index 3713272fd7c..e00e0568c60 100644 --- a/source/configure/calls-deployment.rst +++ b/source/configure/calls-deployment.rst @@ -12,6 +12,7 @@ Quick Links For detailed information on specific topics, please refer to these specialized guides: - `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Offloader Setup and Configuration `__: Comprehensive guide for setting up the calls-offloader service for recording and transcription - `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques - `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability - `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments @@ -39,8 +40,8 @@ Key Components ------------- - **Calls plugin**: The main plugin that enables calls functionality. Installed by default in Mattermost self-hosted deployments. -- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. -- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. +- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. See `RTCD Setup and Configuration `__ for details. +- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. See `Calls Offloader Setup and Configuration `__ for setup and troubleshooting details. Network Requirements ------------------ diff --git a/source/configure/calls-kubernetes.rst b/source/configure/calls-kubernetes.rst index 1f66f3a492b..dca52a68f73 100644 --- a/source/configure/calls-kubernetes.rst +++ b/source/configure/calls-kubernetes.rst @@ -23,7 +23,7 @@ This diagram shows how the RTCD standalone service can be deployed in a Kubernet 1. Calls traffic is handled by dedicated RTCD pods 2. RTCD services are exposed through load balancers 3. Scaling is managed through Kubernetes deployment configurations -4. Call recording and transcription is handled by the calls-offloader service +4. Call recording and transcription is handled by the calls-offloader service (see `Calls Offloader Setup and Configuration `__) If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the `Kubernetes operator guide `__. diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index 7c48930bb09..7a96c499640 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -65,6 +65,9 @@ Installing Prometheus static_configs: - targets: ['rtcd-server:8045'] + .. important:: + **Metrics Configuration Notice**: The Calls dashboard expects targets to be in ``:`` format. Avoid using ``labels`` in your Prometheus configuration for Calls metrics, as this can cause compatibility issues with the dashboard. For example, use ``targets: ['rtcd-server:8045']`` instead of labels-based targeting. + Installing Grafana ^^^^^^^^^^^^^^^ diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst new file mode 100644 index 00000000000..6c467377329 --- /dev/null +++ b/source/configure/calls-offloader-setup.rst @@ -0,0 +1,372 @@ +Calls Offloader Setup and Configuration +======================================= + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +.. raw:: html + +
+ +Note + +|plans-img-yellow| The calls-offloader service is available only on `Enterprise `__ plans + +.. |plans-img-yellow| image:: ../_static/images/badges/flag_icon_yellow.svg + :class: mm-badge-flag + +.. raw:: html + +
+ +This guide provides detailed instructions for setting up, configuring, and validating the Mattermost calls-offloader service used for call recording and transcription features. + +- `Overview <#overview>`__ +- `Prerequisites <#prerequisites>`__ +- `Installation and deployment <#installation-and-deployment>`__ +- `Configuration <#configuration>`__ +- `Validation and testing <#validation-and-testing>`__ +- `Integration with Mattermost <#integration-with-mattermost>`__ +- `Troubleshooting <#troubleshooting>`__ + +Overview +-------- + +The calls-offloader service is a dedicated microservice that handles resource-intensive tasks for Mattermost Calls, including: + +- **Call recording**: Captures audio and screen sharing content from calls +- **Call transcription**: Provides automated transcription of recorded calls +- **Live captions** (Experimental): Real-time transcription during active calls + +By offloading these tasks to a dedicated service, the main Mattermost server and RTCD service can focus on core functionality while maintaining optimal performance. + +Prerequisites +------------- + +Before deploying calls-offloader, ensure you have: + +- A Mattermost Enterprise license +- A properly configured Mattermost Calls deployment (either integrated or with RTCD) +- Docker installed and running (for Docker-based job execution) +- Sufficient storage space for recordings (see `Storage Requirements <#storage-requirements>`__) +- A server or container environment with adequate resources + +System Requirements +^^^^^^^^^^^^^^^^^ + +For detailed system requirements and performance recommendations, refer to the `calls-offloader performance documentation `__. + +Storage Requirements +^^^^^^^^^^^^^^^^^^ + +Call recordings can consume significant storage space: + +- Audio-only recordings: ~1MB per minute per participant +- Screen sharing recordings: ~10-50MB per minute depending on content + +Installation and Deployment +--------------------------- + +Bare Metal or VM Deployment +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Download the latest release from the `calls-offloader GitHub repository `__ + +2. Create the necessary directories: + + .. code-block:: bash + + sudo mkdir -p /opt/calls-offloader/data/db + sudo useradd --system --home /opt/calls-offloader calls-offloader + sudo chown -R calls-offloader:calls-offloader /opt/calls-offloader + +3. Create a configuration file (``/opt/calls-offloader/config.toml``): + + .. code-block:: toml + + [api] + http.listen_address = ":4545" + http.tls.enable = false + http.tls.cert_file = "" + http.tls.cert_key = "" + security.allow_self_registration = true + security.enable_admin = true + security.admin_secret_key = "changeme" + security.session_cache.expiration_minutes = 1440 + + [store] + data_source = "/opt/calls-offloader/data/db" + + [jobs] + api_type = "docker" + max_concurrent_jobs = 2 + failed_jobs_retention_time = "7d" + image_registry = "mattermost" + + [logger] + enable_console = true + console_json = false + console_level = "INFO" + enable_file = true + file_json = true + file_level = "INFO" + file_location = "/opt/calls-offloader/calls-offloader.log" + enable_color = true + +4. Create a systemd service file (``/etc/systemd/system/calls-offloader.service``): + + .. code-block:: ini + + [Unit] + Description=Mattermost Calls Offloader Service + After=network.target docker.service + Requires=docker.service + + [Service] + Type=simple + User=calls-offloader + WorkingDirectory=/opt/calls-offloader + ExecStart=/opt/calls-offloader/calls-offloader --config /opt/calls-offloader/config.toml + Restart=always + RestartSec=10 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + +5. Enable and start the service: + + .. code-block:: bash + + sudo systemctl daemon-reload + sudo systemctl enable calls-offloader + sudo systemctl start calls-offloader + +6. Check the service status: + + .. code-block:: bash + + sudo systemctl status calls-offloader + +7. Verify the service is responding: + + .. code-block:: bash + + curl http://localhost:4545/version + # Example output: + # {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} + + +Configuration +------------- + +API Configuration +^^^^^^^^^^^^^^^ + +The API section controls how the service accepts requests: + +- **http.listen_address**: The address and port where the service listens (default: ``:4545``) +- **http.tls.enable**: Whether to use TLS encryption for the API +- **security.allow_self_registration**: Allow clients to self-register for job management +- **security.enable_admin**: Enable admin functionality +- **security.admin_secret_key**: Secret key for admin authentication (change from default!) + +Store Configuration +^^^^^^^^^^^^^^^^^ + +Controls persistent data storage: + +- **data_source**: Path to directory for storing job metadata and state + +Jobs Configuration +^^^^^^^^^^^^^^^^ + +Controls job processing behavior: + +- **api_type**: Job execution backend (``docker`` or ``kubernetes``) +- **max_concurrent_jobs**: Maximum number of simultaneous recording/transcription jobs +- **failed_jobs_retention_time**: How long to keep failed job data before cleanup +- **image_registry**: Docker registry for job runner images (typically ``mattermost``) + +Logger Configuration +^^^^^^^^^^^^^^^^^^ + +Controls logging output: + +- **enable_console**: Log to console output +- **console_json**: Use JSON format for console logs +- **console_level**: Log level for console (DEBUG, INFO, WARN, ERROR) +- **enable_file**: Log to file +- **file_location**: Path to log file +- **enable_color**: Use colored output for console logs + +Private Network Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When the Mattermost deployment is running in a private network, additional configuration may be necessary for the jobs spawned by the calls-offloader service to reach the Mattermost server. + +In such cases, you can override the site URL used by recorder jobs or transcriber jobs to connect to Mattermost by setting the following environment variables on the Mattermost server: + +- **MM_CALLS_RECORDER_SITE_URL**: Override the site URL used by recording jobs +- **MM_CALLS_TRANSCRIBER_SITE_URL**: Override the site URL used by transcription jobs + +Example configuration: + +Create or edit the Mattermost environment file (``/opt/mattermost/config/mattermost.environment``): + +.. code-block:: bash + + MM_CALLS_RECORDER_SITE_URL="http://internal-mattermost-server:8065" + MM_CALLS_TRANSCRIBER_SITE_URL="http://internal-mattermost-server:8065" + +Then ensure your Mattermost systemd service references this environment file: + +.. code-block:: ini + + [Unit] + Description=Mattermost + After=network.target + + [Service] + Type=notify + EnvironmentFile=/opt/mattermost/config/mattermost.environment + ExecStart=/opt/mattermost/bin/mattermost + TimeoutStartSec=3600 + KillMode=mixed + Restart=always + RestartSec=10 + WorkingDirectory=/opt/mattermost + User=mattermost + Group=mattermost + + [Install] + WantedBy=multi-user.target + +This is particularly useful when: + +- The calls-offloader service runs in a different network segment than clients +- Internal DNS resolution differs from external URLs +- You need to use internal load balancer endpoints for job communication + +Validation and Testing +--------------------- + +After deploying calls-offloader, validate the installation: + +1. **Check service status**: + + .. code-block:: bash + + # For systemd + sudo systemctl status calls-offloader + + +2. **Test API connectivity**: + + .. code-block:: bash + + curl http://localhost:4545/version + # Should return version information + +3. **Verify Docker integration** (if using docker api_type): + + .. code-block:: bash + + # Check that system user running calls-offloader can access Docker + sudo -u calls-offloader docker ps + +Integration with Mattermost +--------------------------- + +Once calls-offloader is properly set up and validated, configure Mattermost to use it: + +1. Go to **System Console > Plugins > Calls** + +2. In the **Job Service** section: + + - Set **Job Service URL** to your calls-offloader service (e.g., ``http://calls-offloader-server:4545``) + - Configure **Job Service Secret** to match your ``admin_secret_key`` if enabled + +3. Enable recording and transcription features as needed: + + - **Enable Call Recordings**: Toggle to allow call recordings + - **Enable Call Transcriptions**: Toggle to allow call transcriptions + - **Enable Live Captions** (Experimental): Toggle to allow real-time transcription + +4. Save the configuration + +5. Test by starting a call and enabling recording or live captions + +Troubleshooting +--------------- + +Common Issues +^^^^^^^^^^^ + +**"failed to create recording job: max concurrent jobs reached"** + +This error occurs when the calls-offloader service has reached its configured job limit. + +Solutions: + +- Increase ``max_concurrent_jobs`` in the configuration +- Check if jobs are hanging and restart the service +- Monitor system resources and scale up if needed + +**Jobs not processing** + +Check the following: + +- Verify the calls-offloader service is running: ``sudo systemctl status calls-offloader`` +- Ensure network connectivity between Mattermost and calls-offloader +- Check Docker daemon is running and accessible by the user running `calls-offloader`: ``docker ps`` +- Verify authentication configuration matches between services +- Review service logs for specific error messages + +**Docker permission issues** + +If using Docker API and seeing permission errors: + +.. code-block:: bash + + # Add calls-offloader user to docker group + sudo usermod -a -G docker calls-offloader + sudo systemctl restart calls-offloader + +Debugging Commands +^^^^^^^^^^^^^^^^ + +Monitor calls-offloader job containers: + +.. code-block:: bash + + # View running job containers + docker ps --format "{{.ID}} {{.Image}}" | grep "calls" + + # Follow logs for debugging + docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {} + + # View completed job containers + docker ps -a --filter "status=exited" + +Monitor service health: + +.. code-block:: bash + + # Check service version and health + curl http://localhost:4545/version + +Check service logs: + +.. code-block:: bash + + # View recent logs + sudo journalctl -u calls-offloader -f + + # View log file (if file logging enabled) + tail -f /opt/calls-offloader/calls-offloader.log + +Performance Monitoring +^^^^^^^^^^^^^^^^^^^^ + +For detailed performance tuning and monitoring recommendations, refer to the `calls-offloader performance documentation `__. \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst index 383ab9f88ba..9cc2e484090 100644 --- a/source/configure/calls-rtcd-setup.rst +++ b/source/configure/calls-rtcd-setup.rst @@ -58,12 +58,98 @@ The following network connectivity is required: Installation and Deployment -------------------------- -There are multiple ways to deploy RTCD, depending on your environment: +There are multiple ways to deploy RTCD, depending on your environment. We recommend the following order based on production readiness and operational control: + +Bare Metal or VM Deployment (Recommended) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is the recommended deployment method for production environments as it provides the best performance and operational control. + +1. Download the latest release from the `RTCD GitHub repository `__ + +2. Create a configuration file (``/opt/rtcd/rtcd.toml``) with the following settings: + + .. code-block:: toml + + [api] + http.listen_address = ":8045" + security.allow_self_registration = true + + [rtc] + ice_address_udp = "" + ice_port_udp = 8443 + ice_address_tcp = "" + ice_port_tcp = 8443 + ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" + + # UDP port range for WebRTC connections + ice.port_range.min = 9000 + ice.port_range.max = 10000 + + # STUN/TURN server configuration + ice_servers = [ + { urls = ["stun:stun.l.google.com:19302"] } + ] + + [store] + data_source = "/opt/rtcd/data/db" + + [logger] + enable_console = true + console_json = true + console_level = "INFO" + enable_file = true + file_json = true + file_level = "INFO" + file_location = "/opt/rtcd/rtcd.log" + enable_color = true + + [mattermost] + host = "http://YOUR_MATTERMOST_SERVER:8065" + +3. Create the data directory: + + .. code-block:: bash + + sudo mkdir -p /opt/rtcd/data/db + +4. Create a systemd service file (``/etc/systemd/system/rtcd.service``): + + .. code-block:: ini + + [Unit] + Description=Mattermost RTCD Server + After=network.target + + [Service] + Type=simple + User=root + ExecStart=/opt/rtcd/rtcd --config /opt/rtcd/rtcd.toml + Restart=always + RestartSec=10 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + +5. Enable and start the service: + + .. code-block:: bash + + sudo systemctl daemon-reload + sudo systemctl enable rtcd + sudo systemctl start rtcd + +6. Check the service status: + + .. code-block:: bash + + sudo systemctl status rtcd Docker Deployment ^^^^^^^^^^^^^^^ -The simplest way to deploy RTCD with Docker is to use environment variables for configuration: +Docker deployment is suitable for development, testing, or containerized production environments: 1. Run the RTCD container with basic configuration: @@ -133,29 +219,6 @@ For Kubernetes deployments, use the official Helm chart: Refer to the `RTCD Helm chart documentation `__ for additional configuration options. -Bare Metal or VM Deployment -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. Download the latest release from the `RTCD GitHub repository `__ - -2. Create a configuration file (``config.toml``) with the following minimal settings: - - .. code-block:: toml - - [api] - http.listen_address = ":8045" - - [rtc] - ice_address_udp = "" - ice_port_udp = 8443 - ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" - -3. Run the RTCD service: - - .. code-block:: bash - - ./rtcd --config config.toml - Configuration ----------- diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst index e498d3c5afc..7437cd765ae 100644 --- a/source/configure/calls-troubleshooting.rst +++ b/source/configure/calls-troubleshooting.rst @@ -330,45 +330,21 @@ If you suspect network bandwidth issues: net.core.wmem_max = 16777216 net.core.optmem_max = 16777216 -Debugging Tools ------------- - -WebRTC Internals (Chrome) -^^^^^^^^^^^^^^^^^^^^^^^^ - -For in-depth WebRTC diagnostics in Chrome: +Recording and Transcription Issues +---------------------------------- -1. **Access chrome://webrtc-internals** in a new browser tab while on a call +For troubleshooting calls-offloader service issues including recording and transcription problems, see the `Calls Offloader Setup and Configuration `__ guide. -2. **Examine the connection details**: - - - ICE connection state - - Selected candidate pairs - - DTLS/SRTP setup - - Bandwidth estimation +Debugging Tools +------------ -3. **Look for specific issues**: - - - Candidate gathering delays - - Failed ICE connections - - Bandwidth limitations Prometheus Metrics Analysis ^^^^^^^^^^^^^^^^^^^^^^^^^ Use Prometheus metrics for real-time and historical performance data: -1. **Key metrics to monitor**: - - - ``rtcd_rtc_sessions_total``: Number of active RTC sessions - - ``rtcd_rtc_conn_states_total``: Connection state transitions - - ``rtcd_rtc_errors_total``: Error counts - - ``rtcd_rtc_rtp_tracks_total``: Media track count - - ``rtcd_process_cpu_seconds_total``: CPU usage - -2. **Set up Grafana dashboards**: - - Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. +Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. Advanced Diagnostics ----------------- @@ -429,7 +405,7 @@ When to Contact Support Consider contacting Mattermost Support when: -1. You've tried basic troubleshooting steps without resolution +1. You've tried troubleshooting steps without resolution 2. You're experiencing persistent connection failures across multiple clients 3. You notice unexpected or degraded performance despite proper configuration 4. You need help interpreting diagnostic information @@ -442,4 +418,5 @@ When contacting support, please include: - Calls plugin version - Client environments (browsers, OS versions) - Relevant logs and diagnostic information -- Detailed description of the issue and steps to reproduce \ No newline at end of file +- Detailed description of the issue and steps to reproduce +- Monitoring dashboards screenshots \ No newline at end of file From 2e75095b96c8757f65b85310bdda70c343d40e51 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 14:40:15 -0400 Subject: [PATCH 05/60] Added bottom navigation to get to all sections --- source/configure/calls-kubernetes.rst | 13 ++++++++----- source/configure/calls-metrics-monitoring.rst | 9 +++++++++ source/configure/calls-offloader-setup.rst | 11 +++++++++++ source/configure/calls-rtcd-setup.rst | 11 ++++++++++- source/configure/calls-troubleshooting.rst | 9 +++++++++ 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/source/configure/calls-kubernetes.rst b/source/configure/calls-kubernetes.rst index dca52a68f73..b9936db5cb0 100644 --- a/source/configure/calls-kubernetes.rst +++ b/source/configure/calls-kubernetes.rst @@ -167,9 +167,12 @@ For Kubernetes-specific troubleshooting: For detailed troubleshooting steps, see the `Calls Troubleshooting `__ guide. -Next Steps ---------- - -1. For RTCD configuration details, see `RTCD Setup and Configuration `__ -2. For monitoring guidance, see `Calls Metrics and Monitoring `__ +Other Calls Documentation +---------------- + +- `Calls Overview `__: Overview of deployment options and architecture +- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription +- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability +- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques 3. If you encounter issues, see `Calls Troubleshooting `__ \ No newline at end of file diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index 7a96c499640..a3ae4c992cd 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -322,4 +322,13 @@ For historical analysis and trend identification: - **Medium-term metrics**: Keep 1-minute resolution data for 2 months - **Long-term metrics**: Keep 5-minute resolution data for 1 year +Other Calls Documentation +---------------- + +- `Calls Overview `__: Overview of deployment options and architecture +- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription +- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments +- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques + Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst index 6c467377329..a8e45adbdf5 100644 --- a/source/configure/calls-offloader-setup.rst +++ b/source/configure/calls-offloader-setup.rst @@ -369,4 +369,15 @@ Check service logs: Performance Monitoring ^^^^^^^^^^^^^^^^^^^^ +Monitor calls-offloader performance and resource usage to ensure optimal operation. Set up alerts for high CPU/memory usage, failed jobs, or extended processing times. + +Other Calls Documentation +---------------- + +- `Calls Overview `__: Overview of deployment options and architecture +- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability +- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments +- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques + For detailed performance tuning and monitoring recommendations, refer to the `calls-offloader performance documentation `__. \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst index 9cc2e484090..908c2bf4cd3 100644 --- a/source/configure/calls-rtcd-setup.rst +++ b/source/configure/calls-rtcd-setup.rst @@ -88,7 +88,7 @@ This is the recommended deployment method for production environments as it prov # STUN/TURN server configuration ice_servers = [ - { urls = ["stun:stun.l.google.com:19302"] } + { urls = ["stun:stun.global.calls.mattermost.com:3478"] } ] [store] @@ -543,4 +543,13 @@ Once RTCD is properly set up and validated, configure Mattermost to use it: 7. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics +Other Calls Documentation +---------------- + +- `Calls Overview `__: Overview of deployment options and architecture +- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription +- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability +- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments +- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques + For detailed Mattermost Calls configuration options, see the `Calls Plugin Configuration Settings `__ documentation. \ No newline at end of file diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst index 7437cd765ae..238ca1d8ca7 100644 --- a/source/configure/calls-troubleshooting.rst +++ b/source/configure/calls-troubleshooting.rst @@ -419,4 +419,13 @@ When contacting support, please include: - Client environments (browsers, OS versions) - Relevant logs and diagnostic information - Detailed description of the issue and steps to reproduce + +Other Calls Documentation +---------------- + +- `Calls Overview `__: Overview of deployment options and architecture +- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service +- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription +- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability +- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments - Monitoring dashboards screenshots \ No newline at end of file From e1456b68106595879b647f8b4ce758bff96684a9 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 14:46:49 -0400 Subject: [PATCH 06/60] Add toctree for sidebar navigation --- source/configure/calls-deployment.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst index e00e0568c60..816f0f6e384 100644 --- a/source/configure/calls-deployment.rst +++ b/source/configure/calls-deployment.rst @@ -6,6 +6,16 @@ Calls self-hosted deployment This document provides an overview of Mattermost Calls deployment options for self-hosted environments, including deployment architectures, key requirements, and important considerations. +.. toctree:: + :maxdepth: 1 + :hidden: + + calls-rtcd-setup + calls-offloader-setup + calls-metrics-monitoring + calls-kubernetes + calls-troubleshooting + Quick Links ---------- From 0fff7b7012dd91b9d5fe96ffa60470da4d60280c Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 14:56:12 -0400 Subject: [PATCH 07/60] Removed Claude's extrapolation to COTURN config --- source/configure/calls-rtcd-setup.rst | 146 +------------------------- 1 file changed, 1 insertion(+), 145 deletions(-) diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst index 908c2bf4cd3..88ff81757c2 100644 --- a/source/configure/calls-rtcd-setup.rst +++ b/source/configure/calls-rtcd-setup.rst @@ -289,41 +289,7 @@ For clients behind strict firewalls, you may need to configure STUN/TURN servers { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } ] -We recommend using `coturn `__ for your TURN server implementation. For setting up and configuring coturn: - -1. Refer to the `official coturn documentation `__ -2. A basic coturn configuration file might look like this: - - .. code-block:: text - - # Basic coturn configuration - customize for your environment - # Refer to official documentation for complete options - - # Listener interface(s) - listening-ip=YOUR_SERVER_IP - listening-port=3478 - - # Relay interface(s) - relay-ip=YOUR_SERVER_IP - min-port=49152 - max-port=65535 - - # Authentication - lt-cred-mech - user=turnuser:turnpassword - - # TLS (recommended for production) - # cert=/path/to/cert.pem - # pkey=/path/to/privkey.pem - - # Logging - verbose - fingerprint - -3. Always test your TURN server connectivity before deploying to production using a tool like `Trickle ICE `__ - -For more advanced scenarios or troubleshooting, consult the official coturn documentation and WebRTC resources. - +We recommend using `coturn `__ for your TURN server implementation. System Tuning ^^^^^^^^^^^ @@ -414,116 +380,6 @@ To scale RTCD horizontally: The Mattermost Calls plugin will distribute calls among the available RTCD hosts. Remember that a single call will always be hosted on one RTCD instance; sessions belonging to the same call are not spread across different instances. -RTCD Connectivity Diagrams ------------------------ - -Understanding the network connectivity between clients, Mattermost servers, and RTCD services is crucial for proper deployment. The following diagrams illustrate the key communication paths in different deployment scenarios. - -Basic RTCD Deployment -^^^^^^^^^^^^^^^^^^^ - -In this basic deployment model, RTCD handles all media traffic while the Mattermost server manages signaling: - -:: - - +----------------+ +----------------+ +----------------+ - | | 1 | | 2 | | - | Client A |<----->| Mattermost |<----->| RTCD | - | | WS | Server | API | Service | - | | | | | | - +----------------+ +----------------+ +----------------+ - ^ ^ - | | - | Media (RTP) | - | 3 | - +-------------------------------------------------+ - -1. **WebSocket Connection (WS)**: Clients connect to Mattermost server using WebSockets for signaling and call control -2. **API Connection**: Mattermost server communicates with RTCD service for call setup and management -3. **Media (RTP) Connection**: Clients send/receive audio and screen sharing directly with RTCD service - -High Availability RTCD Deployment -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For high availability, multiple RTCD instances can be deployed with DNS-based load balancing: - -:: - - +----------------+ +----------------+ +----------------+ - | | | | | RTCD #1 | - | Client A | | Mattermost |<----->| | - | | | Server | +----------------+ - +----------------+ | HA | - ^ | | +----------------+ - | | | | RTCD #2 | - +----------------+ | |<----->| | - | | | | +----------------+ - | Client B |<----->| | - | | | | +----------------+ - +----------------+ | | | RTCD #3 | - ^ | |<----->| | - | +----------------+ +----------------+ - | ^ - | | - +-------------------------------------------------+ - Media flows to appropriate - RTCD instance - -In this model: -- Each client connects to Mattermost through the load balancer -- Mattermost distributes calls among available RTCD instances -- A single call is always hosted on one RTCD instance -- If an RTCD instance fails, only calls on that instance are affected - -RTCD with TURN Server -^^^^^^^^^^^^^^^^^^ - -For environments with restrictive firewalls, a TURN server can relay media: - -:: - - +----------------+ +----------------+ +----------------+ - | | | | | | - | Client A |<----->| Mattermost |<----->| RTCD | - | (Firewall) | | Server | | Service | - | | | | | | - +----------------+ +----------------+ +----------------+ - ^ ^ - | | - | | - v | - +----------------+ | - | | | - | TURN Server |<---------------------------------------+ - | | Media Relay - +----------------+ - -- Clients behind restrictive firewalls connect to the TURN server -- TURN server relays media between clients and RTCD -- Adds some latency but enables connectivity in challenging network environments - -Detailed Network Protocol Diagram -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This diagram shows the specific protocols and ports used in a typical RTCD deployment: - -:: - - WebSockets HTTP(S) RTCD API - TCP 80/443 TCP 8045 - +--------------+ +--------------+ +------------------------+ - | | | | | | - | Clients |<--| Mattermost |<--| RTCD | - | | | Server | | | - +--------------+ +--------------+ +------------------------+ - ^ ^ - | | - | | - | Media (RTP/RTCP) | - +------------------------------------------+ - UDP 8443 (preferred) - TCP 8443 (fallback) - Integration with Mattermost ------------------------- From 3321c25f7993e951b91c9102111d8828adc53d8e Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 15:10:57 -0400 Subject: [PATCH 08/60] Clean up from review and validation --- source/configure/calls-rtcd-setup.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst index 88ff81757c2..18dc0001f6c 100644 --- a/source/configure/calls-rtcd-setup.rst +++ b/source/configure/calls-rtcd-setup.rst @@ -290,6 +290,7 @@ For clients behind strict firewalls, you may need to configure STUN/TURN servers ] We recommend using `coturn `__ for your TURN server implementation. + System Tuning ^^^^^^^^^^^ @@ -339,17 +340,20 @@ After deploying RTCD, validate the installation: Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. + Note: This test must be run with the RTCD service stopped, as it binds to the same port. + + .. code-block:: bash + + sudo systemctl stop rtcd + + 3. **Test TCP connectivity** (if enabled): Similar to the UDP test, but remove the ``-u`` flag from both commands. 4. **Monitor metrics**: - If you've enabled Prometheus metrics, access them at: - - .. code-block:: bash - - curl http://YOUR_RTCD_SERVER:9090/metrics + Refer to `Calls Metrics and Monitoring `__ for setting up Calls metrics and monitoring. Horizontal Scaling ---------------- From 7fe4b70aac9b34ca23f21d831157ccd00b4748a9 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 15:23:20 -0400 Subject: [PATCH 09/60] Expanded API connectivity testing instructions --- source/configure/calls-offloader-setup.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst index a8e45adbdf5..813b621b8a5 100644 --- a/source/configure/calls-offloader-setup.rst +++ b/source/configure/calls-offloader-setup.rst @@ -263,10 +263,27 @@ After deploying calls-offloader, validate the installation: 2. **Test API connectivity**: + **From the calls-offloader server (localhost test)**: + .. code-block:: bash curl http://localhost:4545/version # Should return version information + # Example: {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} + + **From the Mattermost server**: + + .. code-block:: bash + + curl http://YOUR_CALLS_OFFLOADER_SERVER:4545/version + # Should return the same version information + # This confirms network connectivity from Mattermost to calls-offloader + + If the localhost test works but the Mattermost server test fails, check: + + - Firewall rules or SELinux policies on the calls-offloader server (port 4545 must be accessible) + - Network connectivity between Mattermost and calls-offloader servers + - calls-offloader service binding configuration (ensure it's not bound to localhost only) 3. **Verify Docker integration** (if using docker api_type): From 13c5724c1efd21b479b08192ea3c91b615ec043e Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 15:27:20 -0400 Subject: [PATCH 10/60] Removed reference to job service secret We don't really talk about it enough in the docs anyway. Leave that for another revision --- source/configure/calls-offloader-setup.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst index 813b621b8a5..34773f4683b 100644 --- a/source/configure/calls-offloader-setup.rst +++ b/source/configure/calls-offloader-setup.rst @@ -302,7 +302,6 @@ Once calls-offloader is properly set up and validated, configure Mattermost to u 2. In the **Job Service** section: - Set **Job Service URL** to your calls-offloader service (e.g., ``http://calls-offloader-server:4545``) - - Configure **Job Service Secret** to match your ``admin_secret_key`` if enabled 3. Enable recording and transcription features as needed: From 22057ab41bad0a4f1bbc72122e69f4792f84f2c0 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 15:28:41 -0400 Subject: [PATCH 11/60] Added plugin restart guidance when configuring offloader --- source/configure/calls-offloader-setup.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst index 34773f4683b..e9d11a3b576 100644 --- a/source/configure/calls-offloader-setup.rst +++ b/source/configure/calls-offloader-setup.rst @@ -311,7 +311,13 @@ Once calls-offloader is properly set up and validated, configure Mattermost to u 4. Save the configuration -5. Test by starting a call and enabling recording or live captions +5. Restart the Calls plugin to re-establish state: + + - Go to **System Console > Plugins > Plugin Management** + - Find the **Calls** plugin and click **Disable** + - Wait a few seconds, then click **Enable** + +6. Test by starting a call and enabling recording or live captions Troubleshooting --------------- From 1d682d5527a7c5b62d383aea24800c1efd488fb4 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 16:15:48 -0400 Subject: [PATCH 12/60] Tweaked footer links --- source/configure/calls-offloader-setup.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst index e9d11a3b576..195020f787f 100644 --- a/source/configure/calls-offloader-setup.rst +++ b/source/configure/calls-offloader-setup.rst @@ -391,7 +391,7 @@ Check service logs: Performance Monitoring ^^^^^^^^^^^^^^^^^^^^ -Monitor calls-offloader performance and resource usage to ensure optimal operation. Set up alerts for high CPU/memory usage, failed jobs, or extended processing times. +Monitor calls-offloader performance and resource usage to ensure optimal operation. See `Calls Metrics and Monitoring `__ for details on setting up metrics and observability. Other Calls Documentation ---------------- @@ -401,5 +401,4 @@ Other Calls Documentation - `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability - `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments - `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques - -For detailed performance tuning and monitoring recommendations, refer to the `calls-offloader performance documentation `__. \ No newline at end of file +- `calls-offloader performance documentation `__: Detailed performance tuning and monitoring recommendations \ No newline at end of file From 1caaf3eb33cf40ce77732e2a692bff27b68813fa Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 16:22:12 -0400 Subject: [PATCH 13/60] Tweaks and validation of metrics --- source/configure/calls-metrics-monitoring.rst | 126 +++--------------- 1 file changed, 18 insertions(+), 108 deletions(-) diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index a3ae4c992cd..b64c04db395 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -176,116 +176,35 @@ Mattermost provides an official Grafana dashboard for monitoring Calls performan - Navigate to Dashboards > Import - Upload the JSON file or paste its contents - Select your Prometheus data source + - Confirm the correct rtcd (`5045`) and calls plugin (`8065`) targets are set - Click Import -3. **Key panels** in the dashboard: - - - Active Calls and Participants - - RTC Connection States - - Media Tracks (In/Out) - - CPU and Memory Usage - - Network Traffic - - Error Counts - -Custom Dashboard Panels -^^^^^^^^^^^^^^^^^^^^ - -Consider adding these custom panels to your dashboard: - -1. **Error Rate Panel**: - - PromQL query: - - .. code-block:: text - - sum(rate(rtcd_rtc_errors_total[5m])) by (type) - -2. **Connection Success Rate**: - - PromQL query: - - .. code-block:: text - - sum(rtcd_rtc_conn_states_total{state="connected"}) / (sum(rtcd_rtc_conn_states_total{state="connected"}) + sum(rtcd_rtc_conn_states_total{state="failed"})) - -3. **Media Track Count by Direction**: - - PromQL query: - - .. code-block:: text - - sum(rtcd_rtc_rtp_tracks_total) by (direction) - -Alerting Recommendations ---------------------- - -Setting up alerts helps you respond quickly to potential issues. Here are recommended alert thresholds: - -1. **High CPU Usage Alert**: - - PromQL query: - - .. code-block:: text - - rate(rtcd_process_cpu_seconds_total[5m]) > 0.8 - - This alerts when CPU usage exceeds 80% over 5 minutes. - -2. **Connection Failure Rate Alert**: - - PromQL query: - - .. code-block:: text - - sum(rate(rtcd_rtc_conn_states_total{state="failed"}[5m])) / sum(rate(rtcd_rtc_conn_states_total[5m])) > 0.1 - - This alerts when more than 10% of connection attempts fail over 5 minutes. - -3. **WebSocket Connection Drop Alert**: - - PromQL query: - - .. code-block:: text - - rate(rtcd_ws_connections_total{state="closed"}[5m]) > 5 - - This alerts when more than 5 WebSocket connections are dropping per minute. - -4. **Memory Leak Detection**: - - PromQL query: - - .. code-block:: text - - rate(rtcd_process_resident_memory_bytes[30m]) > 1024 * 1024 * 10 - - This alerts when memory usage is increasing by more than 10MB per 30 minutes. - Performance Baselines ------------------ -Understanding normal performance patterns helps identify anomalies. Here are baseline expectations based on call volume: +The following performance benchmarks provide baseline metrics for RTCD deployments under various load conditions and configurations. -Small Deployment (1-10 concurrent calls) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +**Deployment specifications** -- **CPU Usage**: 5-15% on a modern 4-core server -- **Memory Usage**: 200-500MB -- **Network**: 5-20 Mbps (depending on participant count and unmuted users) +- 1x r6i.large nginx proxy +- 3x c5.large MM app nodes (HA) +- 2x db.x2g.xlarge RDS Aurora MySQL v8 (one writer, one reader) +- 1x (c7i.xlarge, c7i.2xlarge, c7i.4xlarge) RTCD +- 2x c7i.2xlarge load-test agents -Medium Deployment (10-50 concurrent calls) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +**App specifications** -- **CPU Usage**: 15-40% on a modern 8-core server -- **Memory Usage**: 500MB-1GB -- **Network**: 20-100 Mbps +- Mattermost v9.6 +- Mattermost Calls v0.28.0 +- RTCD v0.16.0 +- load-test agent v0.28.0 -Large Deployment (50+ concurrent calls) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +**Media specifications** -- **CPU Usage**: Consider multiple RTCD instances -- **Memory Usage**: 1-2GB per instance -- **Network**: 100Mbps-1Gbps (with horizontal scaling) +- Speech sample bitrate: 80Kbps +- Screen sharing sample bitrate: 1.6Mbps + +**Results** Below are the detailed benchmarks based on internal performance testing: @@ -313,15 +232,6 @@ Below are the detailed benchmarks based on internal performance testing: | 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | +-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -Metric Retention Recommendations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For historical analysis and trend identification: - -- **Short-term metrics**: Keep 15-second resolution data for 2 weeks -- **Medium-term metrics**: Keep 1-minute resolution data for 2 months -- **Long-term metrics**: Keep 5-minute resolution data for 1 year - Other Calls Documentation ---------------- From 42dfc7272c3654c7ec94553062f60654b75888da Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 16:26:57 -0400 Subject: [PATCH 14/60] Fleshed out prometheus target setup docs --- source/configure/calls-metrics-monitoring.rst | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index b64c04db395..35d2c80935a 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -47,27 +47,60 @@ Installing Prometheus Visit the [Prometheus download page](https://prometheus.io/download/) for installation instructions. -2. **Configure Prometheus** to scrape metrics from Mattermost and RTCD: +2. **Configure Prometheus** to scrape metrics from all Calls-related services: - Example ``prometheus.yml`` configuration: + Complete ``prometheus.yml`` configuration for Calls monitoring: .. code-block:: yaml + global: + scrape_interval: 15s + evaluation_interval: 15s + scrape_configs: - - job_name: 'mattermost-calls' - scrape_interval: 15s - metrics_path: '/plugins/com.mattermost.calls/metrics' + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + - job_name: 'mattermost' + metrics_path: /metrics static_configs: - - targets: ['mattermost-server:8065'] - + - targets: ['MATTERMOST_SERVER_IP:8067'] + + - job_name: 'calls' + metrics_path: /plugins/com.mattermost.calls/metrics + static_configs: + - targets: ['MATTERMOST_SERVER_IP:8067'] + - job_name: 'rtcd' - scrape_interval: 15s + metrics_path: /metrics static_configs: - - targets: ['rtcd-server:8045'] + - targets: ['RTCD_SERVER_IP:8045'] + + - job_name: 'node_exporter' + metrics_path: /metrics + static_configs: + - targets: ['RTCD_SERVER_IP:9100'] + + - job_name: 'calls-offloader' + metrics_path: /metrics + static_configs: + - targets: ['CALLS_OFFLOADER_SERVER_IP:4545'] + + Replace the placeholder IP addresses with your actual server addresses: + + - ``MATTERMOST_SERVER_IP``: IP address of your Mattermost server + - ``RTCD_SERVER_IP``: IP address of your RTCD server + - ``CALLS_OFFLOADER_SERVER_IP``: IP address of your calls-offloader server (if deployed) .. important:: **Metrics Configuration Notice**: The Calls dashboard expects targets to be in ``:`` format. Avoid using ``labels`` in your Prometheus configuration for Calls metrics, as this can cause compatibility issues with the dashboard. For example, use ``targets: ['rtcd-server:8045']`` instead of labels-based targeting. + .. note:: + - **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See `node_exporter setup guide `__ for installation instructions. + - **calls-offloader**: Only needed if you have call recording/transcription enabled + - **Port 8067**: Default Mattermost metrics port (configurable in System Console) + Installing Grafana ^^^^^^^^^^^^^^^ From 06f3e2fd639a62ec6d36d96ceba408d6e0dec043 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 6 Jun 2025 16:27:26 -0400 Subject: [PATCH 15/60] Removed Claude halucinated detail --- source/configure/calls-metrics-monitoring.rst | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index 35d2c80935a..a4aaec68634 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -58,10 +58,6 @@ Installing Prometheus evaluation_interval: 15s scrape_configs: - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - - job_name: 'mattermost' metrics_path: /metrics static_configs: @@ -115,19 +111,6 @@ Installing Grafana - Enter the URL of your Prometheus server - Test and save the configuration -Enabling Metrics in RTCD -^^^^^^^^^^^^^^^^^^^^^^ - -Add the following to your RTCD configuration file: - -.. code-block:: json - - { - "metrics": { - "enableProm": true, - "promPort": 9090 - } - } Key Metrics to Monitor -------------------- From 7e63612a3a146190317560ba156b82e64b48082d Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 10:10:58 -0400 Subject: [PATCH 16/60] Docs refinements from further testing and experience --- source/configure/calls-deployment.rst | 62 ++++++++++++++-- source/configure/calls-metrics-monitoring.rst | 66 ++++++++++-------- source/configure/calls-troubleshooting.rst | 6 +- .../images/calls-channel-enable-disable.png | Bin 0 -> 194225 bytes 4 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 source/images/calls-channel-enable-disable.png diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst index 816f0f6e384..d7379ca87ce 100644 --- a/source/configure/calls-deployment.rst +++ b/source/configure/calls-deployment.rst @@ -77,9 +77,10 @@ For complete network requirements, see the `RTCD Setup and Configuration Plugin Management > Calls > Max call participants**. There's no limit to the total number of participants across all calls as the supported value greatly depends on instance resources. -- For more information on capacity planning, see the `Performance Considerations <#performance-considerations>`__ section below. +- All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. +- For group calls up to 50 concurrent users, Mattermost Enterprise, Professional, or Mattermost Cloud is required. +- Enterprise customers can also `record calls `__, enable `live text captions `__ during calls, and `transcribe recorded calls `__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the `dedicated RTCD service <#when-to-use-rtcd>`__. +- For Mattermost self-hosted deployments, System admins need to enable and configure the plugin `using the System Console `__. The default maximum number of participants is unlimited; however, we recommend a maximum of 50 participants per call. Maximum call participants is configurable by going to **System Console > Plugin Management > Calls > Max call participants**. Call participant limits greatly depends on instance resources. For more details, refer to the `Performance Considerations <#performance-considerations>`__ section below. Configuration ------------- @@ -160,6 +161,15 @@ For call recording and transcription, you need to: 2. Configure the service URL in the System Console 3. Enable call recordings and/or transcriptions in the plugin settings +Air-Gapped Deployments +--------------------- + +Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: + +- Users should connect from within the private/local network. This can be done on-premises, through a VPN, or via virtual machines. +- Configuring a STUN server is unnecessary, as all connections occur within the local network. +- The ICE Host Override configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. + Performance Considerations ------------------------ @@ -181,14 +191,56 @@ Yes, using WebRTC security standards (DTLS/SRTP). Traffic is encrypted in transi Only a Mattermost STUN server (``stun.global.calls.mattermost.com``) is used by default. This can be removed if you set the ICE Host Override configuration. **Is using UDP a requirement?** -UDP is recommended for best performance, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. +UDP is recommended protocol to serve real-time media as it allows for the lowest latency between peers, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. + +If clients are unable to connect using UDP (due to limitations or strict firewalls), you have a few options: + +- Since plugin version 0.17 and `rtcd` version 0.11 the RTC service will listen for TCP connections in addition to UDP ones. If configured correctly (e.g. using commonly allowed ports such as 80 or 443) it's possible to have clients connect directly through TCP when unable to do it through the preferred UDP channel. + +- Run calls through an external TURN server that listens on TCP and relays all media traffic between peers. However, this is a sub-optimal solution that should be avoided if possible as it will introduce extra latency along with added infrastructural cost. **Do I need a TURN server?** -Only if clients are behind restrictive firewalls that block UDP. We recommend `coturn `__ if needed. +Only if clients are behind restrictive firewalls that block UDP. We recommend (and officially support) `coturn `__ if needed. **Can RTCD traffic be kept internal?** Yes, and it's recommended. Only the media ports need to be accessible to end-users. +**How will this work with an existing reverse proxy sitting in front of Mattermost?** + +Generally clients should connect directly to either Mattermost or, if deployed, the dedicated ``rtcd`` service through the configured UDP port. However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. + +**Do calls require a dedicated server to work or can they run alongside Mattermost?** + +The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). + +See RTCD Setup and Configuration for more details on the dedicated RTCD service. + +**Can the traffic between Mattermost and ``rtcd`` be kept internal or should it be opened to the public?** + +When possible, it's recommended to keep communication between the Mattermost cluster and the dedicated ``rtcd`` service under the same private network as this can greatly simplify deployment and security. There's no requirement to expose ``rtcd``'s HTTP API to the public internet. + +**Can Calls be rolled out on a per-channel basis?** + +.. include:: ../_static/badges/selfhosted-only.rst + :start-after: :nosearch: + +Yes. Mattermost system admins running self-hosted deployments can enable or disable call functionality per channel. Once `test mode `__ is enabled for Mattermost Calls: + +1. **Navigate to the channel** where you want to enable or disable Calls +2. **Access the channel menu** by clicking the channel name at the top of the channel +3. **Select the Calls option** from the dropdown menu: + - Select **Enable calls** for each channel where you want Calls enabled + - Select **Disable calls** for all channels where you want Calls disabled + +.. image:: ../images/calls-channel-enable-disable.png + :alt: Channel menu showing Enable/Disable calls options + :width: 400px + +Once Calls is enabled for specific channels, users can start making calls in those channels. + +.. note:: + When `test mode `__ is disabled for Mattermost Calls, users in any Mattermost channel can make a call. + Troubleshooting --------------- diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst index a4aaec68634..81d29f74e99 100644 --- a/source/configure/calls-metrics-monitoring.rst +++ b/source/configure/calls-metrics-monitoring.rst @@ -45,7 +45,7 @@ Installing Prometheus 1. **Download and install Prometheus**: - Visit the [Prometheus download page](https://prometheus.io/download/) for installation instructions. + Visit the `Prometheus download page `__ for installation instructions. 2. **Configure Prometheus** to scrape metrics from all Calls-related services: @@ -58,51 +58,66 @@ Installing Prometheus evaluation_interval: 15s scrape_configs: + - job_name: 'prometheus' + static_configs: + - targets: ['PROMETHEUS_IP:9090'] + - job_name: 'mattermost' metrics_path: /metrics static_configs: - targets: ['MATTERMOST_SERVER_IP:8067'] - - job_name: 'calls' + - job_name: 'calls-plugin' metrics_path: /plugins/com.mattermost.calls/metrics static_configs: - targets: ['MATTERMOST_SERVER_IP:8067'] + labels: + service_name: 'calls-plugin' - job_name: 'rtcd' metrics_path: /metrics static_configs: - targets: ['RTCD_SERVER_IP:8045'] - - - job_name: 'node_exporter' + labels: + service_name: 'rtcd' + + - job_name: 'rtcd-node-exporter' metrics_path: /metrics static_configs: - targets: ['RTCD_SERVER_IP:9100'] - - - job_name: 'calls-offloader' + labels: + service_name: 'rtcd' + + - job_name: 'calls_offloader-node-exporter' metrics_path: /metrics static_configs: - - targets: ['CALLS_OFFLOADER_SERVER_IP:4545'] + - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] + labels: + service_name: 'offloader' Replace the placeholder IP addresses with your actual server addresses: - ``MATTERMOST_SERVER_IP``: IP address of your Mattermost server - ``RTCD_SERVER_IP``: IP address of your RTCD server - ``CALLS_OFFLOADER_SERVER_IP``: IP address of your calls-offloader server (if deployed) + - ``PROMETHEUS_IP``: IP address of your Prometheus server + - **Note**: The configuration above uses the default ports (RTCD: ``8045``, Mattermost metrics: ``8067``, etc.). Adjust these ports in ``prometheus.yml`` if you have customized them. + .. important:: + **Metrics Path**: Ensure the metrics paths are correct. The RTCD service exposes metrics at ``/metrics`` by default, and the Calls plugin at ``/plugins/com.mattermost.calls/metrics``. .. important:: - **Metrics Configuration Notice**: The Calls dashboard expects targets to be in ``:`` format. Avoid using ``labels`` in your Prometheus configuration for Calls metrics, as this can cause compatibility issues with the dashboard. For example, use ``targets: ['rtcd-server:8045']`` instead of labels-based targeting. + **Metrics Configuration Notice**: Use the ``service_name`` labels as shown in the configuration above. These labels help organize metrics in dashboards and enable proper service identification. .. note:: - **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See `node_exporter setup guide `__ for installation instructions. - **calls-offloader**: Only needed if you have call recording/transcription enabled - - **Port 8067**: Default Mattermost metrics port (configurable in System Console) Installing Grafana ^^^^^^^^^^^^^^^ 1. **Download and install Grafana**: - Visit the [Grafana download page](https://grafana.com/grafana/download) for installation instructions. + Visit the `Grafana download page `__ for installation instructions. 2. **Configure Grafana** to use Prometheus as a data source: @@ -111,6 +126,17 @@ Installing Grafana - Enter the URL of your Prometheus server - Test and save the configuration +3. **Import the Mattermost Calls dashboard**: + + - Navigate to Dashboards > Import in Grafana + - Enter dashboard ID: ``23225`` or use the direct link: `Mattermost Calls Performance Monitoring `__ + - Select your Prometheus data source, and enter values for the + - Confirm the port used for RTCD metrics (default is ``8045``), and the port used for the Calls plugin metrics (default is ``8067``) + - Click Import to add the dashboard to your Grafana instance + + .. note:: + The dashboard is also available as JSON source from the `Mattermost performance assets repository `__ for manual import or customization. + Key Metrics to Monitor -------------------- @@ -175,26 +201,6 @@ Similar metrics are available for the Calls plugin with the following prefixes: - WebSocket metrics: ``mattermost_plugin_calls_websocket_*`` - Store metrics: ``mattermost_plugin_calls_store_ops_total`` -Grafana Dashboards ----------------- - -Official Dashboard -^^^^^^^^^^^^^^^^ - -Mattermost provides an official Grafana dashboard for monitoring Calls performance: - -1. **Download the dashboard JSON**: - - Get it from [GitHub](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) - -2. **Import the dashboard** into Grafana: - - - Navigate to Dashboards > Import - - Upload the JSON file or paste its contents - - Select your Prometheus data source - - Confirm the correct rtcd (`5045`) and calls plugin (`8065`) targets are set - - Click Import - Performance Baselines ------------------ diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst index 238ca1d8ca7..f54dfff24d0 100644 --- a/source/configure/calls-troubleshooting.rst +++ b/source/configure/calls-troubleshooting.rst @@ -344,7 +344,7 @@ Prometheus Metrics Analysis Use Prometheus metrics for real-time and historical performance data: -Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. +Import the official `Mattermost Calls dashboard `__ into Grafana for visualization. Advanced Diagnostics ----------------- @@ -389,11 +389,11 @@ Tools to help diagnose client-side issues: 1. **WebRTC Troubleshooter**: - Direct users to [WebRTC Troubleshooter](https://test.webrtc.org/) for browser capability testing. + Direct users to `WebRTC Troubleshooter `__ for browser capability testing. 2. **Network Quality Tests**: - Use [Speedtest](https://www.speedtest.net/) or similar to check internet connection quality. + Use `Speedtest `__ or similar to check internet connection quality. 3. **Browser-Specific WebRTC Info**: diff --git a/source/images/calls-channel-enable-disable.png b/source/images/calls-channel-enable-disable.png new file mode 100644 index 0000000000000000000000000000000000000000..a2751779dadbd39f0b8f5802fdc4815449b9d40e GIT binary patch literal 194225 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

E9?VoxA8jFbd6Zw;V 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

5STlcc`wz|yWu*?``gO2-&NY6 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%0Dk>eF7hbFi+nd!*qdxcREpPd0Bb8ao( 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 G{Qn;wuFRwW literal 0 HcmV?d00001 From 15f73b1393bd6de1e0e7f6111d9831f54b1449dc Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 11:02:23 -0400 Subject: [PATCH 17/60] Transitioned all Calls docs to Markdown Attempted to merge some edits that happened in the time between I switched to RST and back to MD. Need to double check those changes make it to the final merge. --- source/configure/calls-deployment.md | 514 +++++-------------- source/configure/calls-kubernetes.md | 163 ++++++ source/configure/calls-metrics-monitoring.md | 245 +++++++++ source/configure/calls-offloader-setup.md | 368 +++++++++++++ source/configure/calls-rtcd-setup.md | 378 ++++++++++++++ source/configure/calls-troubleshooting.md | 406 +++++++++++++++ 6 files changed, 1676 insertions(+), 398 deletions(-) create mode 100644 source/configure/calls-kubernetes.md create mode 100644 source/configure/calls-metrics-monitoring.md create mode 100644 source/configure/calls-offloader-setup.md create mode 100644 source/configure/calls-rtcd-setup.md create mode 100644 source/configure/calls-troubleshooting.md diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 6ec820a9c7d..bd54c0911e7 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -1,30 +1,56 @@ -# Calls self-hosted deployment +# Calls Deployment Overview -```{include} ../_static/badges/allplans-selfhosted.md + +```{include} ../_static/badges/allplans-cloud-selfhosted.md ``` -Mattermost Calls is an excellent option for organizations demanding enhanced security and control over their communication infrastructure. Calls is designed to operate securely in self-hosted deployments, including [air-gapped environments](https://docs.mattermost.com/configure/calls-deployment.html#air-gapped-deployments), ensuring private communication without reliance on public internet connectivity with flexible configuration options for complex network requirements. +This document provides an overview of Mattermost Calls deployment options for self-hosted environments, including [air-gapped environments](https://docs.mattermost.com/configure/calls-deployment.html#air-gapped-deployments), ensuring private communication without reliance on public internet connectivity with flexible configuration options for complex network requirements. -This document provides information on how to successfully make the Calls plugin work on self-hosted deployments. It also outlines some of the most common deployment strategies with example diagrams, and provides the deployment guidelines for the recording, transcription, and live captions service. +```{toctree} +:maxdepth: 1 +:hidden: -## Terminology +calls-rtcd-setup.md +calls-offloader-setup.md +calls-metrics-monitoring.md +calls-kubernetes.md +calls-troubleshooting.md +``` + +## Quick Links + +For detailed information on specific topics, please refer to these specialized guides: -- [WebRTC](https://bloggeek.me/webrtcglossary/webrtc-2/): The set of underlying protocols/specifications on top of which calls are implemented. -- **RTC (Real Time Connection)**: The real-time connection. This is the channel used to send media tracks (audio/video/screen). -- **WS (WebSocket)**: The WebSocket connection. This is the channel used to set up a connection (signaling process). -- [NAT (Network Address Translation)](https://bloggeek.me/webrtcglossary/nat/): A networking technique to map IP addresses. -- [STUN (Session Traversal Utilities for NAT)](https://bloggeek.me/webrtcglossary/stun/): A protocol/service used by WebRTC clients to help traversing NATs. On the server side it's mainly used to figure out the public IP of the instance. -- [TURN (Traversal Using Relays around NAT)](https://bloggeek.me/webrtcglossary/turn/): A protocol/service used to help WebRTC clients behind strict firewalls connect to a call through media relay. +- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Comprehensive guide for setting up the calls-offloader service for recording and transcription +- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments -## Plugin components +## About Mattermost Calls -- **Calls plugin**: This is the main entry point and a requirement to enable channel calls. +Mattermost Calls provides integrated audio calling and screen sharing capabilities within Mattermost channels. It's built on WebRTC technology and can be deployed either: -- **rtcd**: This is an optional service that can be deployed to offload all the functionality and data processing involved with the WebRTC connections. Read more about when and why to use [rtcd](#the-rtcd-service) below. +1. **Integrated mode**: Built into the Calls plugin (simpler, suitable for smaller deployments) +2. **RTCD mode**: Using a dedicated service for improved performance and scalability (recommended for production environments) -## Requirements +## Terminology + +- [WebRTC](https://bloggeek.me/webrtcglossary/webrtc-2/): The set of protocols on which calls are built +- **RTC**: Real-Time Connection channel used for media (audio/video/screen) +- **WS**: WebSocket connection used for signaling and connection setup +- **SFU**: Selective Forwarding Unit, routes media between participants +- [NAT](https://bloggeek.me/webrtcglossary/nat/): Network Address Translation for mapping IP addresses +- [STUN](https://bloggeek.me/webrtcglossary/stun/): Protocol used by WebRTC clients to help traverse NATs +- [TURN](https://bloggeek.me/webrtcglossary/turn/): Protocol to relay media for clients behind strict firewalls + +## Key Components -### Server +- **Calls plugin**: The main plugin that enables calls functionality. Installed by default in Mattermost self-hosted deployments. +- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. See [RTCD Setup and Configuration](calls-rtcd-setup.html) for details. +- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. See [Calls Offloader Setup and Configuration](calls-offloader-setup.html) for setup and troubleshooting details. + +## Network Requirements - Run Mattermost server on a secure (HTTPs) connection. This is a necessary requirement on the client to allow capturing devices (e.g., microphone, screen). See the [config TLS](https://docs.mattermost.com/deploy/server/setup-tls.html) section for more info. - See [network requirements](#network) below. @@ -119,6 +145,8 @@ This document provides information on how to successfully make the Calls plugin +For complete network requirements, see the [RTCD Setup and Configuration](calls-rtcd-setup.html) guide. + #### Air-gapped deployments Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: @@ -131,81 +159,72 @@ Mattermost Calls can function in air-gapped environments. Exposing Calls to the - All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. - For group calls up to 50 concurrent users, Mattermost Enterprise, Professional, or Mattermost Cloud is required. -- Enterprise customers can also [record calls](https://docs.mattermost.com/collaborate/make-calls.html#record-a-call), enable [live text captions](https://docs.mattermost.com/collaborate/make-calls.html#live-captions-during-calls) during calls, and [transcribe recorded calls](https://docs.mattermost.com/collaborate/make-calls.html#transcribe-recorded-calls). We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the [dedicated rtcd service](#the-rtcd-service). -- For Mattermost self-hosted deployments, System admins need to enable and configure the plugin [using the System Console](https://docs.mattermost.com/configure/plugins-configuration-settings.html#calls). The default maximum number of participants is unlimited; however, we recommend a maximum of 50 participants per call. Maximum call participants is configurable by going to **System Console > Plugin Management > Calls > Max call participants**. Call participant limits greatly depends on instance resources. For more details, refer to the [performance section](#performance) below. +- Enterprise customers can also [record calls](https://docs.mattermost.com/collaborate/make-calls.html#record-a-call), enable [live text captions](https://docs.mattermost.com/collaborate/make-calls.html#live-captions-during-calls) during calls, and [transcribe recorded calls](https://docs.mattermost.com/collaborate/make-calls.html#transcribe-recorded-calls). We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the [dedicated RTCD service](#when-to-use-rtcd). +- For Mattermost self-hosted deployments, System admins need to enable and configure the plugin [using the System Console](https://docs.mattermost.com/configure/plugins-configuration-settings.html#calls). The default maximum number of participants is unlimited; however, we recommend a maximum of 50 participants per call. Maximum call participants is configurable by going to **System Console > Plugin Management > Calls > Max call participants**. Call participant limits greatly depends on instance resources. For more details, refer to the [Performance Considerations](#performance-considerations) section below. ## Configuration -For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in the [System Console](https://docs.mattermost.com/configure/plugins-configuration-settings.html#calls). +For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in the [System Console](/configure/plugins-configuration-settings.html#calls). -## Modes of operation +## Deployment Architecture Options -Depending on how the Mattermost server is running, there are several modes under which the Calls plugin can operate. Please refer to the section below on [the rtcd service](#the-rtcd-service) to learn about the `rtcd` and the Selective Forwarding Unit (SFU). +Mattermost Calls can be deployed in several configurations: -| Mattermost deployment | SFU | SFU deployment | -|-----------------------|-----|----------------| -| Single instance | integrated | | -| Single instance | rtcd | | -| High availability cluster-based | integrated | clustered | -| High availability cluster-based | rtcd | | +### Single Instance Deployments -### Single instance +#### Integrated Mode -#### Integrated +The WebRTC service runs within the Calls plugin on the Mattermost server. This is the default mode when first installing the plugin on a single Mattermost instance setup. The WebRTC service is integrated in the plugin itself and runs alongside the Mattermost server. -This is the default mode when first installing the plugin on a single Mattermost instance setup. The WebRTC service is integrated in the plugin itself and runs alongside the Mattermost server. +![Integrated configuration model of a single instance](../images/calls-deployment-image3.png) -![A diagram of the integrated configuration model of a single instance.](/images/calls-deployment-image3.png) +#### RTCD Mode -#### rtcd +A dedicated RTCD service handles media routing, reducing load on the Mattermost server. -An external, dedicated and scalable WebRTC service (`rtcd`) is used to handle all calls media routing. +![Web RTC deployment configuration](../images/calls-deployment-image7.png) -![A diagram of a Web RTC deployment configuration.](/images/calls-deployment-image7.png) +### High Availability Deployments -### High availability cluster-based - -#### Clustered +#### Clustered Mode This is the default mode when running the plugin in a high availability cluster-based deployment. Every Mattermost node will run an instance of the plugin that includes a WebRTC service. Calls are distributed across all available nodes through the existing load-balancer: a call is hosted on the instance where the initiating websocket connection (first client to join) is made. A single call will be hosted on a single cluster node. -![A diagram of a clustered calls deployment.](/images/calls-deployment-image5.png) +![Clustered calls deployment](../images/calls-deployment-image5.png) -#### rtcd (High Availability) +#### RTCD with High Availability -![A diagram of an rtcd deployment.](/images/calls-deployment-image2.png) +Dedicated RTCD services handle media routing for high availability. -## Performance +![RTCD deployment with high availability](../images/calls-deployment-image2.png) -Calls performance primarily depends on two resources: CPU and bandwidth (both network latency and overall throughput). The final consumption exhibits quadratic growth with the number of clients transmitting and receiving media. +### Kubernetes Deployments -As an example, a single call with 10 participants of which two are unmuted (transmitting voice data) will generally consume double the resources than the same call with a single participant unmuted. What ultimately counts towards performance is the overall number of concurrent media flows (in/out) across the server. +RTCD is the only officially supported approach for Kubernetes deployments. For detailed information on deploying Mattermost Calls in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the [Calls Deployment on Kubernetes](calls-kubernetes.html) guide. -### Benchmarks +## When to Use RTCD -Here are the results from internally conducted performance and ceiling tests on a dedicated `rtcd` instance: +The dedicated RTCD service (available with Enterprise license) is recommended for: -#### Deployment specifications +- **Production environments**: Isolates call traffic from other Mattermost services +- **Performance optimization**: Dedicated service tuned for real-time media +- **Scalability**: Add RTCD instances as call volume grows +- **Call stability**: Calls continue even if Mattermost server needs to restart +- **Kubernetes deployments**: Required for officially supported Kubernetes deployments -- 1x r6i.large nginx proxy -- 3x c5.large MM app nodes (HA) -- 2x db.x2g.xlarge RDS Aurora MySQL v8 (one writer, one reader) -- 1x (c7i.xlarge, c7i.2xlarge, c7i.4xlarge) RTCD -- 2x c7i.2xlarge load-test agents +For detailed RTCD setup instructions, see the [RTCD Setup and Configuration](calls-rtcd-setup.html) guide. -#### App specifications +## Call Recording and Transcription -- Mattermost v9.6 -- Mattermost Calls v0.28.0 -- RTCD v0.16.0 -- load-test agent v0.28.0 +For call recording and transcription, you need to: -#### Media specifications +1. Deploy the `calls-offloader` service +2. Configure the service URL in the System Console +3. Enable call recordings and/or transcriptions in the plugin settings -- Speech sample bitrate: 80Kbps -- Screen sharing sample bitrate: 1.6Mbps +## Air-Gapped Deployments -#### Results +Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: @@ -414,329 +433,65 @@ Here are the results from internally conducted performance and ceiling tests on
-```{note} -- The tests focused on a single, vertically scaled RTCD instance to understand the processing limits within a single node. Scaling the RTCD service horizontally should be sufficient to support a higher number of calls. -- RTCD processes were executed with all performance profiling enabled (including block and mutex). This resulted in some computational overhead. -- Both speech and screen samples have slightly higher bitrates than the average produced by a real client (e.g., a browser). This gives us some safety margin over real-world deployments. -``` - -### Dedicated service - -For Enterprise customers we offer a way to offload performance costs through a [dedicated service](https://github.com/mattermost/rtcd) that can be used to further scale up calls. - -### Load testing - -We provide a [load-test tool](https://github.com/mattermost/mattermost-plugin-calls/tree/main/lt) that can be used to simulate and measure the performance impact of calls. - -### Monitoring - -Both the plugin and the external `rtcd` service expose some Prometheus metrics to monitor performance. We provide an [official dashboard](https://grafana.com/grafana/dashboards/23225-mattermost-calls-performance-monitoring/) that can be imported in Grafana. You can refer to [Performance monitoring](https://docs.mattermost.com/scale/deploy-prometheus-grafana-for-performance-monitoring.html) for more information on how to set up Prometheus and visualize metrics through Grafana. - -#### Calls plugin metrics - -Metrics for the calls plugin are exposed through the `/plugins/com.mattermost.calls/metrics` subpath under the existing Mattermost server metrics endpoint. This is controlled by the [Listen address for performance](https://docs.mattermost.com/configure/environment-configuration-settings.html#listen-address-for-performance) configuration setting. It defaults to port `8067`. - -```{note} -- The [Metrics plugin](https://docs.mattermost.com/scale/collect-performance-metrics.html) collects application-level metrics only and does not make system or OS-level calls. As a result, data typically derived from system-level metrics may be missing in the Grafana panel. -- On Mattermost versions prior to v9.5, plugin metrics were exposed through the public `/plugins/com.mattermost.calls/metrics` API endpoint controlled by the [Web server listen address](https://docs.mattermost.com/configure/environment-configuration-settings.html#web-server-listen-address) configuration setting. This defaults to port `8065`. -``` - -**Process** - -- `mattermost_plugin_calls_process_cpu_seconds_total`: Total user and system CPU time spent in seconds. -- `mattermost_plugin_calls_process_max_fds`: Maximum number of open file descriptors. -- `mattermost_plugin_calls_process_open_fds`: Number of open file descriptors. -- `mattermost_plugin_calls_process_resident_memory_bytes`: Resident memory size in bytes. -- `mattermost_plugin_calls_process_virtual_memory_bytes`: Virtual memory size in bytes. - -**WebRTC connection** - -- `mattermost_plugin_calls_rtc_conn_states_total`: Total number of RTC connection state changes. -- `mattermost_plugin_calls_rtc_errors_total`: Total number of RTC errors. -- `mattermost_plugin_calls_rtc_rtp_bytes_total`: Total number of sent/received RTP packets in bytes. - - - Note: removed as of v0.16.0 - -- `mattermost_plugin_calls_rtc_rtp_packets_total`: Total number of sent/received RTP packets. - - - Note: removed as of v0.16.0 - -- `mattermost_plugin_calls_rtc_rtp_tracks_total`: Total number of incoming/outgoing RTP tracks. - - - Note: added as of v0.16.0 - -- `mattermost_plugin_calls_rtc_sessions_total`: Total number of active RTC sessions. - -**Application** - -- `mattermost_plugin_calls_app_handlers_time_bucket`: Time taken to execute app handlers. - - - `mattermost_plugin_calls_app_handlers_time_sum` - - - `mattermost_plugin_calls_app_handlers_time_count` - -**Database** +Calls performance primarily depends on: -- `mattermost_plugin_calls_store_ops_total`: Total number of db store operations. -- `mattermost_plugin_calls_store_methods_time_bucket`: Time taken to execute store methods. +- **CPU resources**: More participants require more processing power +- **Network bandwidth**: Both incoming and outgoing traffic increases with participant count +- **Active speakers**: Unmuted participants require significantly more resources - - `mattermost_plugin_calls_store_methods_time_sum` +For detailed performance metrics, benchmarks, and monitoring guidance, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide. - - `mattermost_plugin_calls_store_methods_time_count` -- `mattermost_plugin_calls_cluster_mutex_grab_time_bucket`: Time taken to grab global mutexes. +## Frequently Asked Questions - - `mattermost_plugin_calls_cluster_mutex_grab_time_sum` - - - `mattermost_plugin_calls_cluster_mutex_grab_time_count` -- `mattermost_plugin_calls_cluster_mutex_locked_time_bucket`: Time spent locked in global mutexes. - - - `mattermost_plugin_calls_cluster_mutex_locked_time_sum` - - - `mattermost_plugin_calls_cluster_mutex_locked_time_count` - -**WebSocket** - -- `mattermost_plugin_calls_websocket_connections_total`: Total number of active WebSocket connections. -- `mattermost_plugin_calls_websocket_events_total`: Total number of WebSocket events. - -**Jobs** - -- `mattermost_plugin_calls_jobs_live_captions_new_audio_len_ms_bucket`: Duration (in ms) of new audio transcribed for live captions. - - - `mattermost_plugin_calls_jobs_live_captions_new_audio_len_ms_sum` - - - `mattermost_plugin_calls_jobs_live_captions_new_audio_len_ms_count` -- `mattermost_plugin_calls_jobs_live_captions_pktPayloadCh_buf_full`: Total packets of audio data dropped due to full channel. -- `mattermost_plugin_calls_jobs_live_captions_window_dropped`: Total windows of audio data dropped due to pressure on the transcriber. - -#### WebRTC service metrics - -Metrics for the `rtcd` service are exposed through the `/metrics` API endpoint under the `rtcd` API listener controlled by the `api.http.listen_address` configuration setting. It defaults to port `8045`. - -**Process** - -- `rtcd_process_cpu_seconds_total`: Total user and system CPU time spent in seconds. -- `rtcd_plugin_calls_process_max_fds`: Maximum number of open file descriptors. -- `rtcd_plugin_calls_process_open_fds`: Number of open file descriptors. -- `rtcd_plugin_calls_process_resident_memory_bytes`: Resident memory size in bytes. -- `rtcd_plugin_calls_process_virtual_memory_bytes`: Virtual memory size in bytes. - -**WebRTC Connection** - -- `rtcd_rtc_conn_states_total`: Total number of RTC connection state changes. -- `rtcd_rtc_errors_total`: Total number of RTC errors. -- `rtcd_rtc_rtp_bytes_total`: Total number of sent/received RTP packets in bytes. -- `rtcd_rtc_rtp_packets_total`: Total number of sent/received RTP packets. -- `rtcd_rtc_rtp_tracks_total`: Total number of incoming/outgoing RTP tracks. -- `rtcd_rtc_sessions_total`: Total number of active RTC sessions. -- `rtcd_rtc_rtp_tracks_writes_time_bucket`: Time taken to write to outgoing RTP tracks. - - - `rtcd_rtc_rtp_tracks_writes_time_sum` - - - `rtcd_rtc_rtp_tracks_writes_time_count` - -**WebSocket** - -- `rtcd_ws_connections_total`: Total number of active WebSocket connections. -- `rtcd_ws_messages_total`: Total number of received/sent WebSocket messages. - -#### Configuration - -A sample Prometheus configuration to scrape both plugin and `rtcd` metrics could look like this: - -``` -scrape_configs: -- job_name: node - static_configs: - - targets: ['rtcd-0:9100','rtcd-1:9100', 'calls-offloader-1:9100', 'calls-offloader-2:9100'] -- job_name: calls - metrics_path: /plugins/com.mattermost.calls/metrics - static_configs: - - targets: ['app-0:8067','app-1:8067','app-2:8067'] -- job_name: rtcd - static_configs: - - targets: ['rtcd-0:8045', 'rtcd-1:8045'] -``` - -### System tunings - -If you want to host many calls or calls with a large number of participants, take a look at the following platform specific (Linux) tunings (this is the only officially supported target for the plugin right now): - -``` -# Setting the maximum buffer size of the receiving UDP buffer to 16MB -net.core.rmem_max = 16777216 - -# Setting the maximum buffer size of the sending UDP buffer to 16MB -net.core.wmem_max = 16777216 - -# Allow to allocate more memory as needed for more control messages that need to be sent for each socket connected -net.core.optmem_max = 16777216 -``` - -## The rtcd service - -```{include} ./calls-rtcd-ent-only.md -``` - -The Calls plugin has a built-in [Selective Forwarding Unit (SFU)](https://bloggeek.me/webrtcglossary/sfu/) to route audio and screensharing data. This is the `integrated` option described in the [Modes of operation](#modes-of-operation) section above. But this SFU functionality can be deployed separately as an external `rtcd` instance. - -### Reasons to use the `rtcd` service - -This section will help you understand when and why your organization would want to use `rtcd`. - -```{note} -`rtcd` is a standalone service, which adds operational complexity, maintenance costs, and requires an enterprise licence. For those who are evaluating Calls, and for many small instances of Mattermost, the integrated SFU (the one included in the Calls plugin) may be sufficient initially. -``` +**Is calls traffic encrypted?** +Yes, using WebRTC security standards (DTLS/SRTP). Traffic is encrypted in transit. -The `rtcd` service is the recommended way to host Calls for the following reasons: +**Are there any third-party services involved?** +Only a Mattermost STUN server (`stun.global.calls.mattermost.com`) is used by default. This can be removed if you set the ICE Host Override configuration. -- **Performance of the main Mattermost server(s).** When the Calls plugin runs the SFU, calls traffic is added to the processing load of the server running the rest of your Mattermost services. If Calls traffic spikes, it can negatively affect the responsiveness of these services. Using an rtcd service isolates the calls traffic processing to those rtcd instances, and also reduces costs by minimizing CPU usage spikes. +**Is using UDP a requirement?** +UDP is recommended protocol to serve real-time media as it allows for the lowest latency between peers, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. -- **Performance, scalability, and stability of the Calls product.** If Calls traffic spikes, or more overall capacity is needed, `rtcd` servers can be added to balance the load. As an added benefit, if the Mattermost traffic spikes, or if a Mattermost instance needs to be restarted, those people in a current call will not be affected - current calls won't be dropped. - -Some caveats apply here. Web socket events (for example: emoji reactions, hand raising, muting/unmuting) will not be transmitted while the main Mattermost server is down. But the call itself will continue while the main server restarts. - -- **Kubernetes deployments.** In a Kubernetes deployment, `rtcd` is strongly recommended; it is currently the only officially supported way to run Calls. -- **Technical benefits.** The dedicated `rtcd` service has been optimized and tuned at the system/network level for real-time audio/video traffic, where latency is generally more important than throughput. - -In general, `rtcd` is the preferred solution for a performant and scalable deployment. With `rtcd`, the Mattermost server will be minimally impacted when hosting a high number of calls. - -See the [Mattermost rtcd repository documentation](https://github.com/mattermost/rtcd/blob/master/README.md) on GitHub for details on [how to run calls through the service](https://github.com/mattermost/rtcd/blob/master/docs/getting_started.md), as well as: - -- [Key implementation details](https://github.com/mattermost/rtcd/blob/master/docs/implementation.md) -- [Project structure](https://github.com/mattermost/rtcd/blob/master/docs/project_structure.md) -- [Configuration overrides](https://github.com/mattermost/rtcd/blob/master/docs/env_config.md) -- [Authentication flow](https://github.com/mattermost/rtcd/blob/master/docs/security.md) - -### Horizontal scalability - -The supported way to enable horizontal scalability for Calls is through a form of DNS based load balancing. This can be achieved regardless of how the `rtcd` service is deployed (bare bone instance, Kubernetes, or an alternate way). - -In order for this to work, the [RTCD Service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtcd-service-url) should point to a hostname that resolves to multiple IP addresses, each pointing to a running `rtcd` instance. The Mattermost Calls plugin will then automatically distribute calls amongst the available hosts. - -The expected requirements are the following: - -- When a new `rtcd` instance is deployed, it should be added to the DNS record. The plugin side will then be able to pick it up and start assigning calls to the new host. -- If a `rtcd` instance goes down, it should be removed from the DNS record. The plugin side can then detect the change and stop assigning new calls to that host. - -```{note} -- Load balancing is done at the call level. This means that a single call will always live on a single `rtcd` instance. -- There's currently no support for spreading sessions belonging to the same call across a fleet of instances. -``` - -## Configure recording, transcriptions, and live captions - -Before you can start recording, transcribing, and live captioning calls, you need to configure the `calls-offloader` job service. See the [calls-offloader](https://github.com/mattermost/calls-offloader/blob/master/docs/getting_started.md) documentation on GitHub for details on deploying and running this service. [Performance and scalability recommendations](https://github.com/mattermost/calls-offloader/blob/master/docs/performance.md) related to this service are also available on GitHub. - -```{note} -If deploying the service in a Kubernetes cluster, refer to the later section on [Helm charts](#helm-charts). -``` - -Once the `calls-offloader` service is running, recordings should be explicitly enabled through the [Enable call recordings](https://docs.mattermost.com/configure/plugins-configuration-settings.html#enable-call-recordings) config setting and the service's URL should be configured using [Job service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#job-service-url). - -Call transcriptions can be enabled through the [Enable call transcriptions](https://docs.mattermost.com/configure/plugins-configuration-settings.html#enable-call-transcriptions) configuration setting. - -Live captions can be enabled through the [Enable live captions](https://docs.mattermost.com/configure/plugins-configuration-settings.html#enable-live-captions) configuration setting. - -```{note} -- The call transcriptions functionality is available starting in Calls version v0.22.0. -- The live captions functionality is available starting in Calls version v0.26.2. -``` - -## Kubernetes deployments - -The Calls plugin has been designed to integrate well with Kubernetes to offer improved scalability and control over the deployment. - -This is a sample diagram showing how the `rtcd` standalone service can be deployed in a Kubernetes cluster: - -![A diagram of calls deployed in a Kubernetes cluster.](/images/calls-deployment-kubernetes.png) - -If Mattermost isn't deployed in a Kubernetes cluster, and you want to use this deployment type, see the [Deploy Mattermost on Kubernetes](https://docs.mattermost.com/install/install-kubernetes.html) documentation. - -### Helm Charts - -The recommended way to deploy Calls related components and services in a Kubernetes deployment is to use the officially provided Helm charts. Related documentation including detailed information on how to deploy these services can be found in our `mattermost-helm` repository: - -- [rtcd Helm chart](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-rtcd) - -- [calls-offloader Helm chart](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-calls-offloader) - -### Limitations - -Due to the inherent complexities of hosting a WebRTC service, some limitations apply when deploying Calls in a Kubernetes environment. - -One key requirement is that each `rtcd` process live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally not go through a standard ingress but directly to the pod running the `rtcd` process. - -The general recommendation is to expose one external IP address per `rtcd` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. - -If, for some reason, exposing multiple IP addresses is not possible in your environment, port mapping (NAT) can be used. In this scenario different ports are used to map the respective `rtcd` nodes behind the single external IP. Example: - -```sh -EXT_IP:8443 -> rtcdA:8443 -EXT_IP:8444 -> rtcdB:8443 -EXT_IP:8445 -> rtcdC:8443 -``` - -This case requires a couple of extra configurations: - -- NAT mappings need to be in place for every `rtcd` node. This is usually done at the ingress point (e.g., ELB, NLB, etc). -- The `RTCD_RTC_ICEHOSTPORTOVERRIDE` config should be used to pass a full mapping of node IPs and their respective port. - - Example: `RTCD_RTC_ICEHOSTPORTOVERRIDE=rtcdA_IP/8443,rtcdB_IP/8444,rtcdC_IP/8445` -- The `RTCD_RTC_ICEHOSTOVERRIDE` should be used to set the external IP address. - -```{note} -One option to limit these static mappings is to reduce the size of the local subnet (e.g., to `/29`). -``` - -## Frequently asked questions - -### Is there encryption? - -Media (audio/video) is encrypted using security standards as part of WebRTC. It's mainly a combination of DTLS and SRTP. It's not e2e encrypted in the sense that in the current design all media needs to go through Mattermost which acts as a media router and has complete access to it. Media is then encrypted back to the clients so it's secured during transit. In short: only the participant clients and the Mattermost server have access to unencrypted call data. - -### Are there any third-party services involved? - -The only external service used is a Mattermost official STUN server (`stun.global.calls.mattermost.com`) which is configured as default. This is primarily used to find the public address of the Mattermost instance if none is provided through the [ICE Host Override](https://docs.mattermost.com/configure/plugins-configuration-settings.html#ice-host-override) option. The only information sent to this service is the IP addresses of clients connecting as no other traffic goes through it. It can be removed in cases where the [ICE Host Override](https://docs.mattermost.com/configure/plugins-configuration-settings.html#ice-host-override) setting is provided. - -```{note} -In air-gapped deployments, using STUN servers is not necessary since all connections remain within the local network. -``` - -### Is using UDP a requirement? - -Yes, UDP is the recommended protocol to serve real-time media as it allows for the lowest latency between peers. However, there are a couple of possible solutions to cover clients that due to limitations or strict firewalls are unable to use UDP: +If clients are unable to connect using UDP (due to limitations or strict firewalls), you have a few options: - Since plugin version 0.17 and `rtcd` version 0.11 the RTC service will listen for TCP connections in addition to UDP ones. If configured correctly (e.g. using commonly allowed ports such as 80 or 443) it's possible to have clients connect directly through TCP when unable to do it through the preferred UDP channel. - Run calls through an external TURN server that listens on TCP and relays all media traffic between peers. However, this is a sub-optimal solution that should be avoided if possible as it will introduce extra latency along with added infrastructural cost. -### Do I need a TURN server? - -TURN becomes necessary when you expect to have clients that are unable to connect through the configured UDP port. This can happen due to very restrictive firewalls that either block non standard ports even in the outgoing direction or don't allow the use of the UDP protocol altogether (e.g. some corporate firewalls). In such cases TURN is needed to allow connectivity. +**Do I need a TURN server?** +Only if clients are behind restrictive firewalls that block UDP. We recommend (and officially support) [coturn](https://github.com/coturn/coturn) if needed. -We officially support and recommend using [coturn](https://github.com/coturn/coturn) for a stable and performant TURN service implementation. +**Can RTCD traffic be kept internal?** +Yes, and it's recommended. Only the media ports need to be accessible to end-users. -### How will this work with an existing reverse proxy sitting in front of Mattermost? +**How will this work with an existing reverse proxy sitting in front of Mattermost?** -Generally clients should connect directly to either Mattermost or, if deployed, the dedicated `rtcd` service through the configured UDP port . However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. +Generally clients should connect directly to either Mattermost or, if deployed, the dedicated `rtcd` service through the configured UDP port. However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. -### Do calls require a dedicated server to work or can they run alongside Mattermost? +**Do calls require a dedicated server to work or can they run alongside Mattermost?** The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). -### Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public? +See [RTCD Setup and Configuration](calls-rtcd-setup.html) for more details on the dedicated RTCD service. + +**Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public?** When possible, it's recommended to keep communication between the Mattermost cluster and the dedicated `rtcd` service under the same private network as this can greatly simplify deployment and security. There's no requirement to expose `rtcd`'s HTTP API to the public internet. -### Can Calls be rolled out on a per-channel basis? +**Can Calls be rolled out on a per-channel basis?** ```{include} ../_static/badges/selfhosted-only.md ``` Yes. Mattermost system admins running self-hosted deployments can enable or disable call functionality per channel. Once [test mode](https://docs.mattermost.com/configure/plugins-configuration-settings.html#test-mode) is enabled for Mattermost Calls: -- Select **Enable calls** for each channel where you want Calls enabled -- Select **Disable calls** for all channels where you want Calls disabled. +1. **Navigate to the channel** where you want to enable or disable Calls +2. **Access the channel menu** by clicking the channel name at the top of the channel +3. **Select the Calls option** from the dropdown menu: + - Select **Enable calls** for each channel where you want Calls enabled + - Select **Disable calls** for all channels where you want Calls disabled + +![Channel menu showing Enable/Disable calls options](../images/calls-channel-enable-disable.png) Once Calls is enabled for specific channels, users can start making calls in those channels. @@ -746,48 +501,11 @@ When [test mode](https://docs.mattermost.com/configure/plugins-configuration-set ## Troubleshooting -### Connectivity issues - -If calls are failing to connect or timing out, it's likely there could be a misconfiguration at either the plugin config or networking level. +For comprehensive troubleshooting steps and debugging techniques, please refer to the [Calls Troubleshooting](calls-troubleshooting.html) guide. -For example, the [RTC Server Port (UDP)](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtc-server-port-udp) or the [RTC Server Port (TCP)](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtc-server-port-tcp) may not be open or forwarded correctly. - -#### Connectivity checks - -An easy way to check whether data can go through is to perform some tests using the `netcat` command line tool. - -On the host running Calls (could be the Mattermost instance itself or the one running `rtcd` depending on the chosen setup), run the following: - -```sh -nc -l -u -p 8443 -``` - -On the client side (i.e., the machine you would normally use to run the Mattermost desktop app or browser), run the following: - -```sh -nc -v -u HOST_IP 8443 -``` - -If connection succeeds, you should be able to send and receive text messages by typing and hitting enter on either side. - -```{note} -`HOST_IP` should generally be the public (client facing) IP of the Mattermost -(or `rtcd`) instance hosting the calls. When set, it should be the value of the [ICE Host Override](https://docs.mattermost.com/configure/plugins-configuration-settings.html#ice-host-override) -config setting. - -`8443` should be changed with the port configured in [RTC Server Port](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtc-server-port-udp). - -The same checks can be performed to test connectivity through the TCP port using the same commands with `-u` flag removed. -``` - -#### Network packets debugging - -A more advanced way to debug networking issues is to use the `tcpdump` command line utility to temporaily monitor network packets flowing in and out of the instance hosting calls. - -On the server side, run the following: - -```sh -sudo tcpdump -n port 8443 -``` +## Next Steps -This command will output information (i.e. source and destination addresses) for all the network packets being sent or received through port `8443`. This is a good way to check whether data is getting in and out of the instance and can be used to quickly identify network configuration issues. +1. For detailed setup instructions, see [RTCD Setup and Configuration](calls-rtcd-setup.html) +2. For monitoring guidance, see [Calls Metrics and Monitoring](calls-metrics-monitoring.html) +3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.html) +4. For Kubernetes deployments, see [Calls Deployment on Kubernetes](calls-kubernetes.html) diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md new file mode 100644 index 00000000000..627bff23982 --- /dev/null +++ b/source/configure/calls-kubernetes.md @@ -0,0 +1,163 @@ +# Calls deployment on Kubernetes + +```{include} ../_static/badges/allplans-cloud-selfhosted.md +``` + +This guide provides detailed information for deploying Mattermost Calls on Kubernetes environments. + +## Overview + +Mattermost Calls has been designed to integrate well with Kubernetes to offer improved scalability and control over the deployment. For Kubernetes deployments, the RTCD service is strongly recommended and is the only officially supported approach. + +## Architecture + +![Calls deployed in a Kubernetes cluster](../images/calls-deployment-kubernetes.png) + +This diagram shows how the RTCD standalone service can be deployed in a Kubernetes cluster. In this architecture: + +1. Calls traffic is handled by dedicated RTCD pods +2. RTCD services are exposed through load balancers +3. Scaling is managed through Kubernetes deployment configurations +4. Call recording and transcription is handled by the calls-offloader service (see [Calls Offloader Setup and Configuration](calls-offloader-setup.html)) + +If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the [Kubernetes operator guide](/install/mattermost-kubernetes-operator.html). + +## Helm Chart Deployment + +The recommended way to deploy Calls-related components in a Kubernetes environment is to use the officially provided Helm charts: + +### RTCD Helm Chart + +The RTCD Helm chart deploys the RTCD service needed for call media handling: + +```bash +helm repo add mattermost https://helm.mattermost.com +helm repo update + +helm install mattermost-rtcd mattermost/mattermost-rtcd \ + --set ingress.enabled=true \ + --set ingress.host=rtcd.example.com \ + --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ + --set rtcd.ice.hostOverride=rtcd.example.com +``` + +For complete configuration options, see the [RTCD Helm chart documentation](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-rtcd). + +### Calls-Offloader Helm Chart + +If you need call recording and transcription capabilities, deploy the calls-offloader service: + +```bash +helm install mattermost-calls-offloader mattermost/mattermost-calls-offloader \ + --set ingress.enabled=true \ + --set ingress.host=calls-offloader.example.com +``` + +For complete configuration options, see the [Calls-Offloader Helm chart documentation](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-calls-offloader). + +## Kubernetes-Specific Configuration + +### Network Configuration + +For Kubernetes deployments, you need to ensure: + +1. UDP traffic is properly routed to RTCD pods (for media) +2. TCP traffic can reach both the Mattermost pods and RTCD pods +3. Load balancers are properly configured to handle UDP traffic +4. Network policies allow the required communications between services + +Recommended annotations for AWS environments: + +```yaml +service.beta.kubernetes.io/aws-load-balancer-backend-protocol: udp +service.beta.kubernetes.io/aws-load-balancer-type: nlb +``` + +### Resource Requirements + +For optimal performance in Kubernetes environments: + +1. **CPU**: At least 2 CPU cores per RTCD pod +2. **Memory**: At least 1GB RAM per RTCD pod +3. **Network**: Sufficient bandwidth for expected call volume (see benchmarks) + +We recommend setting resource limits and requests in your deployment: + +```yaml +resources: + requests: + cpu: 1000m + memory: 1Gi + limits: + cpu: 2000m + memory: 2Gi +``` + +### Scaling Considerations + +Horizontal scaling of RTCD pods is possible, but remember: + +1. Each call is hosted entirely on a single RTCD pod +2. DNS-based load balancing should be used to distribute calls among pods +3. Health checks should ensure that only healthy pods receive new calls +4. Calls remain on their assigned pod for their entire duration + +### Limitations + +Due to the inherent complexities of hosting a WebRTC service, some limitations apply when deploying Calls in a Kubernetes environment. + +One key requirement is that each `rtcd` process must live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally not go through a standard ingress but directly to the pod running the `rtcd` process. + +The general recommendation is to expose one external IP address per `rtcd` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. + +If, for some reason, exposing multiple IP addresses is not possible in your environment, port mapping (NAT) can be used. In this scenario different ports are used to map the respective `rtcd` nodes behind the single external IP. Example: + +```text +EXT_IP:8443 -> rtcdA:8443 +EXT_IP:8444 -> rtcdB:8443 +EXT_IP:8445 -> rtcdC:8443 +``` + +This case requires a couple of extra configurations: + +* NAT mappings need to be in place for every `rtcd` node. This is usually done at the ingress point (e.g., ELB, NLB, etc). + +* The `RTCD_RTC_ICEHOSTPORTOVERRIDE` config should be used to pass a full mapping of node IPs and their respective port. + + * Example: `RTCD_RTC_ICEHOSTPORTOVERRIDE=rtcdA_IP/8443,rtcdB_IP/8444,rtcdC_IP/8445` + +* The `RTCD_RTC_ICEHOSTOVERRIDE` should be used to set the external IP address. + +```{note} +One option to limit these static mappings is to reduce the size of the local subnet (e.g., to `/29`). +``` + +## Monitoring and Metrics + +We recommend deploying Prometheus and Grafana alongside your Calls deployment: + +1. Configure Prometheus to scrape metrics from both Mattermost and RTCD pods +2. Import the official Mattermost Calls dashboard to Grafana +3. Set up alerts for CPU usage, connection failures, and error rates + +For detailed information on metrics collection and monitoring, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide. + +## Troubleshooting + +For Kubernetes-specific troubleshooting: + +1. Check pod logs: `kubectl logs -f deployment/mattermost-rtcd` +2. Verify service connectivity: `kubectl port-forward service/mattermost-rtcd 8045:8045` +3. Ensure UDP traffic is properly routed through your ingress/load balancer +4. Verify network policies allow required communication paths + +For detailed troubleshooting steps, see the [Calls Troubleshooting](calls-troubleshooting.html) guide. + +## Other Calls Documentation + +- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability +- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.html) \ No newline at end of file diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md new file mode 100644 index 00000000000..b93bbfa0bd7 --- /dev/null +++ b/source/configure/calls-metrics-monitoring.md @@ -0,0 +1,245 @@ +# Calls Metrics and Monitoring + +```{include} ../_static/badges/ent-only.md +``` + +This guide provides detailed information on monitoring Mattermost Calls performance and health through metrics and observability tools. Effective monitoring is essential for maintaining optimal call quality and quickly addressing any issues that arise. + +- [Metrics overview](#metrics-overview) +- [Setting up monitoring](#setting-up-monitoring) +- [Key metrics to monitor](#key-metrics-to-monitor) +- [Grafana dashboards](#grafana-dashboards) +- [Alerting recommendations](#alerting-recommendations) +- [Performance baselines](#performance-baselines) + +## Metrics Overview + +Mattermost Calls provides metrics through Prometheus for both the Calls plugin and the RTCD service. These metrics help track: + +- Active call sessions and participants +- Media track statistics +- Connection states and errors +- Resource utilization (CPU, memory, network) +- WebSocket connections and events + +The metrics are exposed through HTTP endpoints: + +- **Calls Plugin**: `/plugins/com.mattermost.calls/metrics` +- **RTCD Service**: `/metrics` (default) or a configured endpoint + +## Setting Up Monitoring + +### Prerequisites + +To monitor Calls metrics, you'll need: + +1. **Prometheus**: For collecting and storing metrics +2. **Grafana**: For visualizing metrics (optional but recommended) + +### Installing Prometheus + +1. **Download and install Prometheus**: + + Visit the [Prometheus download page](https://prometheus.io/download/) for installation instructions. + +2. **Configure Prometheus** to scrape metrics from all Calls-related services: + + Complete `prometheus.yml` configuration for Calls monitoring: + + ```yaml + global: + scrape_interval: 15s + evaluation_interval: 15s + + scrape_configs: + - job_name: 'prometheus' + static_configs: + - targets: ['PROMETHEUS_IP:9090'] + + - job_name: 'mattermost' + metrics_path: /metrics + static_configs: + - targets: ['MATTERMOST_SERVER_IP:8067'] + + - job_name: 'calls-plugin' + metrics_path: /plugins/com.mattermost.calls/metrics + static_configs: + - targets: ['MATTERMOST_SERVER_IP:8067'] + labels: + service_name: 'calls-plugin' + + - job_name: 'rtcd' + metrics_path: /metrics + static_configs: + - targets: ['RTCD_SERVER_IP:8045'] + labels: + service_name: 'rtcd' + + - job_name: 'rtcd-node-exporter' + metrics_path: /metrics + static_configs: + - targets: ['RTCD_SERVER_IP:9100'] + labels: + service_name: 'rtcd' + + - job_name: 'calls_offloader-node-exporter' + metrics_path: /metrics + static_configs: + - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] + labels: + service_name: 'offloader' + ``` + + Replace the placeholder IP addresses with your actual server addresses: + + - `MATTERMOST_SERVER_IP`: IP address of your Mattermost server + - `RTCD_SERVER_IP`: IP address of your RTCD server + - `CALLS_OFFLOADER_SERVER_IP`: IP address of your calls-offloader server (if deployed) + - `PROMETHEUS_IP`: IP address of your Prometheus server + - **Note**: The configuration above uses the default ports (RTCD: `8045`, Mattermost metrics: `8067`, etc.). Adjust these ports in `prometheus.yml` if you have customized them. + + ```{important} + **Metrics Path**: Ensure the metrics paths are correct. The RTCD service exposes metrics at `/metrics` by default, and the Calls plugin at `/plugins/com.mattermost.calls/metrics`. + ``` + + ```{important} + **Metrics Configuration Notice**: Use the `service_name` labels as shown in the configuration above. These labels help organize metrics in dashboards and enable proper service identification. + ``` + + ```{note} + - **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See [node_exporter setup guide](https://prometheus.io/docs/guides/node-exporter/) for installation instructions. + - **calls-offloader**: Only needed if you have call recording/transcription enabled + ``` + +### Installing Grafana + +1. **Download and install Grafana**: + + Visit the [Grafana download page](https://grafana.com/grafana/download) for installation instructions. + +2. **Configure Grafana** to use Prometheus as a data source: + + - Add a new data source in Grafana + - Select Prometheus as the type + - Enter the URL of your Prometheus server + - Test and save the configuration + +3. **Import the Mattermost Calls dashboard**: + + - Navigate to Dashboards > Import in Grafana + - Enter dashboard ID: `23225` or use the direct link: [Mattermost Calls Performance Monitoring](https://grafana.com/grafana/dashboards/23225-mattermost-calls-performance-monitoring/) + - Select your Prometheus data source, and enter values for the + - Confirm the port used for RTCD metrics (default is `8045`), and the port used for the Calls plugin metrics (default is `8067`) + - Click Import to add the dashboard to your Grafana instance + + ```{note} + The dashboard is also available as JSON source from the [Mattermost performance assets repository](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) for manual import or customization. + ``` + +## Key Metrics to Monitor + +### RTCD Metrics + +#### Process Metrics + +These metrics help monitor the health and resource usage of the RTCD process: + +- `rtcd_process_cpu_seconds_total`: Total CPU time spent +- `rtcd_process_open_fds`: Number of open file descriptors +- `rtcd_process_max_fds`: Maximum number of file descriptors +- `rtcd_process_resident_memory_bytes`: Memory usage in bytes +- `rtcd_process_virtual_memory_bytes`: Virtual memory used + +**Interpretation**: + +- High CPU usage (>70%) may indicate the need for additional RTCD instances +- Steadily increasing memory usage might indicate a memory leak +- High number of file descriptors could indicate connection handling issues + +#### WebRTC Connection Metrics + +These metrics track the WebRTC connections and media flow: + +- `rtcd_rtc_conn_states_total{state="X"}`: Count of connections in different states +- `rtcd_rtc_errors_total{type="X"}`: Count of RTC errors by type +- `rtcd_rtc_rtp_tracks_total{direction="X"}`: Count of RTP tracks (incoming/outgoing) +- `rtcd_rtc_sessions_total`: Total number of active RTC sessions + +**Interpretation**: + +- Increasing error counts may indicate connectivity or configuration issues +- Track by state to see if connections are failing to establish or dropping +- Larger track counts require proportionally more CPU and bandwidth + +#### WebSocket Metrics + +These metrics track the signaling channel: + +- `rtcd_ws_connections_total`: Total number of active WebSocket connections +- `rtcd_ws_messages_total{direction="X"}`: Count of WebSocket messages (sent/received) + +**Interpretation**: + +- Connection count should match expected participant numbers +- Unusually high message counts might indicate protocol issues +- Connection drops might indicate network issues + +### Calls Plugin Metrics + +Similar metrics are available for the Calls plugin with the following prefixes: + +- Process metrics: `mattermost_plugin_calls_process_*` +- WebRTC connection metrics: `mattermost_plugin_calls_rtc_*` +- WebSocket metrics: `mattermost_plugin_calls_websocket_*` +- Store metrics: `mattermost_plugin_calls_store_ops_total` + +## Performance Baselines + +The following performance benchmarks provide baseline metrics for RTCD deployments under various load conditions and configurations. + +**Deployment specifications** + +- 1x r6i.large nginx proxy +- 3x c5.large MM app nodes (HA) +- 2x db.x2g.xlarge RDS Aurora MySQL v8 (one writer, one reader) +- 1x (c7i.xlarge, c7i.2xlarge, c7i.4xlarge) RTCD +- 2x c7i.2xlarge load-test agents + +**App specifications** + +- Mattermost v9.6 +- Mattermost Calls v0.28.0 +- RTCD v0.16.0 +- load-test agent v0.28.0 + +**Media specifications** + +- Speech sample bitrate: 80Kbps +- Screen sharing sample bitrate: 1.6Mbps + +**Results** + +Below are the detailed benchmarks based on internal performance testing: + +| Calls | Users/call | Unmuted/call | Screen sharing | CPU (avg) | Memory (avg) | Bandwidth (in/out) | Instance (EC2) | +|-------|------------|--------------|----------------|-----------|--------------|--------------------|--------------| +| 100 | 8 | 2 | no | 60% | 0.5GB | 22Mbps / 125Mbps | c6i.xlarge | +| 100 | 8 | 2 | no | 30% | 0.5GB | 22Mbps / 125Mbps | c6i.2xlarge | +| 100 | 8 | 2 | yes | 86% | 0.7GB | 280Mbps / 2.2Gbps | c6i.2xlarge | +| 10 | 50 | 2 | no | 35% | 0.3GB | 5.25Mbps / 86Mbps | c6i.xlarge | +| 10 | 50 | 2 | no | 16% | 0.3GB | 5.25Mbps / 86Mbps | c6i.2xlarge | +| 10 | 50 | 2 | yes | 90% | 0.3GB | 32Mbps / 1.33Gbps | c6i.xlarge | +| 10 | 50 | 2 | yes | 45% | 0.3GB | 32Mbps / 1.33Gbps | c6i.2xlarge | +| 5 | 200 | 2 | no | 65% | 0.6GB | 8.2Mbps / 180Mbps | c6i.xlarge | +| 5 | 200 | 2 | no | 30% | 0.6GB | 8.2Mbps / 180Mbps | c6i.2xlarge | +| 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | + +## Other Calls Documentation + +- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription +- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques + +Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md new file mode 100644 index 00000000000..79dd55e3c0c --- /dev/null +++ b/source/configure/calls-offloader-setup.md @@ -0,0 +1,368 @@ +# Calls Offloader Setup and Configuration + +```{include} ../_static/badges/ent-only.md +``` + + +This guide provides detailed instructions for setting up, configuring, and validating the Mattermost calls-offloader service used for call recording and transcription features. + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Installation and deployment](#installation-and-deployment) +- [Configuration](#configuration) +- [Validation and testing](#validation-and-testing) +- [Integration with Mattermost](#integration-with-mattermost) +- [Troubleshooting](#troubleshooting) + +## Overview + +The calls-offloader service is a dedicated microservice that handles resource-intensive tasks for Mattermost Calls, including: + +- **Call recording**: Captures audio and screen sharing content from calls +- **Call transcription**: Provides automated transcription of recorded calls +- **Live captions** (Experimental): Real-time transcription during active calls + +By offloading these tasks to a dedicated service, the main Mattermost server and RTCD service can focus on core functionality while maintaining optimal performance. + +## Prerequisites + +Before deploying calls-offloader, ensure you have: + +- A Mattermost Enterprise license +- A properly configured Mattermost Calls deployment (either integrated or with RTCD) +- Docker installed and running (for Docker-based job execution) +- Sufficient storage space for recordings (see [Storage Requirements](#storage-requirements)) +- A server or container environment with adequate resources + +### System Requirements + +For detailed system requirements and performance recommendations, refer to the [calls-offloader performance documentation](https://github.com/mattermost/calls-offloader/blob/master/docs/performance.md). + +### Storage Requirements + +Call recordings can consume significant storage space: + +- Audio-only recordings: ~1MB per minute per participant +- Screen sharing recordings: ~10-50MB per minute depending on content + +## Installation and Deployment + +### Bare Metal or VM Deployment + +1. Download the latest release from the [calls-offloader GitHub repository](https://github.com/mattermost/calls-offloader/releases) + +2. Create the necessary directories: + + ```bash + sudo mkdir -p /opt/calls-offloader/data/db + sudo useradd --system --home /opt/calls-offloader calls-offloader + sudo chown -R calls-offloader:calls-offloader /opt/calls-offloader + ``` + +3. Create a configuration file (`/opt/calls-offloader/config.toml`): + + ```toml + [api] + http.listen_address = ":4545" + http.tls.enable = false + http.tls.cert_file = "" + http.tls.cert_key = "" + security.allow_self_registration = true + security.enable_admin = true + security.admin_secret_key = "changeme" + security.session_cache.expiration_minutes = 1440 + + [store] + data_source = "/opt/calls-offloader/data/db" + + [jobs] + api_type = "docker" + max_concurrent_jobs = 2 + failed_jobs_retention_time = "7d" + image_registry = "mattermost" + + [logger] + enable_console = true + console_json = false + console_level = "INFO" + enable_file = true + file_json = true + file_level = "INFO" + file_location = "/opt/calls-offloader/calls-offloader.log" + enable_color = true + ``` + +4. Create a systemd service file (`/etc/systemd/system/calls-offloader.service`): + + ```ini + [Unit] + Description=Mattermost Calls Offloader Service + After=network.target docker.service + Requires=docker.service + + [Service] + Type=simple + User=calls-offloader + WorkingDirectory=/opt/calls-offloader + ExecStart=/opt/calls-offloader/calls-offloader --config /opt/calls-offloader/config.toml + Restart=always + RestartSec=10 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + ``` + +5. Enable and start the service: + + ```bash + sudo systemctl daemon-reload + sudo systemctl enable calls-offloader + sudo systemctl start calls-offloader + ``` + +6. Check the service status: + + ```bash + sudo systemctl status calls-offloader + ``` + +7. Verify the service is responding: + + ```bash + curl http://localhost:4545/version + # Example output: + # {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} + ``` + +## Configuration + +### API Configuration + +The API section controls how the service accepts requests: + +- **http.listen_address**: The address and port where the service listens (default: `:4545`) +- **http.tls.enable**: Whether to use TLS encryption for the API +- **security.allow_self_registration**: Allow clients to self-register for job management +- **security.enable_admin**: Enable admin functionality +- **security.admin_secret_key**: Secret key for admin authentication (change from default!) + +### Store Configuration + +Controls persistent data storage: + +- **data_source**: Path to directory for storing job metadata and state + +### Jobs Configuration + +Controls job processing behavior: + +- **api_type**: Job execution backend (`docker` or `kubernetes`) +- **max_concurrent_jobs**: Maximum number of simultaneous recording/transcription jobs +- **failed_jobs_retention_time**: How long to keep failed job data before cleanup +- **image_registry**: Docker registry for job runner images (typically `mattermost`) + +### Logger Configuration + +Controls logging output: + +- **enable_console**: Log to console output +- **console_json**: Use JSON format for console logs +- **console_level**: Log level for console (DEBUG, INFO, WARN, ERROR) +- **enable_file**: Log to file +- **file_location**: Path to log file +- **enable_color**: Use colored output for console logs + +### Private Network Configuration + +When the Mattermost deployment is running in a private network, additional configuration may be necessary for the jobs spawned by the calls-offloader service to reach the Mattermost server. + +In such cases, you can override the site URL used by recorder jobs or transcriber jobs to connect to Mattermost by setting the following environment variables on the Mattermost server: + +- **MM_CALLS_RECORDER_SITE_URL**: Override the site URL used by recording jobs +- **MM_CALLS_TRANSCRIBER_SITE_URL**: Override the site URL used by transcription jobs + +Example configuration: + +Create or edit the Mattermost environment file (`/opt/mattermost/config/mattermost.environment`): + +```bash +MM_CALLS_RECORDER_SITE_URL="http://internal-mattermost-server:8065" +MM_CALLS_TRANSCRIBER_SITE_URL="http://internal-mattermost-server:8065" +``` + +Then ensure your Mattermost systemd service references this environment file: + +```ini +[Unit] +Description=Mattermost +After=network.target + +[Service] +Type=notify +EnvironmentFile=/opt/mattermost/config/mattermost.environment +ExecStart=/opt/mattermost/bin/mattermost +TimeoutStartSec=3600 +KillMode=mixed +Restart=always +RestartSec=10 +WorkingDirectory=/opt/mattermost +User=mattermost +Group=mattermost + +[Install] +WantedBy=multi-user.target +``` + +This is particularly useful when: + +- The calls-offloader service runs in a different network segment than clients +- Internal DNS resolution differs from external URLs +- You need to use internal load balancer endpoints for job communication + +## Validation and Testing + +After deploying calls-offloader, validate the installation: + +1. **Check service status**: + + ```bash + # For systemd + sudo systemctl status calls-offloader + ``` + +2. **Test API connectivity**: + + **From the calls-offloader server (localhost test)**: + + ```bash + curl http://localhost:4545/version + # Should return version information + # Example: {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} + ``` + + **From the Mattermost server**: + + ```bash + curl http://YOUR_CALLS_OFFLOADER_SERVER:4545/version + # Should return the same version information + # This confirms network connectivity from Mattermost to calls-offloader + ``` + + If the localhost test works but the Mattermost server test fails, check: + + - Firewall rules or SELinux policies on the calls-offloader server (port 4545 must be accessible) + - Network connectivity between Mattermost and calls-offloader servers + - calls-offloader service binding configuration (ensure it's not bound to localhost only) + +3. **Verify Docker integration** (if using docker api_type): + + ```bash + # Check that system user running calls-offloader can access Docker + sudo -u calls-offloader docker ps + ``` + +## Integration with Mattermost + +Once calls-offloader is properly set up and validated, configure Mattermost to use it: + +1. Go to **System Console > Plugins > Calls** + +2. In the **Job Service** section: + + - Set **Job Service URL** to your calls-offloader service (e.g., `http://calls-offloader-server:4545`) + +3. Enable recording and transcription features as needed: + + - **Enable Call Recordings**: Toggle to allow call recordings + - **Enable Call Transcriptions**: Toggle to allow call transcriptions + - **Enable Live Captions** (Experimental): Toggle to allow real-time transcription + +4. Save the configuration + +5. Restart the Calls plugin to re-establish state: + + - Go to **System Console > Plugins > Plugin Management** + - Find the **Calls** plugin and click **Disable** + - Wait a few seconds, then click **Enable** + +6. Test by starting a call and enabling recording or live captions + +## Troubleshooting + +### Common Issues + +**"failed to create recording job: max concurrent jobs reached"** + +This error occurs when the calls-offloader service has reached its configured job limit. + +Solutions: + +- Increase `max_concurrent_jobs` in the configuration +- Check if jobs are hanging and restart the service +- Monitor system resources and scale up if needed + +**Jobs not processing** + +Check the following: + +- Verify the calls-offloader service is running: `sudo systemctl status calls-offloader` +- Ensure network connectivity between Mattermost and calls-offloader +- Check Docker daemon is running and accessible by the user running `calls-offloader`: `docker ps` +- Verify authentication configuration matches between services +- Review service logs for specific error messages + +**Docker permission issues** + +If using Docker API and seeing permission errors: + +```bash +# Add calls-offloader user to docker group +sudo usermod -a -G docker calls-offloader +sudo systemctl restart calls-offloader +``` + +### Debugging Commands + +Monitor calls-offloader job containers: + +```bash +# View running job containers +docker ps --format "{{.ID}} {{.Image}}" | grep "calls" + +# Follow logs for debugging +docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {} + +# View completed job containers +docker ps -a --filter "status=exited" +``` + +Monitor service health: + +```bash +# Check service version and health +curl http://localhost:4545/version +``` + +Check service logs: + +```bash +# View recent logs +sudo journalctl -u calls-offloader -f + +# View log file (if file logging enabled) +tail -f /opt/calls-offloader/calls-offloader.log +``` + +### Performance Monitoring + +Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.html) for details on setting up metrics and observability. + +## Other Calls Documentation + +- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +- [calls-offloader performance documentation](https://github.com/mattermost/calls-offloader/blob/master/docs/performance.md): Detailed performance tuning and monitoring recommendations \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md new file mode 100644 index 00000000000..c7fd09e4f44 --- /dev/null +++ b/source/configure/calls-rtcd-setup.md @@ -0,0 +1,378 @@ +# RTCD Setup and Configuration + +```{include} ../_static/badges/ent-only.md +``` + +This guide provides detailed instructions for setting up, configuring, and validating a Mattermost Calls deployment using the dedicated RTCD service. + +- [Prerequisites](#prerequisites) +- [Installation and deployment](#installation-and-deployment) +- [Configuration](#configuration) +- [Validation and testing](#validation-and-testing) +- [Horizontal scaling](#horizontal-scaling) +- [Integration with Mattermost](#integration-with-mattermost) + +## Prerequisites + +Before deploying RTCD, ensure you have: + +- A Mattermost Enterprise license +- A server or VM with sufficient CPU and network capacity (see the [Performance](calls-deployment.html#performance) section for sizing guidance) + +## Network Requirements + +The following network connectivity is required: + +| Service | Ports | Protocols | Source | Target | +|-------------------|--------|-----------------|-------------------------|------------------------| +| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | +| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | +| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | +| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | +| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | + +## Installation and Deployment + +There are multiple ways to deploy RTCD, depending on your environment. We recommend the following order based on production readiness and operational control: + +### Bare Metal or VM Deployment (Recommended) + +This is the recommended deployment method for production environments as it provides the best performance and operational control. + +1. Download the latest release from the [RTCD GitHub repository](https://github.com/mattermost/rtcd/releases) + +2. Create a configuration file (`/opt/rtcd/rtcd.toml`) with the following settings: + + ```toml + [api] + http.listen_address = ":8045" + security.allow_self_registration = true + + [rtc] + ice_address_udp = "" + ice_port_udp = 8443 + ice_address_tcp = "" + ice_port_tcp = 8443 + ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" + + # UDP port range for WebRTC connections + ice.port_range.min = 9000 + ice.port_range.max = 10000 + + # STUN/TURN server configuration + ice_servers = [ + { urls = ["stun:stun.global.calls.mattermost.com:3478"] } + ] + + [store] + data_source = "/opt/rtcd/data/db" + + [logger] + enable_console = true + console_json = true + console_level = "INFO" + enable_file = true + file_json = true + file_level = "INFO" + file_location = "/opt/rtcd/rtcd.log" + enable_color = true + + [mattermost] + host = "http://YOUR_MATTERMOST_SERVER:8065" + ``` + +3. Create the data directory: + + ```bash + sudo mkdir -p /opt/rtcd/data/db + ``` + +4. Create a systemd service file (`/etc/systemd/system/rtcd.service`): + + ```ini + [Unit] + Description=Mattermost RTCD Server + After=network.target + + [Service] + Type=simple + User=root + ExecStart=/opt/rtcd/rtcd --config /opt/rtcd/rtcd.toml + Restart=always + RestartSec=10 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + ``` + +5. Enable and start the service: + + ```bash + sudo systemctl daemon-reload + sudo systemctl enable rtcd + sudo systemctl start rtcd + ``` + +6. Check the service status: + + ```bash + sudo systemctl status rtcd + ``` + +### Docker Deployment + +Docker deployment is suitable for development, testing, or containerized production environments: + +1. Run the RTCD container with basic configuration: + + ```bash + docker run -d --name rtcd \ + -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -p 8045:8045/tcp \ + mattermost/rtcd:latest + ``` + +2. For debugging purposes, you can enable more detailed logging: + + ```bash + docker run -d --name rtcd \ + -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_LOGGER_CONSOLELEVEL=DEBUG" \ + -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -p 8045:8045/tcp \ + mattermost/rtcd:latest + ``` + + To view the logs: + + ```bash + docker logs -f rtcd + ``` + +You can also use a mounted configuration file instead of environment variables: + +```bash +docker run -d --name rtcd \ + -p 8045:8045 \ + -p 8443:8443/udp \ + -p 8443:8443/tcp \ + -v /path/to/config.toml:/rtcd/config/config.toml \ + mattermost/rtcd:latest +``` + +For a complete sample configuration file, see the [RTCD config.sample.toml](https://github.com/mattermost/rtcd/blob/master/config/config.sample.toml) in the official repository. + +### Kubernetes Deployment + +For Kubernetes deployments, use the official Helm chart: + +1. Add the Mattermost Helm repository: + + ```bash + helm repo add mattermost https://helm.mattermost.com + helm repo update + ``` + +2. Install the RTCD chart: + + ```bash + helm install mattermost-rtcd mattermost/mattermost-rtcd \ + --set ingress.enabled=true \ + --set ingress.host=rtcd.example.com \ + --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ + --set rtcd.ice.hostOverride=rtcd.example.com + ``` + + Refer to the [RTCD Helm chart documentation](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-rtcd) for additional configuration options. + +## Configuration + +### RTCD Configuration File + +The RTCD service uses a TOML configuration file. Here's a comprehensive example with commonly used settings: + +```toml +[api] +# The address and port to which the HTTP API server will listen +http.listen_address = ":8045" +# Security settings for authentication +security.allow_self_registration = false +security.enable_admin = true +security.admin_secret_key = "YOUR_API_KEY" +# Configure allowed origins for CORS +security.allowed_origins = ["https://mattermost.example.com"] + +[rtc] +# The UDP address and port for media traffic +ice_address_udp = "" +ice_port_udp = 8443 +# The TCP address and port for fallback connections +ice_address_tcp = "" +ice_port_tcp = 8443 +# Public hostname or IP that clients will use to connect +ice_host_override = "rtcd.example.com" + +[logger] +# Logging configuration +enable_console = true +console_json = false +console_level = "INFO" +enable_file = true +file_json = true +file_level = "DEBUG" +file_location = "rtcd.log" + +[metrics] +# Prometheus metrics configuration +enable_prom = true +prom_port = 9090 +``` + +Key Configuration Options: + +- **api.http.listen_address**: The address and port where the RTCD HTTP API service listens +- **rtc.ice_address_udp**: The UDP address for media traffic (empty means listen on all interfaces) +- **rtc.ice_port_udp**: The UDP port for media traffic +- **rtc.ice_address_tcp**: The TCP address for fallback media traffic +- **rtc.ice_port_tcp**: The TCP port for fallback media traffic +- **rtc.ice_host_override**: The public hostname or IP address clients will use to connect to RTCD +- **api.security.allowed_origins**: List of allowed origins for CORS +- **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD + +### STUN/TURN Configuration + +For clients behind strict firewalls, you may need to configure STUN/TURN servers. In the RTCD configuration file, reference your STUN/TURN servers as follows: + +```toml +[rtc] +# STUN/TURN server configuration +ice_servers = [ + { urls = ["stun:stun.example.com:3478"] }, + { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } +] +``` + +We recommend using [coturn](https://github.com/coturn/coturn) for your TURN server implementation. + +### System Tuning + +For high-volume deployments, tune your Linux system: + +1. Add the following to `/etc/sysctl.conf`: + + ```bash + # Increase UDP buffer sizes + net.core.rmem_max = 16777216 + net.core.wmem_max = 16777216 + net.core.optmem_max = 16777216 + ``` + +2. Apply the settings: + + ```bash + sudo sysctl -p + ``` + +## Validation and Testing + +After deploying RTCD, validate the installation: + +1. **Check service status and version**: + + ```bash + curl http://YOUR_RTCD_SERVER:8045/version + # Should return a JSON object with service information + # Example: {"build_hash":"abc123","build_date":"2023-01-15T12:00:00Z","build_version":"0.11.0","goVersion":"go1.20.4"} + ``` + +2. **Test UDP connectivity**: + + On the RTCD server: + + ```bash + nc -l -u -p 8443 + ``` + + On a client machine: + + ```bash + nc -v -u YOUR_RTCD_SERVER 8443 + ``` + + Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. + + Note: This test must be run with the RTCD service stopped, as it binds to the same port. + + ```bash + sudo systemctl stop rtcd + ``` + +3. **Test TCP connectivity** (if enabled): + + Similar to the UDP test, but remove the `-u` flag from both commands. + +4. **Monitor metrics**: + + Refer to [Calls Metrics and Monitoring](calls-metrics-monitoring.html) for setting up Calls metrics and monitoring. + +## Horizontal Scaling + +To scale RTCD horizontally: + +1. **Deploy multiple RTCD instances**: + + Deploy multiple RTCD servers, each with their own unique IP address. + +2. **Configure DNS-based load balancing**: + + Set up a DNS record that points to multiple RTCD IP addresses: + + ```bash + rtcd.example.com. IN A 10.0.0.1 + rtcd.example.com. IN A 10.0.0.2 + rtcd.example.com. IN A 10.0.0.3 + ``` + +3. **Configure health checks**: + + Set up health checks to automatically remove unhealthy RTCD instances from DNS. + +4. **Configure Mattermost**: + + In the Mattermost System Console, set the **RTCD Service URL** to your DNS name (e.g., `rtcd.example.com`). + +The Mattermost Calls plugin will distribute calls among the available RTCD hosts. Remember that a single call will always be hosted on one RTCD instance; sessions belonging to the same call are not spread across different instances. + +## Integration with Mattermost + +Once RTCD is properly set up and validated, configure Mattermost to use it: + +1. Go to **System Console > Plugins > Calls** + +2. Enable the **Enable RTCD Service** option + +3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname) + +4. If configured, enter the **RTCD API Key** that matches the one in your RTCD configuration + +5. Save the configuration + +6. Test by creating a new call in any Mattermost channel + +7. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics + +## Other Calls Documentation + +- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture +- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques + +For detailed Mattermost Calls configuration options, see the [Calls Plugin Configuration Settings](plugins-configuration-settings.html#calls) documentation. \ No newline at end of file diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md new file mode 100644 index 00000000000..bf25fbe7b12 --- /dev/null +++ b/source/configure/calls-troubleshooting.md @@ -0,0 +1,406 @@ +# Troubleshooting Mattermost Calls + +```{include} ../_static/badges/allplans-cloud-selfhosted.md +``` + +This guide provides comprehensive troubleshooting steps for Mattermost Calls, particularly focusing on the dedicated RTCD deployment model. Follow these steps to identify and resolve common issues. + +- [Common issues](#common-issues) +- [Connectivity troubleshooting](#connectivity-troubleshooting) +- [Log analysis](#log-analysis) +- [Performance issues](#performance-issues) +- [Debugging tools](#debugging-tools) +- [Advanced diagnostics](#advanced-diagnostics) + +## Common Issues + +### Calls Not Connecting + +**Symptoms**: Users can start calls but cannot connect, or calls connect but drop quickly. + +**Possible causes and solutions**: + +1. **Network connectivity issues**: + - Verify that UDP port 8443 (or your configured port) is open between clients and RTCD servers + - Ensure TCP port 8045 is open between Mattermost and RTCD servers + - Check that any load balancers are properly configured for UDP traffic + +2. **ICE configuration issues**: + - Verify the `rtc.ice_host_override` setting in RTCD configuration matches the publicly accessible hostname or IP of the RTCD server + - If this setting is incorrect, client browser console may show errors like: `com.mattermost.calls: peer error timed out waiting for rtc connection` + - Meanwhile, RTCD `trace` level logs might show internal IP addresses in ICE connection logs: + + ```json + {"timestamp":"2025-05-14 10:29:08.935 Z","level":"trace","msg":"Ping STUN from udp4 host 172.31.29.117:8443 (resolved: 172.31.29.117:8443) to udp4 host 192.168.64.1:59737 (resolved: 192.168.64.1:59737)","caller":"rtc/logger.go:54","origin":"ice/v4.(*Agent).sendBindingRequest github.com/pion/ice/v4@v4.0.3/agent.go:921"} + ``` + +3. **API connectivity**: + - Verify that Mattermost servers can reach the RTCD API endpoint + - Check that the API key is correctly configured in both Mattermost and RTCD + +4. **Plugin configuration**: + - Ensure the Calls plugin is enabled and properly configured + - Verify the RTCD service URL is correct in the System Console + +### Audio Issues + +**Symptoms**: Users can connect to calls, but audio is one-way, choppy, or not working. + +**Possible causes and solutions**: + +1. **Client permissions**: + - Ensure browser/app has microphone permissions + - Check if users are using multiple audio devices that might interfere + +2. **Network quality**: + - High latency or packet loss can cause audio issues + - Try testing with TCP fallback enabled (requires RTCD v0.11+ and Calls v0.17+) + +3. **Audio device configuration**: + - Users should verify their audio input/output settings + - Try different browsers or the desktop app + +### Call Quality Issues + +**Symptoms**: Calls connect but quality is poor, with latency, echo, or distortion. + +**Possible causes and solutions**: + +1. **Server resources**: + - Check CPU usage on RTCD servers - high CPU can cause quality issues + - Refer to the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide for detailed instructions on monitoring and optimizing performance + - Monitor network bandwidth usage + +2. **Network congestion**: + - Check for packet loss between clients and RTCD + - Consider network QoS settings to prioritize real-time traffic + +3. **Client-side issues**: + - Browser or app limitations + - Hardware limitations (CPU, memory) + - Network congestion at the user's location + +## Connectivity Troubleshooting + +### Basic Connectivity Tests + +1. **HTTP API connectivity test**: + + Test if the RTCD API is reachable: + + ```bash + curl http://YOUR_RTCD_SERVER:8045/api/v1/health + # Expected response: {"status":"ok"} + ``` + +2. **UDP connectivity test**: + + On the RTCD server: + + ```bash + nc -l -u -p 8443 + ``` + + On a client machine: + + ```bash + nc -v -u YOUR_RTCD_SERVER 8443 + ``` + + Type a message and press Enter. If you see the message on both sides, UDP connectivity is working. + +3. **TCP fallback connectivity test**: + + Same as the UDP test, but without the `-u` flag: + + On the RTCD server: + + ```bash + nc -l -p 8443 + ``` + + On a client machine: + + ```bash + nc -v YOUR_RTCD_SERVER 8443 + ``` + +### Network Packet Analysis + +To capture and analyze network traffic: + +1. **Capture UDP traffic on the RTCD server**: + + ```bash + sudo tcpdump -n 'udp port 8443' -i any + ``` + +2. **Capture TCP API traffic**: + + ```bash + sudo tcpdump -n 'tcp port 8045' -i any + ``` + +3. **Analyze traffic patterns**: + + - Verify packets are flowing both ways + - Look for ICMP errors that might indicate firewall issues + - Check for patterns of packet loss + +4. **Use Wireshark for deeper analysis**: + + For more detailed packet inspection, capture traffic with tcpdump and analyze with Wireshark: + + ```bash + sudo tcpdump -n -w calls_traffic.pcap 'port 8443' + ``` + + Then analyze the `calls_traffic.pcap` file with Wireshark. + +### Firewall Configuration Checks + +1. **Check iptables rules** (Linux): + + ```bash + sudo iptables -L -n + ``` + + Ensure there are no rules blocking UDP port 8443 or TCP ports 8045/8443. + +2. **Check cloud provider security groups**: + + Verify that security groups or network ACLs allow: + - Inbound UDP on port 8443 from client networks + - Inbound TCP on port 8045 from Mattermost server networks + - Inbound TCP on port 8443 (if TCP fallback is enabled) + +3. **Check intermediate firewalls**: + + - Corporate firewalls might block UDP traffic + - Some networks might require TURN servers for traversal + +## Log Analysis + +### RTCD Logs + +The RTCD service logs important events and errors. Set the log level to "debug" for troubleshooting: + +1. **In the configuration file**: + + ```json + { + "log": { + "level": "debug", + "json": true + } + } + ``` + +2. **Common log patterns to look for**: + + - **Connection errors**: Look for "failed to connect" or "connection error" messages + - **ICE negotiation failures**: Look for "ICE failed" or "ICE timeout" messages + - **API authentication issues**: Look for "unauthorized" or "invalid API key" messages + +### Mattermost Logs + +Check the Mattermost server logs for Calls plugin related issues: + +1. **Enable debug logging** in System Console > Environment > Logging > File Log Level + +2. **Filter for Calls-related logs**: + + ```bash + grep -i "calls" /path/to/mattermost.log + ``` + +3. **Look for common patterns**: + + - Connection errors to RTCD + - Plugin initialization issues + - WebSocket connection problems + +### Browser Console Logs + +Instruct users to check their browser console logs: + +1. **In Chrome/Edge**: + - Press F12 to open Developer Tools + - Go to the Console tab + - Look for errors related to WebRTC, Calls, or media permissions + +2. **Specific patterns to look for**: + + - "getUserMedia" errors (microphone permission issues) + - "ICE connection" failures + - WebSocket connection errors + +## Performance Issues + +### Diagnosing High CPU Usage + +If RTCD servers show high CPU usage: + +1. **Check concurrent calls and participants**: + + - Access the Prometheus metrics endpoint to see active sessions + - Compare with the benchmark data in the documentation + +2. **Profile CPU usage** (Linux): + + ```bash + top -p $(pgrep rtcd) + ``` + + Or for detailed per-thread usage: + + ```bash + ps -eLo pid,ppid,tid,pcpu,comm | grep rtcd + ``` + +3. **Enable pprof profiling** (if needed): + + Add to your RTCD configuration: + + ```json + { + "debug": { + "pprof": true, + "pprofPort": 6060 + } + } + ``` + + Then capture a CPU profile: + + ```bash + curl http://localhost:6060/debug/pprof/profile > cpu.profile + ``` + + Analyze with: + + ```bash + go tool pprof -http=:8080 cpu.profile + ``` + +### Diagnosing Network Bottlenecks + +If you suspect network bandwidth issues: + +1. **Monitor network utilization**: + + ```bash + iftop -n + ``` + +2. **Check for packet drops**: + + ```bash + netstat -su | grep -E 'drop|error' + ``` + +3. **Verify system network buffers**: + + ```bash + sysctl -a | grep net.core.rmem + sysctl -a | grep net.core.wmem + ``` + + Ensure these match the recommended values: + + ```bash + net.core.rmem_max = 16777216 + net.core.wmem_max = 16777216 + net.core.optmem_max = 16777216 + ``` + +## Recording and Transcription Issues + +For troubleshooting calls-offloader service issues including recording and transcription problems, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.html#troubleshooting) guide. + +## Debugging Tools + +### Prometheus Metrics Analysis + +Use Prometheus metrics for real-time and historical performance data: + +Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. + +## Advanced Diagnostics + +### WebRTC Diagnostic Commands + +For detailed WebRTC diagnostics: + +1. **Test STUN server connectivity**: + + ```bash + # Using stun-client (you may need to install it) + stun-client stun.global.calls.mattermost.com + ``` + + This should return your public IP address if STUN is working correctly. + +2. **Verify TURN server**: + + ```bash + # Using turnutils_uclient (part of coturn) + turnutils_uclient -v -s your-turn-server -u username -p password + ``` + + This tests if your TURN server is correctly configured. + +3. **Test end-to-end latency**: + + Between client locations and RTCD server: + + ```bash + ping -c 10 your-rtcd-server + ``` + + Look for consistent, low latency (<100ms ideally for voice calls). + +### Client-Side Testing Tools + +Tools to help diagnose client-side issues: + +1. **WebRTC Troubleshooter**: + + Direct users to [WebRTC Troubleshooter](https://test.webrtc.org/) for browser capability testing. + +2. **Network Quality Tests**: + + Use [Speedtest](https://www.speedtest.net/) or similar to check internet connection quality. + +3. **Browser-Specific WebRTC Info**: + + - Chrome: chrome://webrtc-internals + - Firefox: about:webrtc + +### When to Contact Support + +Consider contacting Mattermost Support when: + +1. You've tried troubleshooting steps without resolution +2. You're experiencing persistent connection failures across multiple clients +3. You notice unexpected or degraded performance despite proper configuration +4. You need help interpreting diagnostic information +5. You suspect a bug in the Calls plugin or RTCD service + +When contacting support, please include: + +- RTCD version and configuration (with sensitive information redacted) +- Mattermost server version +- Calls plugin version +- Client environments (browsers, OS versions) +- Relevant logs and diagnostic information +- Detailed description of the issue and steps to reproduce + +## Other Calls Documentation + +- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments +- Monitoring dashboards screenshots \ No newline at end of file From 3ca52ce1bf997accbca4466ae374255288aa4d77 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 11:25:17 -0400 Subject: [PATCH 18/60] Cleaned up old rst files, fixed bad RTCD health check endpoint --- source/configure/calls-deployment.rst | 255 ----------- source/configure/calls-kubernetes.rst | 178 -------- source/configure/calls-metrics-monitoring.rst | 266 ----------- source/configure/calls-offloader-setup.rst | 404 ---------------- source/configure/calls-rtcd-setup.rst | 415 ----------------- source/configure/calls-troubleshooting.md | 5 +- source/configure/calls-troubleshooting.rst | 431 ------------------ 7 files changed, 2 insertions(+), 1952 deletions(-) delete mode 100644 source/configure/calls-deployment.rst delete mode 100644 source/configure/calls-kubernetes.rst delete mode 100644 source/configure/calls-metrics-monitoring.rst delete mode 100644 source/configure/calls-offloader-setup.rst delete mode 100644 source/configure/calls-rtcd-setup.rst delete mode 100644 source/configure/calls-troubleshooting.rst diff --git a/source/configure/calls-deployment.rst b/source/configure/calls-deployment.rst deleted file mode 100644 index d7379ca87ce..00000000000 --- a/source/configure/calls-deployment.rst +++ /dev/null @@ -1,255 +0,0 @@ -Calls self-hosted deployment -============================ - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -This document provides an overview of Mattermost Calls deployment options for self-hosted environments, including deployment architectures, key requirements, and important considerations. - -.. toctree:: - :maxdepth: 1 - :hidden: - - calls-rtcd-setup - calls-offloader-setup - calls-metrics-monitoring - calls-kubernetes - calls-troubleshooting - -Quick Links ----------- - -For detailed information on specific topics, please refer to these specialized guides: - -- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service -- `Calls Offloader Setup and Configuration `__: Comprehensive guide for setting up the calls-offloader service for recording and transcription -- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques -- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability -- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments - -About Mattermost Calls ---------------------- - -Mattermost Calls provides integrated audio calling and screen sharing capabilities within Mattermost channels. It's built on WebRTC technology and can be deployed either: - -1. **Integrated mode**: Built into the Calls plugin (simpler, suitable for smaller deployments) -2. **RTCD mode**: Using a dedicated service for improved performance and scalability (recommended for production environments) - -Terminology ------------ - -- `WebRTC `__: The set of protocols on which calls are built -- **RTC**: Real-Time Connection channel used for media (audio/video/screen) -- **WS**: WebSocket connection used for signaling and connection setup -- **SFU**: Selective Forwarding Unit, routes media between participants -- `NAT `__: Network Address Translation for mapping IP addresses -- `STUN `__: Protocol used by WebRTC clients to help traverse NATs -- `TURN `__: Protocol to relay media for clients behind strict firewalls - -Key Components -------------- - -- **Calls plugin**: The main plugin that enables calls functionality. Installed by default in Mattermost self-hosted deployments. -- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. See `RTCD Setup and Configuration `__ for details. -- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. See `Calls Offloader Setup and Configuration `__ for setup and troubleshooting details. - -Network Requirements ------------------- - -The following network connectivity is required: - -+-------------------+--------+-----------------+-------------------------+------------------------+ -| Service | Ports | Protocols | Source | Target | -+===================+========+=================+=========================+========================+ -| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | -+-------------------+--------+-----------------+-------------------------+------------------------+ - -For complete network requirements, see the `RTCD Setup and Configuration `__ guide. - -Limitations ------------ - -- All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. -- For group calls up to 50 concurrent users, Mattermost Enterprise, Professional, or Mattermost Cloud is required. -- Enterprise customers can also `record calls `__, enable `live text captions `__ during calls, and `transcribe recorded calls `__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the `dedicated RTCD service <#when-to-use-rtcd>`__. -- For Mattermost self-hosted deployments, System admins need to enable and configure the plugin `using the System Console `__. The default maximum number of participants is unlimited; however, we recommend a maximum of 50 participants per call. Maximum call participants is configurable by going to **System Console > Plugin Management > Calls > Max call participants**. Call participant limits greatly depends on instance resources. For more details, refer to the `Performance Considerations <#performance-considerations>`__ section below. - -Configuration -------------- - -For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in the `System Console `__. - -Deployment Architecture Options ------------------------------ - -Mattermost Calls can be deployed in several configurations: - -Single Instance Deployments -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Integrated Mode -^^^^^^^^^^^^^ - -The WebRTC service runs within the Calls plugin on the Mattermost server. This is the default mode when first installing the plugin on a single Mattermost instance setup. The WebRTC service is integrated in the plugin itself and runs alongside the Mattermost server. - -.. image:: ../images/calls-deployment-image3.png - :alt: Integrated configuration model of a single instance - :width: 600px - -RTCD Mode -^^^^^^^^ - -A dedicated RTCD service handles media routing, reducing load on the Mattermost server. - -.. image:: ../images/calls-deployment-image7.png - :alt: Web RTC deployment configuration - :width: 600px - -High Availability Deployments -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Clustered Mode -^^^^^^^^^^^^ - -This is the default mode when running the plugin in a high availability cluster-based deployment. Every Mattermost node will run an instance of the plugin that includes a WebRTC service. Calls are distributed across all available nodes through the existing load-balancer: a call is hosted on the instance where the initiating websocket connection (first client to join) is made. A single call will be hosted on a single cluster node. - -.. image:: ../images/calls-deployment-image5.png - :alt: Clustered calls deployment - :width: 600px - -RTCD with High Availability -^^^^^^^^^^ - -Dedicated RTCD services handle media routing for high availability. - -.. image:: ../images/calls-deployment-image2.png - :alt: RTCD deployment with high availability - :width: 600px - -Kubernetes Deployments -~~~~~~~~~~~~~~~~~~~~ - -RTCD is the only officially supported approach for Kubernetes deployments. For detailed information on deploying Mattermost Calls in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the `Calls Deployment on Kubernetes `__ guide. - -When to Use RTCD --------------- - -The dedicated RTCD service (available with Enterprise license) is recommended for: - -- **Production environments**: Isolates call traffic from other Mattermost services -- **Performance optimization**: Dedicated service tuned for real-time media -- **Scalability**: Add RTCD instances as call volume grows -- **Call stability**: Calls continue even if Mattermost server needs to restart -- **Kubernetes deployments**: Required for officially supported Kubernetes deployments - -For detailed RTCD setup instructions, see the `RTCD Setup and Configuration `__ guide. - -Call Recording and Transcription ------------------------------- - -For call recording and transcription, you need to: - -1. Deploy the ``calls-offloader`` service -2. Configure the service URL in the System Console -3. Enable call recordings and/or transcriptions in the plugin settings - -Air-Gapped Deployments ---------------------- - -Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: - -- Users should connect from within the private/local network. This can be done on-premises, through a VPN, or via virtual machines. -- Configuring a STUN server is unnecessary, as all connections occur within the local network. -- The ICE Host Override configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. - -Performance Considerations ------------------------- - -Calls performance primarily depends on: - -- **CPU resources**: More participants require more processing power -- **Network bandwidth**: Both incoming and outgoing traffic increases with participant count -- **Active speakers**: Unmuted participants require significantly more resources - -For detailed performance metrics, benchmarks, and monitoring guidance, see the `Calls Metrics and Monitoring `__ guide. - -Frequently Asked Questions ------------------------- - -**Is calls traffic encrypted?** -Yes, using WebRTC security standards (DTLS/SRTP). Traffic is encrypted in transit. - -**Are there any third-party services involved?** -Only a Mattermost STUN server (``stun.global.calls.mattermost.com``) is used by default. This can be removed if you set the ICE Host Override configuration. - -**Is using UDP a requirement?** -UDP is recommended protocol to serve real-time media as it allows for the lowest latency between peers, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. - -If clients are unable to connect using UDP (due to limitations or strict firewalls), you have a few options: - -- Since plugin version 0.17 and `rtcd` version 0.11 the RTC service will listen for TCP connections in addition to UDP ones. If configured correctly (e.g. using commonly allowed ports such as 80 or 443) it's possible to have clients connect directly through TCP when unable to do it through the preferred UDP channel. - -- Run calls through an external TURN server that listens on TCP and relays all media traffic between peers. However, this is a sub-optimal solution that should be avoided if possible as it will introduce extra latency along with added infrastructural cost. - -**Do I need a TURN server?** -Only if clients are behind restrictive firewalls that block UDP. We recommend (and officially support) `coturn `__ if needed. - -**Can RTCD traffic be kept internal?** -Yes, and it's recommended. Only the media ports need to be accessible to end-users. - -**How will this work with an existing reverse proxy sitting in front of Mattermost?** - -Generally clients should connect directly to either Mattermost or, if deployed, the dedicated ``rtcd`` service through the configured UDP port. However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. - -**Do calls require a dedicated server to work or can they run alongside Mattermost?** - -The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). - -See RTCD Setup and Configuration for more details on the dedicated RTCD service. - -**Can the traffic between Mattermost and ``rtcd`` be kept internal or should it be opened to the public?** - -When possible, it's recommended to keep communication between the Mattermost cluster and the dedicated ``rtcd`` service under the same private network as this can greatly simplify deployment and security. There's no requirement to expose ``rtcd``'s HTTP API to the public internet. - -**Can Calls be rolled out on a per-channel basis?** - -.. include:: ../_static/badges/selfhosted-only.rst - :start-after: :nosearch: - -Yes. Mattermost system admins running self-hosted deployments can enable or disable call functionality per channel. Once `test mode `__ is enabled for Mattermost Calls: - -1. **Navigate to the channel** where you want to enable or disable Calls -2. **Access the channel menu** by clicking the channel name at the top of the channel -3. **Select the Calls option** from the dropdown menu: - - Select **Enable calls** for each channel where you want Calls enabled - - Select **Disable calls** for all channels where you want Calls disabled - -.. image:: ../images/calls-channel-enable-disable.png - :alt: Channel menu showing Enable/Disable calls options - :width: 400px - -Once Calls is enabled for specific channels, users can start making calls in those channels. - -.. note:: - When `test mode `__ is disabled for Mattermost Calls, users in any Mattermost channel can make a call. - -Troubleshooting ---------------- - -For comprehensive troubleshooting steps and debugging techniques, please refer to the `Calls Troubleshooting `__ guide. - -Next Steps ---------- - -1. For detailed setup instructions, see `RTCD Setup and Configuration `__ -2. For monitoring guidance, see `Calls Metrics and Monitoring `__ -3. If you encounter issues, see `Calls Troubleshooting `__ -4. For Kubernetes deployments, see `Calls Deployment on Kubernetes `__ \ No newline at end of file diff --git a/source/configure/calls-kubernetes.rst b/source/configure/calls-kubernetes.rst deleted file mode 100644 index b9936db5cb0..00000000000 --- a/source/configure/calls-kubernetes.rst +++ /dev/null @@ -1,178 +0,0 @@ -Calls deployment on Kubernetes -=========================== - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -This guide provides detailed information for deploying Mattermost Calls on Kubernetes environments. - -Overview --------- - -Mattermost Calls has been designed to integrate well with Kubernetes to offer improved scalability and control over the deployment. For Kubernetes deployments, the RTCD service is strongly recommended and is the only officially supported approach. - -Architecture ------------ - -.. image:: ../images/calls-deployment-kubernetes.png - :alt: Calls deployed in a Kubernetes cluster - :width: 600px - -This diagram shows how the RTCD standalone service can be deployed in a Kubernetes cluster. In this architecture: - -1. Calls traffic is handled by dedicated RTCD pods -2. RTCD services are exposed through load balancers -3. Scaling is managed through Kubernetes deployment configurations -4. Call recording and transcription is handled by the calls-offloader service (see `Calls Offloader Setup and Configuration `__) - -If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the `Kubernetes operator guide `__. - -Helm Chart Deployment -------------------- - -The recommended way to deploy Calls-related components in a Kubernetes environment is to use the officially provided Helm charts: - -RTCD Helm Chart -^^^^^^^^^^^^^ - -The RTCD Helm chart deploys the RTCD service needed for call media handling: - -.. code-block:: bash - - helm repo add mattermost https://helm.mattermost.com - helm repo update - - helm install mattermost-rtcd mattermost/mattermost-rtcd \ - --set ingress.enabled=true \ - --set ingress.host=rtcd.example.com \ - --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ - --set rtcd.ice.hostOverride=rtcd.example.com - -For complete configuration options, see the `RTCD Helm chart documentation `__. - -Calls-Offloader Helm Chart -^^^^^^^^^^^^^^^^^^^^^^^^ - -If you need call recording and transcription capabilities, deploy the calls-offloader service: - -.. code-block:: bash - - helm install mattermost-calls-offloader mattermost/mattermost-calls-offloader \ - --set ingress.enabled=true \ - --set ingress.host=calls-offloader.example.com - -For complete configuration options, see the `Calls-Offloader Helm chart documentation `__. - -Kubernetes-Specific Configuration -------------------------------- - -Network Configuration -^^^^^^^^^^^^^^^^^^ - -For Kubernetes deployments, you need to ensure: - -1. UDP traffic is properly routed to RTCD pods (for media) -2. TCP traffic can reach both the Mattermost pods and RTCD pods -3. Load balancers are properly configured to handle UDP traffic -4. Network policies allow the required communications between services - -Recommended annotations for AWS environments: - -.. code-block:: yaml - - service.beta.kubernetes.io/aws-load-balancer-backend-protocol: udp - service.beta.kubernetes.io/aws-load-balancer-type: nlb - -Resource Requirements -^^^^^^^^^^^^^^^^^^ - -For optimal performance in Kubernetes environments: - -1. **CPU**: At least 2 CPU cores per RTCD pod -2. **Memory**: At least 1GB RAM per RTCD pod -3. **Network**: Sufficient bandwidth for expected call volume (see benchmarks) - -We recommend setting resource limits and requests in your deployment: - -.. code-block:: yaml - - resources: - requests: - cpu: 1000m - memory: 1Gi - limits: - cpu: 2000m - memory: 2Gi - -Scaling Considerations -^^^^^^^^^^^^^^^^^^ - -Horizontal scaling of RTCD pods is possible, but remember: - -1. Each call is hosted entirely on a single RTCD pod -2. DNS-based load balancing should be used to distribute calls among pods -3. Health checks should ensure that only healthy pods receive new calls -4. Calls remain on their assigned pod for their entire duration - -Limitations -^^^^^^^^^^ - -Due to the inherent complexities of hosting a WebRTC service, some limitations apply when deploying Calls in a Kubernetes environment. - -One key requirement is that each ``rtcd`` process must live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally not go through a standard ingress but directly to the pod running the ``rtcd`` process. - -The general recommendation is to expose one external IP address per ``rtcd`` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. - -If, for some reason, exposing multiple IP addresses is not possible in your environment, port mapping (NAT) can be used. In this scenario different ports are used to map the respective ``rtcd`` nodes behind the single external IP. Example: - -.. code-block:: text - - EXT_IP:8443 -> rtcdA:8443 - EXT_IP:8444 -> rtcdB:8443 - EXT_IP:8445 -> rtcdC:8443 - -This case requires a couple of extra configurations: - -* NAT mappings need to be in place for every ``rtcd`` node. This is usually done at the ingress point (e.g., ELB, NLB, etc). - -* The ``RTCD_RTC_ICEHOSTPORTOVERRIDE`` config should be used to pass a full mapping of node IPs and their respective port. - - * Example: ``RTCD_RTC_ICEHOSTPORTOVERRIDE=rtcdA_IP/8443,rtcdB_IP/8444,rtcdC_IP/8445`` - -* The ``RTCD_RTC_ICEHOSTOVERRIDE`` should be used to set the external IP address. - -.. note:: - One option to limit these static mappings is to reduce the size of the local subnet (e.g., to ``/29``). - -Monitoring and Metrics -^^^^^^^^^^^^^^^^^^^ - -We recommend deploying Prometheus and Grafana alongside your Calls deployment: - -1. Configure Prometheus to scrape metrics from both Mattermost and RTCD pods -2. Import the official Mattermost Calls dashboard to Grafana -3. Set up alerts for CPU usage, connection failures, and error rates - -For detailed information on metrics collection and monitoring, see the `Calls Metrics and Monitoring `__ guide. - -Troubleshooting --------------- - -For Kubernetes-specific troubleshooting: - -1. Check pod logs: `kubectl logs -f deployment/mattermost-rtcd` -2. Verify service connectivity: `kubectl port-forward service/mattermost-rtcd 8045:8045` -3. Ensure UDP traffic is properly routed through your ingress/load balancer -4. Verify network policies allow required communication paths - -For detailed troubleshooting steps, see the `Calls Troubleshooting `__ guide. - -Other Calls Documentation ----------------- - -- `Calls Overview `__: Overview of deployment options and architecture -- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service -- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription -- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability -- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques -3. If you encounter issues, see `Calls Troubleshooting `__ \ No newline at end of file diff --git a/source/configure/calls-metrics-monitoring.rst b/source/configure/calls-metrics-monitoring.rst deleted file mode 100644 index 81d29f74e99..00000000000 --- a/source/configure/calls-metrics-monitoring.rst +++ /dev/null @@ -1,266 +0,0 @@ -Calls Metrics and Monitoring -========================= - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -This guide provides detailed information on monitoring Mattermost Calls performance and health through metrics and observability tools. Effective monitoring is essential for maintaining optimal call quality and quickly addressing any issues that arise. - -- `Metrics overview <#metrics-overview>`__ -- `Setting up monitoring <#setting-up-monitoring>`__ -- `Key metrics to monitor <#key-metrics-to-monitor>`__ -- `Grafana dashboards <#grafana-dashboards>`__ -- `Alerting recommendations <#alerting-recommendations>`__ -- `Performance baselines <#performance-baselines>`__ - -Metrics Overview --------------- - -Mattermost Calls provides metrics through Prometheus for both the Calls plugin and the RTCD service. These metrics help track: - -- Active call sessions and participants -- Media track statistics -- Connection states and errors -- Resource utilization (CPU, memory, network) -- WebSocket connections and events - -The metrics are exposed through HTTP endpoints: - -- **Calls Plugin**: ``/plugins/com.mattermost.calls/metrics`` -- **RTCD Service**: ``/metrics`` (default) or a configured endpoint - -Setting Up Monitoring -------------------- - -Prerequisites -^^^^^^^^^^^ - -To monitor Calls metrics, you'll need: - -1. **Prometheus**: For collecting and storing metrics -2. **Grafana**: For visualizing metrics (optional but recommended) - -Installing Prometheus -^^^^^^^^^^^^^^^^^^ - -1. **Download and install Prometheus**: - - Visit the `Prometheus download page `__ for installation instructions. - -2. **Configure Prometheus** to scrape metrics from all Calls-related services: - - Complete ``prometheus.yml`` configuration for Calls monitoring: - - .. code-block:: yaml - - global: - scrape_interval: 15s - evaluation_interval: 15s - - scrape_configs: - - job_name: 'prometheus' - static_configs: - - targets: ['PROMETHEUS_IP:9090'] - - - job_name: 'mattermost' - metrics_path: /metrics - static_configs: - - targets: ['MATTERMOST_SERVER_IP:8067'] - - - job_name: 'calls-plugin' - metrics_path: /plugins/com.mattermost.calls/metrics - static_configs: - - targets: ['MATTERMOST_SERVER_IP:8067'] - labels: - service_name: 'calls-plugin' - - - job_name: 'rtcd' - metrics_path: /metrics - static_configs: - - targets: ['RTCD_SERVER_IP:8045'] - labels: - service_name: 'rtcd' - - - job_name: 'rtcd-node-exporter' - metrics_path: /metrics - static_configs: - - targets: ['RTCD_SERVER_IP:9100'] - labels: - service_name: 'rtcd' - - - job_name: 'calls_offloader-node-exporter' - metrics_path: /metrics - static_configs: - - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] - labels: - service_name: 'offloader' - - Replace the placeholder IP addresses with your actual server addresses: - - - ``MATTERMOST_SERVER_IP``: IP address of your Mattermost server - - ``RTCD_SERVER_IP``: IP address of your RTCD server - - ``CALLS_OFFLOADER_SERVER_IP``: IP address of your calls-offloader server (if deployed) - - ``PROMETHEUS_IP``: IP address of your Prometheus server - - **Note**: The configuration above uses the default ports (RTCD: ``8045``, Mattermost metrics: ``8067``, etc.). Adjust these ports in ``prometheus.yml`` if you have customized them. - .. important:: - **Metrics Path**: Ensure the metrics paths are correct. The RTCD service exposes metrics at ``/metrics`` by default, and the Calls plugin at ``/plugins/com.mattermost.calls/metrics``. - - .. important:: - **Metrics Configuration Notice**: Use the ``service_name`` labels as shown in the configuration above. These labels help organize metrics in dashboards and enable proper service identification. - - .. note:: - - **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See `node_exporter setup guide `__ for installation instructions. - - **calls-offloader**: Only needed if you have call recording/transcription enabled - -Installing Grafana -^^^^^^^^^^^^^^^ - -1. **Download and install Grafana**: - - Visit the `Grafana download page `__ for installation instructions. - -2. **Configure Grafana** to use Prometheus as a data source: - - - Add a new data source in Grafana - - Select Prometheus as the type - - Enter the URL of your Prometheus server - - Test and save the configuration - -3. **Import the Mattermost Calls dashboard**: - - - Navigate to Dashboards > Import in Grafana - - Enter dashboard ID: ``23225`` or use the direct link: `Mattermost Calls Performance Monitoring `__ - - Select your Prometheus data source, and enter values for the - - Confirm the port used for RTCD metrics (default is ``8045``), and the port used for the Calls plugin metrics (default is ``8067``) - - Click Import to add the dashboard to your Grafana instance - - .. note:: - The dashboard is also available as JSON source from the `Mattermost performance assets repository `__ for manual import or customization. - - -Key Metrics to Monitor --------------------- - -RTCD Metrics -^^^^^^^^^^ - -Process Metrics -"""""""""""""" - -These metrics help monitor the health and resource usage of the RTCD process: - -- ``rtcd_process_cpu_seconds_total``: Total CPU time spent -- ``rtcd_process_open_fds``: Number of open file descriptors -- ``rtcd_process_max_fds``: Maximum number of file descriptors -- ``rtcd_process_resident_memory_bytes``: Memory usage in bytes -- ``rtcd_process_virtual_memory_bytes``: Virtual memory used - -**Interpretation**: - -- High CPU usage (>70%) may indicate the need for additional RTCD instances -- Steadily increasing memory usage might indicate a memory leak -- High number of file descriptors could indicate connection handling issues - -WebRTC Connection Metrics -""""""""""""""""""""""" - -These metrics track the WebRTC connections and media flow: - -- ``rtcd_rtc_conn_states_total{state="X"}``: Count of connections in different states -- ``rtcd_rtc_errors_total{type="X"}``: Count of RTC errors by type -- ``rtcd_rtc_rtp_tracks_total{direction="X"}``: Count of RTP tracks (incoming/outgoing) -- ``rtcd_rtc_sessions_total``: Total number of active RTC sessions - -**Interpretation**: - -- Increasing error counts may indicate connectivity or configuration issues -- Track by state to see if connections are failing to establish or dropping -- Larger track counts require proportionally more CPU and bandwidth - -WebSocket Metrics -""""""""""""""" - -These metrics track the signaling channel: - -- ``rtcd_ws_connections_total``: Total number of active WebSocket connections -- ``rtcd_ws_messages_total{direction="X"}``: Count of WebSocket messages (sent/received) - -**Interpretation**: - -- Connection count should match expected participant numbers -- Unusually high message counts might indicate protocol issues -- Connection drops might indicate network issues - -Calls Plugin Metrics -^^^^^^^^^^^^^^^^^ - -Similar metrics are available for the Calls plugin with the following prefixes: - -- Process metrics: ``mattermost_plugin_calls_process_*`` -- WebRTC connection metrics: ``mattermost_plugin_calls_rtc_*`` -- WebSocket metrics: ``mattermost_plugin_calls_websocket_*`` -- Store metrics: ``mattermost_plugin_calls_store_ops_total`` - -Performance Baselines ------------------- - -The following performance benchmarks provide baseline metrics for RTCD deployments under various load conditions and configurations. - -**Deployment specifications** - -- 1x r6i.large nginx proxy -- 3x c5.large MM app nodes (HA) -- 2x db.x2g.xlarge RDS Aurora MySQL v8 (one writer, one reader) -- 1x (c7i.xlarge, c7i.2xlarge, c7i.4xlarge) RTCD -- 2x c7i.2xlarge load-test agents - -**App specifications** - -- Mattermost v9.6 -- Mattermost Calls v0.28.0 -- RTCD v0.16.0 -- load-test agent v0.28.0 - -**Media specifications** - -- Speech sample bitrate: 80Kbps -- Screen sharing sample bitrate: 1.6Mbps - -**Results** - -Below are the detailed benchmarks based on internal performance testing: - -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| Calls | Users/call | Unmuted/call | Screen sharing | CPU (avg) | Memory (avg) | Bandwidth (in/out) | Instance (EC2) | -+=======+============+==============+================+===========+==============+====================+================+ -| 100 | 8 | 2 | no | 60% | 0.5GB | 22Mbps / 125Mbps | c6i.xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 100 | 8 | 2 | no | 30% | 0.5GB | 22Mbps / 125Mbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 100 | 8 | 2 | yes | 86% | 0.7GB | 280Mbps / 2.2Gbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 10 | 50 | 2 | no | 35% | 0.3GB | 5.25Mbps / 86Mbps | c6i.xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 10 | 50 | 2 | no | 16% | 0.3GB | 5.25Mbps / 86Mbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 10 | 50 | 2 | yes | 90% | 0.3GB | 32Mbps / 1.33Gbps | c6i.xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 10 | 50 | 2 | yes | 45% | 0.3GB | 32Mbps / 1.33Gbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 5 | 200 | 2 | no | 65% | 0.6GB | 8.2Mbps / 180Mbps | c6i.xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 5 | 200 | 2 | no | 30% | 0.6GB | 8.2Mbps / 180Mbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ -| 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | -+-------+------------+--------------+----------------+-----------+--------------+--------------------+----------------+ - -Other Calls Documentation ----------------- - -- `Calls Overview `__: Overview of deployment options and architecture -- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service -- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription -- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments -- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques - -Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file diff --git a/source/configure/calls-offloader-setup.rst b/source/configure/calls-offloader-setup.rst deleted file mode 100644 index 195020f787f..00000000000 --- a/source/configure/calls-offloader-setup.rst +++ /dev/null @@ -1,404 +0,0 @@ -Calls Offloader Setup and Configuration -======================================= - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -.. raw:: html - -

- -This guide provides detailed instructions for setting up, configuring, and validating the Mattermost calls-offloader service used for call recording and transcription features. - -- `Overview <#overview>`__ -- `Prerequisites <#prerequisites>`__ -- `Installation and deployment <#installation-and-deployment>`__ -- `Configuration <#configuration>`__ -- `Validation and testing <#validation-and-testing>`__ -- `Integration with Mattermost <#integration-with-mattermost>`__ -- `Troubleshooting <#troubleshooting>`__ - -Overview --------- - -The calls-offloader service is a dedicated microservice that handles resource-intensive tasks for Mattermost Calls, including: - -- **Call recording**: Captures audio and screen sharing content from calls -- **Call transcription**: Provides automated transcription of recorded calls -- **Live captions** (Experimental): Real-time transcription during active calls - -By offloading these tasks to a dedicated service, the main Mattermost server and RTCD service can focus on core functionality while maintaining optimal performance. - -Prerequisites -------------- - -Before deploying calls-offloader, ensure you have: - -- A Mattermost Enterprise license -- A properly configured Mattermost Calls deployment (either integrated or with RTCD) -- Docker installed and running (for Docker-based job execution) -- Sufficient storage space for recordings (see `Storage Requirements <#storage-requirements>`__) -- A server or container environment with adequate resources - -System Requirements -^^^^^^^^^^^^^^^^^ - -For detailed system requirements and performance recommendations, refer to the `calls-offloader performance documentation `__. - -Storage Requirements -^^^^^^^^^^^^^^^^^^ - -Call recordings can consume significant storage space: - -- Audio-only recordings: ~1MB per minute per participant -- Screen sharing recordings: ~10-50MB per minute depending on content - -Installation and Deployment ---------------------------- - -Bare Metal or VM Deployment -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. Download the latest release from the `calls-offloader GitHub repository `__ - -2. Create the necessary directories: - - .. code-block:: bash - - sudo mkdir -p /opt/calls-offloader/data/db - sudo useradd --system --home /opt/calls-offloader calls-offloader - sudo chown -R calls-offloader:calls-offloader /opt/calls-offloader - -3. Create a configuration file (``/opt/calls-offloader/config.toml``): - - .. code-block:: toml - - [api] - http.listen_address = ":4545" - http.tls.enable = false - http.tls.cert_file = "" - http.tls.cert_key = "" - security.allow_self_registration = true - security.enable_admin = true - security.admin_secret_key = "changeme" - security.session_cache.expiration_minutes = 1440 - - [store] - data_source = "/opt/calls-offloader/data/db" - - [jobs] - api_type = "docker" - max_concurrent_jobs = 2 - failed_jobs_retention_time = "7d" - image_registry = "mattermost" - - [logger] - enable_console = true - console_json = false - console_level = "INFO" - enable_file = true - file_json = true - file_level = "INFO" - file_location = "/opt/calls-offloader/calls-offloader.log" - enable_color = true - -4. Create a systemd service file (``/etc/systemd/system/calls-offloader.service``): - - .. code-block:: ini - - [Unit] - Description=Mattermost Calls Offloader Service - After=network.target docker.service - Requires=docker.service - - [Service] - Type=simple - User=calls-offloader - WorkingDirectory=/opt/calls-offloader - ExecStart=/opt/calls-offloader/calls-offloader --config /opt/calls-offloader/config.toml - Restart=always - RestartSec=10 - LimitNOFILE=65536 - - [Install] - WantedBy=multi-user.target - -5. Enable and start the service: - - .. code-block:: bash - - sudo systemctl daemon-reload - sudo systemctl enable calls-offloader - sudo systemctl start calls-offloader - -6. Check the service status: - - .. code-block:: bash - - sudo systemctl status calls-offloader - -7. Verify the service is responding: - - .. code-block:: bash - - curl http://localhost:4545/version - # Example output: - # {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} - - -Configuration -------------- - -API Configuration -^^^^^^^^^^^^^^^ - -The API section controls how the service accepts requests: - -- **http.listen_address**: The address and port where the service listens (default: ``:4545``) -- **http.tls.enable**: Whether to use TLS encryption for the API -- **security.allow_self_registration**: Allow clients to self-register for job management -- **security.enable_admin**: Enable admin functionality -- **security.admin_secret_key**: Secret key for admin authentication (change from default!) - -Store Configuration -^^^^^^^^^^^^^^^^^ - -Controls persistent data storage: - -- **data_source**: Path to directory for storing job metadata and state - -Jobs Configuration -^^^^^^^^^^^^^^^^ - -Controls job processing behavior: - -- **api_type**: Job execution backend (``docker`` or ``kubernetes``) -- **max_concurrent_jobs**: Maximum number of simultaneous recording/transcription jobs -- **failed_jobs_retention_time**: How long to keep failed job data before cleanup -- **image_registry**: Docker registry for job runner images (typically ``mattermost``) - -Logger Configuration -^^^^^^^^^^^^^^^^^^ - -Controls logging output: - -- **enable_console**: Log to console output -- **console_json**: Use JSON format for console logs -- **console_level**: Log level for console (DEBUG, INFO, WARN, ERROR) -- **enable_file**: Log to file -- **file_location**: Path to log file -- **enable_color**: Use colored output for console logs - -Private Network Configuration -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When the Mattermost deployment is running in a private network, additional configuration may be necessary for the jobs spawned by the calls-offloader service to reach the Mattermost server. - -In such cases, you can override the site URL used by recorder jobs or transcriber jobs to connect to Mattermost by setting the following environment variables on the Mattermost server: - -- **MM_CALLS_RECORDER_SITE_URL**: Override the site URL used by recording jobs -- **MM_CALLS_TRANSCRIBER_SITE_URL**: Override the site URL used by transcription jobs - -Example configuration: - -Create or edit the Mattermost environment file (``/opt/mattermost/config/mattermost.environment``): - -.. code-block:: bash - - MM_CALLS_RECORDER_SITE_URL="http://internal-mattermost-server:8065" - MM_CALLS_TRANSCRIBER_SITE_URL="http://internal-mattermost-server:8065" - -Then ensure your Mattermost systemd service references this environment file: - -.. code-block:: ini - - [Unit] - Description=Mattermost - After=network.target - - [Service] - Type=notify - EnvironmentFile=/opt/mattermost/config/mattermost.environment - ExecStart=/opt/mattermost/bin/mattermost - TimeoutStartSec=3600 - KillMode=mixed - Restart=always - RestartSec=10 - WorkingDirectory=/opt/mattermost - User=mattermost - Group=mattermost - - [Install] - WantedBy=multi-user.target - -This is particularly useful when: - -- The calls-offloader service runs in a different network segment than clients -- Internal DNS resolution differs from external URLs -- You need to use internal load balancer endpoints for job communication - -Validation and Testing ---------------------- - -After deploying calls-offloader, validate the installation: - -1. **Check service status**: - - .. code-block:: bash - - # For systemd - sudo systemctl status calls-offloader - - -2. **Test API connectivity**: - - **From the calls-offloader server (localhost test)**: - - .. code-block:: bash - - curl http://localhost:4545/version - # Should return version information - # Example: {"buildDate":"2025-03-10 19:13","buildVersion":"v0.9.2","buildHash":"a4bd418","goVersion":"go1.23.6"} - - **From the Mattermost server**: - - .. code-block:: bash - - curl http://YOUR_CALLS_OFFLOADER_SERVER:4545/version - # Should return the same version information - # This confirms network connectivity from Mattermost to calls-offloader - - If the localhost test works but the Mattermost server test fails, check: - - - Firewall rules or SELinux policies on the calls-offloader server (port 4545 must be accessible) - - Network connectivity between Mattermost and calls-offloader servers - - calls-offloader service binding configuration (ensure it's not bound to localhost only) - -3. **Verify Docker integration** (if using docker api_type): - - .. code-block:: bash - - # Check that system user running calls-offloader can access Docker - sudo -u calls-offloader docker ps - -Integration with Mattermost ---------------------------- - -Once calls-offloader is properly set up and validated, configure Mattermost to use it: - -1. Go to **System Console > Plugins > Calls** - -2. In the **Job Service** section: - - - Set **Job Service URL** to your calls-offloader service (e.g., ``http://calls-offloader-server:4545``) - -3. Enable recording and transcription features as needed: - - - **Enable Call Recordings**: Toggle to allow call recordings - - **Enable Call Transcriptions**: Toggle to allow call transcriptions - - **Enable Live Captions** (Experimental): Toggle to allow real-time transcription - -4. Save the configuration - -5. Restart the Calls plugin to re-establish state: - - - Go to **System Console > Plugins > Plugin Management** - - Find the **Calls** plugin and click **Disable** - - Wait a few seconds, then click **Enable** - -6. Test by starting a call and enabling recording or live captions - -Troubleshooting ---------------- - -Common Issues -^^^^^^^^^^^ - -**"failed to create recording job: max concurrent jobs reached"** - -This error occurs when the calls-offloader service has reached its configured job limit. - -Solutions: - -- Increase ``max_concurrent_jobs`` in the configuration -- Check if jobs are hanging and restart the service -- Monitor system resources and scale up if needed - -**Jobs not processing** - -Check the following: - -- Verify the calls-offloader service is running: ``sudo systemctl status calls-offloader`` -- Ensure network connectivity between Mattermost and calls-offloader -- Check Docker daemon is running and accessible by the user running `calls-offloader`: ``docker ps`` -- Verify authentication configuration matches between services -- Review service logs for specific error messages - -**Docker permission issues** - -If using Docker API and seeing permission errors: - -.. code-block:: bash - - # Add calls-offloader user to docker group - sudo usermod -a -G docker calls-offloader - sudo systemctl restart calls-offloader - -Debugging Commands -^^^^^^^^^^^^^^^^ - -Monitor calls-offloader job containers: - -.. code-block:: bash - - # View running job containers - docker ps --format "{{.ID}} {{.Image}}" | grep "calls" - - # Follow logs for debugging - docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {} - - # View completed job containers - docker ps -a --filter "status=exited" - -Monitor service health: - -.. code-block:: bash - - # Check service version and health - curl http://localhost:4545/version - -Check service logs: - -.. code-block:: bash - - # View recent logs - sudo journalctl -u calls-offloader -f - - # View log file (if file logging enabled) - tail -f /opt/calls-offloader/calls-offloader.log - -Performance Monitoring -^^^^^^^^^^^^^^^^^^^^ - -Monitor calls-offloader performance and resource usage to ensure optimal operation. See `Calls Metrics and Monitoring `__ for details on setting up metrics and observability. - -Other Calls Documentation ----------------- - -- `Calls Overview `__: Overview of deployment options and architecture -- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service -- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability -- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments -- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques -- `calls-offloader performance documentation `__: Detailed performance tuning and monitoring recommendations \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.rst b/source/configure/calls-rtcd-setup.rst deleted file mode 100644 index 18dc0001f6c..00000000000 --- a/source/configure/calls-rtcd-setup.rst +++ /dev/null @@ -1,415 +0,0 @@ -RTCD Setup and Configuration -========================= - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -.. raw:: html - -
- -Note - -|plans-img-yellow| The rtcd service is available only on `Enterprise `__ plans - -.. |plans-img-yellow| image:: ../_static/images/badges/flag_icon_yellow.svg - :class: mm-badge-flag - -.. raw:: html - -
- -This guide provides detailed instructions for setting up, configuring, and validating a Mattermost Calls deployment using the dedicated RTCD service. - -- `Prerequisites <#prerequisites>`__ -- `Installation and deployment <#installation-and-deployment>`__ -- `Configuration <#configuration>`__ -- `Validation and testing <#validation-and-testing>`__ -- `Horizontal scaling <#horizontal-scaling>`__ -- `Integration with Mattermost <#integration-with-mattermost>`__ - -Prerequisites ------------- - -Before deploying RTCD, ensure you have: - -- A Mattermost Enterprise license -- A server or VM with sufficient CPU and network capacity (see the `Performance `__ section for sizing guidance) - -Network Requirements ------------------- - -The following network connectivity is required: - -+-------------------+--------+-----------------+-------------------------+------------------------+ -| Service | Ports | Protocols | Source | Target | -+===================+========+=================+=========================+========================+ -| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | -+-------------------+--------+-----------------+-------------------------+------------------------+ -| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | -+-------------------+--------+-----------------+-------------------------+------------------------+ - -Installation and Deployment --------------------------- - -There are multiple ways to deploy RTCD, depending on your environment. We recommend the following order based on production readiness and operational control: - -Bare Metal or VM Deployment (Recommended) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This is the recommended deployment method for production environments as it provides the best performance and operational control. - -1. Download the latest release from the `RTCD GitHub repository `__ - -2. Create a configuration file (``/opt/rtcd/rtcd.toml``) with the following settings: - - .. code-block:: toml - - [api] - http.listen_address = ":8045" - security.allow_self_registration = true - - [rtc] - ice_address_udp = "" - ice_port_udp = 8443 - ice_address_tcp = "" - ice_port_tcp = 8443 - ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" - - # UDP port range for WebRTC connections - ice.port_range.min = 9000 - ice.port_range.max = 10000 - - # STUN/TURN server configuration - ice_servers = [ - { urls = ["stun:stun.global.calls.mattermost.com:3478"] } - ] - - [store] - data_source = "/opt/rtcd/data/db" - - [logger] - enable_console = true - console_json = true - console_level = "INFO" - enable_file = true - file_json = true - file_level = "INFO" - file_location = "/opt/rtcd/rtcd.log" - enable_color = true - - [mattermost] - host = "http://YOUR_MATTERMOST_SERVER:8065" - -3. Create the data directory: - - .. code-block:: bash - - sudo mkdir -p /opt/rtcd/data/db - -4. Create a systemd service file (``/etc/systemd/system/rtcd.service``): - - .. code-block:: ini - - [Unit] - Description=Mattermost RTCD Server - After=network.target - - [Service] - Type=simple - User=root - ExecStart=/opt/rtcd/rtcd --config /opt/rtcd/rtcd.toml - Restart=always - RestartSec=10 - LimitNOFILE=65536 - - [Install] - WantedBy=multi-user.target - -5. Enable and start the service: - - .. code-block:: bash - - sudo systemctl daemon-reload - sudo systemctl enable rtcd - sudo systemctl start rtcd - -6. Check the service status: - - .. code-block:: bash - - sudo systemctl status rtcd - -Docker Deployment -^^^^^^^^^^^^^^^ - -Docker deployment is suitable for development, testing, or containerized production environments: - -1. Run the RTCD container with basic configuration: - - .. code-block:: bash - - docker run -d --name rtcd \ - -e "RTCD_LOGGER_ENABLEFILE=false" \ - -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ - -p 8443:8443/udp \ - -p 8443:8443/tcp \ - -p 8045:8045/tcp \ - mattermost/rtcd:latest - -2. For debugging purposes, you can enable more detailed logging: - - .. code-block:: bash - - docker run -d --name rtcd \ - -e "RTCD_LOGGER_ENABLEFILE=false" \ - -e "RTCD_LOGGER_CONSOLELEVEL=DEBUG" \ - -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ - -p 8443:8443/udp \ - -p 8443:8443/tcp \ - -p 8045:8045/tcp \ - mattermost/rtcd:latest - - To view the logs: - - .. code-block:: bash - - docker logs -f rtcd - -You can also use a mounted configuration file instead of environment variables: - -.. code-block:: bash - - docker run -d --name rtcd \ - -p 8045:8045 \ - -p 8443:8443/udp \ - -p 8443:8443/tcp \ - -v /path/to/config.toml:/rtcd/config/config.toml \ - mattermost/rtcd:latest - -For a complete sample configuration file, see the `RTCD config.sample.toml `__ in the official repository. - -Kubernetes Deployment -^^^^^^^^^^^^^^^^^^^ - -For Kubernetes deployments, use the official Helm chart: - -1. Add the Mattermost Helm repository: - - .. code-block:: bash - - helm repo add mattermost https://helm.mattermost.com - helm repo update - -2. Install the RTCD chart: - - .. code-block:: bash - - helm install mattermost-rtcd mattermost/mattermost-rtcd \ - --set ingress.enabled=true \ - --set ingress.host=rtcd.example.com \ - --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ - --set rtcd.ice.hostOverride=rtcd.example.com - - Refer to the `RTCD Helm chart documentation `__ for additional configuration options. - -Configuration ------------ - -RTCD Configuration File -^^^^^^^^^^^^^^^^^^^^^ - -The RTCD service uses a TOML configuration file. Here's a comprehensive example with commonly used settings: - -.. code-block:: toml - - [api] - # The address and port to which the HTTP API server will listen - http.listen_address = ":8045" - # Security settings for authentication - security.allow_self_registration = false - security.enable_admin = true - security.admin_secret_key = "YOUR_API_KEY" - # Configure allowed origins for CORS - security.allowed_origins = ["https://mattermost.example.com"] - - [rtc] - # The UDP address and port for media traffic - ice_address_udp = "" - ice_port_udp = 8443 - # The TCP address and port for fallback connections - ice_address_tcp = "" - ice_port_tcp = 8443 - # Public hostname or IP that clients will use to connect - ice_host_override = "rtcd.example.com" - - [logger] - # Logging configuration - enable_console = true - console_json = false - console_level = "INFO" - enable_file = true - file_json = true - file_level = "DEBUG" - file_location = "rtcd.log" - - [metrics] - # Prometheus metrics configuration - enable_prom = true - prom_port = 9090 - -Key Configuration Options: - -- **api.http.listen_address**: The address and port where the RTCD HTTP API service listens -- **rtc.ice_address_udp**: The UDP address for media traffic (empty means listen on all interfaces) -- **rtc.ice_port_udp**: The UDP port for media traffic -- **rtc.ice_address_tcp**: The TCP address for fallback media traffic -- **rtc.ice_port_tcp**: The TCP port for fallback media traffic -- **rtc.ice_host_override**: The public hostname or IP address clients will use to connect to RTCD -- **api.security.allowed_origins**: List of allowed origins for CORS -- **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD - -STUN/TURN Configuration -^^^^^^^^^^^^^^^^^^^^^ - -For clients behind strict firewalls, you may need to configure STUN/TURN servers. In the RTCD configuration file, reference your STUN/TURN servers as follows: - -.. code-block:: toml - - [rtc] - # STUN/TURN server configuration - ice_servers = [ - { urls = ["stun:stun.example.com:3478"] }, - { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } - ] - -We recommend using `coturn `__ for your TURN server implementation. - -System Tuning -^^^^^^^^^^^ - -For high-volume deployments, tune your Linux system: - -1. Add the following to ``/etc/sysctl.conf``: - - .. code-block:: bash - - # Increase UDP buffer sizes - net.core.rmem_max = 16777216 - net.core.wmem_max = 16777216 - net.core.optmem_max = 16777216 - -2. Apply the settings: - - .. code-block:: bash - - sudo sysctl -p - -Validation and Testing --------------------- - -After deploying RTCD, validate the installation: - -1. **Check service status and version**: - - .. code-block:: bash - - curl http://YOUR_RTCD_SERVER:8045/version - # Should return a JSON object with service information - # Example: {"build_hash":"abc123","build_date":"2023-01-15T12:00:00Z","build_version":"0.11.0","goVersion":"go1.20.4"} - -2. **Test UDP connectivity**: - - On the RTCD server: - - .. code-block:: bash - - nc -l -u -p 8443 - - On a client machine: - - .. code-block:: bash - - nc -v -u YOUR_RTCD_SERVER 8443 - - Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. - - Note: This test must be run with the RTCD service stopped, as it binds to the same port. - - .. code-block:: bash - - sudo systemctl stop rtcd - - -3. **Test TCP connectivity** (if enabled): - - Similar to the UDP test, but remove the ``-u`` flag from both commands. - -4. **Monitor metrics**: - - Refer to `Calls Metrics and Monitoring `__ for setting up Calls metrics and monitoring. - -Horizontal Scaling ----------------- - -To scale RTCD horizontally: - -1. **Deploy multiple RTCD instances**: - - Deploy multiple RTCD servers, each with their own unique IP address. - -2. **Configure DNS-based load balancing**: - - Set up a DNS record that points to multiple RTCD IP addresses: - - .. code-block:: bash - - rtcd.example.com. IN A 10.0.0.1 - rtcd.example.com. IN A 10.0.0.2 - rtcd.example.com. IN A 10.0.0.3 - -3. **Configure health checks**: - - Set up health checks to automatically remove unhealthy RTCD instances from DNS. - -4. **Configure Mattermost**: - - In the Mattermost System Console, set the **RTCD Service URL** to your DNS name (e.g., ``rtcd.example.com``). - -The Mattermost Calls plugin will distribute calls among the available RTCD hosts. Remember that a single call will always be hosted on one RTCD instance; sessions belonging to the same call are not spread across different instances. - -Integration with Mattermost -------------------------- - -Once RTCD is properly set up and validated, configure Mattermost to use it: - -1. Go to **System Console > Plugins > Calls** - -2. Enable the **Enable RTCD Service** option - -3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname) - -4. If configured, enter the **RTCD API Key** that matches the one in your RTCD configuration - -5. Save the configuration - -6. Test by creating a new call in any Mattermost channel - -7. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics - -Other Calls Documentation ----------------- - -- `Calls Overview `__: Overview of deployment options and architecture -- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription -- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability -- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments -- `Calls Troubleshooting `__: Detailed troubleshooting steps and debugging techniques - -For detailed Mattermost Calls configuration options, see the `Calls Plugin Configuration Settings `__ documentation. \ No newline at end of file diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index bf25fbe7b12..29d7d9620fc 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -89,9 +89,8 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa Test if the RTCD API is reachable: ```bash - curl http://YOUR_RTCD_SERVER:8045/api/v1/health - # Expected response: {"status":"ok"} - ``` + curl http://YOUR_RTCD_SERVER:8045/version + # Example response: {"buildDate":"2025-04-02 21:33","buildVersion":"v1.1.0","buildHash":"7bc1f7a","goVersion":"go1.23.6","goOS":"linux","goArch":"amd64"} ``` 2. **UDP connectivity test**: diff --git a/source/configure/calls-troubleshooting.rst b/source/configure/calls-troubleshooting.rst deleted file mode 100644 index f54dfff24d0..00000000000 --- a/source/configure/calls-troubleshooting.rst +++ /dev/null @@ -1,431 +0,0 @@ -Troubleshooting Mattermost Calls -=========================== - -.. include:: ../_static/badges/allplans-cloud-selfhosted.rst - :start-after: :nosearch: - -This guide provides comprehensive troubleshooting steps for Mattermost Calls, particularly focusing on the dedicated RTCD deployment model. Follow these steps to identify and resolve common issues. - -- `Common issues <#common-issues>`__ -- `Connectivity troubleshooting <#connectivity-troubleshooting>`__ -- `Log analysis <#log-analysis>`__ -- `Performance issues <#performance-issues>`__ -- `Debugging tools <#debugging-tools>`__ -- `Advanced diagnostics <#advanced-diagnostics>`__ - -Common Issues ------------ - -Calls Not Connecting -^^^^^^^^^^^^^^^^^^^^ - -**Symptoms**: Users can start calls but cannot connect, or calls connect but drop quickly. - -**Possible causes and solutions**: - -1. **Network connectivity issues**: - - Verify that UDP port 8443 (or your configured port) is open between clients and RTCD servers - - Ensure TCP port 8045 is open between Mattermost and RTCD servers - - Check that any load balancers are properly configured for UDP traffic - -2. **ICE configuration issues**: - - Verify the ``rtc.ice_host_override`` setting in RTCD configuration matches the publicly accessible hostname or IP of the RTCD server - - If this setting is incorrect, client browser console may show errors like: ``com.mattermost.calls: peer error timed out waiting for rtc connection`` - - Meanwhile, RTCD `trace` level logs might show internal IP addresses in ICE connection logs: - - .. code-block:: json - - {"timestamp":"2025-05-14 10:29:08.935 Z","level":"trace","msg":"Ping STUN from udp4 host 172.31.29.117:8443 (resolved: 172.31.29.117:8443) to udp4 host 192.168.64.1:59737 (resolved: 192.168.64.1:59737)","caller":"rtc/logger.go:54","origin":"ice/v4.(*Agent).sendBindingRequest github.com/pion/ice/v4@v4.0.3/agent.go:921"} - -3. **API connectivity**: - - Verify that Mattermost servers can reach the RTCD API endpoint - - Check that the API key is correctly configured in both Mattermost and RTCD - -4. **Plugin configuration**: - - Ensure the Calls plugin is enabled and properly configured - - Verify the RTCD service URL is correct in the System Console - -Audio Issues -^^^^^^^^^^^ - -**Symptoms**: Users can connect to calls, but audio is one-way, choppy, or not working. - -**Possible causes and solutions**: - -1. **Client permissions**: - - Ensure browser/app has microphone permissions - - Check if users are using multiple audio devices that might interfere - -2. **Network quality**: - - High latency or packet loss can cause audio issues - - Try testing with TCP fallback enabled (requires RTCD v0.11+ and Calls v0.17+) - -3. **Audio device configuration**: - - Users should verify their audio input/output settings - - Try different browsers or the desktop app - -Call Quality Issues -^^^^^^^^^^^^^^^^^ - -**Symptoms**: Calls connect but quality is poor, with latency, echo, or distortion. - -**Possible causes and solutions**: - -1. **Server resources**: - - Check CPU usage on RTCD servers - high CPU can cause quality issues - - Refer to the `Performance Monitoring setup guide <../performance-monitoring/setup-guide.rst>`__ for detailed instructions on monitoring and optimizing performance - - Monitor network bandwidth usage - -2. **Network congestion**: - - Check for packet loss between clients and RTCD - - Consider network QoS settings to prioritize real-time traffic - -3. **Client-side issues**: - - Browser or app limitations - - Hardware limitations (CPU, memory) - - Network congestion at the user's location - -Connectivity Troubleshooting --------------------------- - -Basic Connectivity Tests -^^^^^^^^^^^^^^^^^^^^^^ - -1. **HTTP API connectivity test**: - - Test if the RTCD API is reachable: - - .. code-block:: bash - - curl http://YOUR_RTCD_SERVER:8045/api/v1/health - # Expected response: {"status":"ok"} - -2. **UDP connectivity test**: - - On the RTCD server: - - .. code-block:: bash - - nc -l -u -p 8443 - - On a client machine: - - .. code-block:: bash - - nc -v -u YOUR_RTCD_SERVER 8443 - - Type a message and press Enter. If you see the message on both sides, UDP connectivity is working. - -3. **TCP fallback connectivity test**: - - Same as the UDP test, but without the ``-u`` flag: - - On the RTCD server: - - .. code-block:: bash - - nc -l -p 8443 - - On a client machine: - - .. code-block:: bash - - nc -v YOUR_RTCD_SERVER 8443 - -Network Packet Analysis -^^^^^^^^^^^^^^^^^^^^^ - -To capture and analyze network traffic: - -1. **Capture UDP traffic on the RTCD server**: - - .. code-block:: bash - - sudo tcpdump -n 'udp port 8443' -i any - -2. **Capture TCP API traffic**: - - .. code-block:: bash - - sudo tcpdump -n 'tcp port 8045' -i any - -3. **Analyze traffic patterns**: - - - Verify packets are flowing both ways - - Look for ICMP errors that might indicate firewall issues - - Check for patterns of packet loss - -4. **Use Wireshark for deeper analysis**: - - For more detailed packet inspection, capture traffic with tcpdump and analyze with Wireshark: - - .. code-block:: bash - - sudo tcpdump -n -w calls_traffic.pcap 'port 8443' - - Then analyze the ``calls_traffic.pcap`` file with Wireshark. - -Firewall Configuration Checks -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. **Check iptables rules** (Linux): - - .. code-block:: bash - - sudo iptables -L -n - - Ensure there are no rules blocking UDP port 8443 or TCP ports 8045/8443. - -2. **Check cloud provider security groups**: - - Verify that security groups or network ACLs allow: - - Inbound UDP on port 8443 from client networks - - Inbound TCP on port 8045 from Mattermost server networks - - Inbound TCP on port 8443 (if TCP fallback is enabled) - -3. **Check intermediate firewalls**: - - - Corporate firewalls might block UDP traffic - - Some networks might require TURN servers for traversal - -Log Analysis ----------- - -RTCD Logs -^^^^^^^^ - -The RTCD service logs important events and errors. Set the log level to "debug" for troubleshooting: - -1. **In the configuration file**: - - .. code-block:: json - - { - "log": { - "level": "debug", - "json": true - } - } - -2. **Common log patterns to look for**: - - - **Connection errors**: Look for "failed to connect" or "connection error" messages - - **ICE negotiation failures**: Look for "ICE failed" or "ICE timeout" messages - - **API authentication issues**: Look for "unauthorized" or "invalid API key" messages - -Mattermost Logs -^^^^^^^^^^^^^ - -Check the Mattermost server logs for Calls plugin related issues: - -1. **Enable debug logging** in System Console > Environment > Logging > File Log Level - -2. **Filter for Calls-related logs**: - - .. code-block:: bash - - grep -i "calls" /path/to/mattermost.log - -3. **Look for common patterns**: - - - Connection errors to RTCD - - Plugin initialization issues - - WebSocket connection problems - -Browser Console Logs -^^^^^^^^^^^^^^^^^ - -Instruct users to check their browser console logs: - -1. **In Chrome/Edge**: - - Press F12 to open Developer Tools - - Go to the Console tab - - Look for errors related to WebRTC, Calls, or media permissions - -2. **Specific patterns to look for**: - - - "getUserMedia" errors (microphone permission issues) - - "ICE connection" failures - - WebSocket connection errors - -Performance Issues ---------------- - -Diagnosing High CPU Usage -^^^^^^^^^^^^^^^^^^^^^^^ - -If RTCD servers show high CPU usage: - -1. **Check concurrent calls and participants**: - - - Access the Prometheus metrics endpoint to see active sessions - - Compare with the benchmark data in the documentation - -2. **Profile CPU usage** (Linux): - - .. code-block:: bash - - top -p $(pgrep rtcd) - - Or for detailed per-thread usage: - - .. code-block:: bash - - ps -eLo pid,ppid,tid,pcpu,comm | grep rtcd - -3. **Enable pprof profiling** (if needed): - - Add to your RTCD configuration: - - .. code-block:: json - - { - "debug": { - "pprof": true, - "pprofPort": 6060 - } - } - - Then capture a CPU profile: - - .. code-block:: bash - - curl http://localhost:6060/debug/pprof/profile > cpu.profile - - Analyze with: - - .. code-block:: bash - - go tool pprof -http=:8080 cpu.profile - -Diagnosing Network Bottlenecks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you suspect network bandwidth issues: - -1. **Monitor network utilization**: - - .. code-block:: bash - - iftop -n - -2. **Check for packet drops**: - - .. code-block:: bash - - netstat -su | grep -E 'drop|error' - -3. **Verify system network buffers**: - - .. code-block:: bash - - sysctl -a | grep net.core.rmem - sysctl -a | grep net.core.wmem - - Ensure these match the recommended values: - - .. code-block:: bash - - net.core.rmem_max = 16777216 - net.core.wmem_max = 16777216 - net.core.optmem_max = 16777216 - -Recording and Transcription Issues ----------------------------------- - -For troubleshooting calls-offloader service issues including recording and transcription problems, see the `Calls Offloader Setup and Configuration `__ guide. - -Debugging Tools ------------- - - -Prometheus Metrics Analysis -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Use Prometheus metrics for real-time and historical performance data: - -Import the official `Mattermost Calls dashboard `__ into Grafana for visualization. - -Advanced Diagnostics ------------------ - -WebRTC Diagnostic Commands -^^^^^^^^^^^^^^^^^^^^^^^^ - -For detailed WebRTC diagnostics: - -1. **Test STUN server connectivity**: - - .. code-block:: bash - - # Using stun-client (you may need to install it) - stun-client stun.global.calls.mattermost.com - - This should return your public IP address if STUN is working correctly. - -2. **Verify TURN server**: - - .. code-block:: bash - - # Using turnutils_uclient (part of coturn) - turnutils_uclient -v -s your-turn-server -u username -p password - - This tests if your TURN server is correctly configured. - -3. **Test end-to-end latency**: - - Between client locations and RTCD server: - - .. code-block:: bash - - ping -c 10 your-rtcd-server - - Look for consistent, low latency (<100ms ideally for voice calls). - -Client-Side Testing Tools -^^^^^^^^^^^^^^^^^^^^^^^ - -Tools to help diagnose client-side issues: - -1. **WebRTC Troubleshooter**: - - Direct users to `WebRTC Troubleshooter `__ for browser capability testing. - -2. **Network Quality Tests**: - - Use `Speedtest `__ or similar to check internet connection quality. - -3. **Browser-Specific WebRTC Info**: - - - Chrome: chrome://webrtc-internals - - Firefox: about:webrtc - -When to Contact Support -^^^^^^^^^^^^^^^^^^^^ - -Consider contacting Mattermost Support when: - -1. You've tried troubleshooting steps without resolution -2. You're experiencing persistent connection failures across multiple clients -3. You notice unexpected or degraded performance despite proper configuration -4. You need help interpreting diagnostic information -5. You suspect a bug in the Calls plugin or RTCD service - -When contacting support, please include: - -- RTCD version and configuration (with sensitive information redacted) -- Mattermost server version -- Calls plugin version -- Client environments (browsers, OS versions) -- Relevant logs and diagnostic information -- Detailed description of the issue and steps to reproduce - -Other Calls Documentation ----------------- - -- `Calls Overview `__: Overview of deployment options and architecture -- `RTCD Setup and Configuration `__: Comprehensive guide for setting up the dedicated RTCD service -- `Calls Offloader Setup and Configuration `__: Setup guide for call recording and transcription -- `Calls Metrics and Monitoring `__: Guide to monitoring Calls performance using metrics and observability -- `Calls Deployment on Kubernetes `__: Detailed guide for deploying Calls in Kubernetes environments -- Monitoring dashboards screenshots \ No newline at end of file From 0b62a410262aac98fff02626e84a883116d69167 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 13:19:49 -0400 Subject: [PATCH 19/60] Updating RTCD Debug log config, fixed broken links --- source/collaborate/make-calls.rst | 2 +- source/configure/calls-troubleshooting.md | 13 ++++++------- source/configure/plugins-configuration-settings.rst | 8 ++++---- source/deploy/server/containers/install-docker.rst | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/source/collaborate/make-calls.rst b/source/collaborate/make-calls.rst index 831bc31108d..fd942c06983 100644 --- a/source/collaborate/make-calls.rst +++ b/source/collaborate/make-calls.rst @@ -10,7 +10,7 @@ Using a web browser, the desktop app, or the mobile app, you can `join a call <# - All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. - For group calls up to 50 concurrent users, Mattermost Enterprise, Professional, or Mattermost Cloud is required. - - Enterprise customers can also `record calls <#record-a-call>`__, enable :ref:`live text captions ` during calls, and `transcribe recorded calls <#transcribe-recorded-calls>`__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the :ref:`dedicated rtcd service `. + - Enterprise customers can also `record calls <#record-a-call>`__, enable :ref:`live text captions ` during calls, and `transcribe recorded calls <#transcribe-recorded-calls>`__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the :doc:`dedicated RTCD service `. - Mattermost Cloud users can start calling right out of the box. For Mattermost self-hosted deployments, System admins need to enable and configure the plugin :ref:`using the System Console `. .. include:: ../_static/badges/academy-calls.rst diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index 29d7d9620fc..4824e8b1a2b 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -186,15 +186,14 @@ The RTCD service logs important events and errors. Set the log level to "debug" 1. **In the configuration file**: - ```json - { - "log": { - "level": "debug", - "json": true - } - } + ```toml + [logger] + enable_file = true + file_level = "DEBUG" ``` + Restart the RTCD service after making these changes + 2. **Common log patterns to look for**: - **Connection errors**: Look for "failed to connect" or "connection error" messages diff --git a/source/configure/plugins-configuration-settings.rst b/source/configure/plugins-configuration-settings.rst index fed0238ea68..d92c4159a26 100644 --- a/source/configure/plugins-configuration-settings.rst +++ b/source/configure/plugins-configuration-settings.rst @@ -532,7 +532,7 @@ ICE servers configurations - The configurations above, containing STUN and TURN servers, are sent to the clients and used to generate local candidates. - If hosting calls through the plugin (i.e. not using the |rtcd_service|) any configured STUN server may also be used to find the instance's public IP when none is provided through the |ice_host_override_link| option. -.. |rtcd_service| replace:: :ref:`rtcd service ` +.. |rtcd_service| replace:: :doc:`RTCD service ` **Example** @@ -764,7 +764,7 @@ Call recording quality +-----------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ .. note:: - The quality setting will affect the performance of the job service and the file size of recordings. Refer to the :ref:`deployment section ` for more information. + The quality setting will affect the performance of the job service and the file size of recordings. Refer to the :ref:`call recording and transcription section ` for more information. .. config:setting:: enable-pluginscalltranscriptions :displayname: Enable call transcriptions (Plugins - Calls) @@ -814,7 +814,7 @@ Transcriber model size +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+ .. note:: - This setting is available starting in plugin version 0.22. The model size setting will affect the performance of the job service. Refer to the :ref:`configure call recordings, transcriptions, and live captions ` documentation for more information. + This setting is available starting in plugin version 0.22. The model size setting will affect the performance of the job service. Refer to the :ref:`call recording and transcription section ` documentation for more information. .. config:setting:: call-transcriber-threads :displayname: Call transcriber threads (Plugins - Calls) @@ -837,7 +837,7 @@ Call transcriber threads +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ .. note:: - The call transcriber threads setting will affect the performance of the job service. Refer to the :ref:`configure call recordings, transcriptions, and live captions ` documentation for more information. This setting is available starting in plugin version 0.26.2. + The call transcriber threads setting will affect the performance of the job service. Refer to the :ref:`call recording and transcription section ` documentation for more information. This setting is available starting in plugin version 0.26.2. .. config:setting:: enable-pluginslivecaptions :displayname: (Experimental) Enable live captions (Plugins - Calls) diff --git a/source/deploy/server/containers/install-docker.rst b/source/deploy/server/containers/install-docker.rst index 84d29e0d35d..dfd60ddb921 100644 --- a/source/deploy/server/containers/install-docker.rst +++ b/source/deploy/server/containers/install-docker.rst @@ -183,7 +183,7 @@ Looking for a way to evaluate Mattermost on a single local machine using Docker? - This local image is self-contained (i.e., it has an internal database and works out of the box). Dropping a container using this image removes data and configuration as expected. You can see the :doc:`configuration settings ` documentation to learn more about customizing your trial deployment. - **Preview Mode** shouldn't be used in a production environment, as it uses a known password string, contains other non-production configuration settings, has email disabled, keeps no persistent data (all data lives inside the container), and doesn't support upgrades. - - If you are planning to use the calling functionality in **Preview Mode** on a non-local environment, you should ensure that the server is running on a secure (HTTPs) connection and that the :ref:`network requirements ` to run calls are met. + - If you are planning to use the calling functionality in **Preview Mode** on a non-local environment, you should ensure that the server is running on a secure (HTTPs) connection and that the :ref:`network requirements ` to run calls are met. 1. Install `Docker `__. From a4ce710307a36d8a7b824f226981a928b306ab6a Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 13:43:29 -0400 Subject: [PATCH 20/60] New debug steps, CORS MM config --- source/configure/calls-metrics-monitoring.md | 32 +++++++++++++++++ source/configure/calls-rtcd-setup.md | 36 +++++++++++++++++++ source/configure/calls-troubleshooting.md | 37 ++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md index b93bbfa0bd7..43e6a7a735b 100644 --- a/source/configure/calls-metrics-monitoring.md +++ b/source/configure/calls-metrics-monitoring.md @@ -234,6 +234,38 @@ Below are the detailed benchmarks based on internal performance testing: | 5 | 200 | 2 | no | 30% | 0.6GB | 8.2Mbps / 180Mbps | c6i.2xlarge | | 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | +## Troubleshooting Metrics Collection + +### Verify RTCD Metrics are Being Collected + +To verify that Prometheus is successfully collecting RTCD metrics, use this command: + +```bash +curl http://PROMETHEUS_IP:9090/api/v1/label/__name__/values | jq '.' | grep rtcd +``` + +This command queries Prometheus for all available metric names and filters for RTCD-related metrics. + +If no RTCD metrics appear, check: +1. RTCD is running +2. Prometheus is configured to scrape the RTCD metrics endpoint +3. RTCD metrics port is accessible from Prometheus (default: 8045) + +### Check Prometheus Scrape Targets + +To verify all Calls-related services are being scraped successfully: + +1. Open the Prometheus web interface (typically `http://PROMETHEUS_IP:9090`) +2. Navigate to **Status > Targets** +3. Look for your configured Calls services: + - Mattermost server (for Calls plugin metrics) + - RTCD service + +Each target should show status "UP" in green. If a target shows "DOWN" or errors: +- Verify the service is running +- Check network connectivity between Prometheus and the target +- Verify the metrics endpoint is accessible + ## Other Calls Documentation - [Calls Overview](calls-deployment.html): Overview of deployment options and architecture diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index c7fd09e4f44..d63ed4a94a4 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -245,6 +245,42 @@ Key Configuration Options: - **api.security.allowed_origins**: List of allowed origins for CORS - **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD +### Required Mattermost Server Configuration + +When using RTCD, you must configure the Mattermost server's CORS settings to allow proper communication between the server and the RTCD service. + +#### CORS Configuration + +The `AllowCorsFrom` setting must include your SiteURL and, if using calls-offloader in a private network, the Mattermost server's private IP address: + +**Using mmctl:** +```bash +# Basic RTCD configuration - include your SiteURL +mmctl config set ServiceSettings.AllowCorsFrom "https://your-domain.com" + +# If using calls-offloader in a private network, also include Mattermost's private IP with port 8065 +mmctl config set ServiceSettings.AllowCorsFrom "https://your-domain.com http://192.168.1.100:8065" +``` + +**Using System Console:** +1. Go to **System Console > Environment > Web Server** +2. Set **Allow cross-origin requests from** to include: + - Your SiteURL (e.g., `https://your-domain.com`) + - If using calls-offloader in a private network: Also include Mattermost's private IP with port 8065 (e.g., `http://192.168.1.100:8065`) + +**Using config.json:** +```json +{ + "ServiceSettings": { + "AllowCorsFrom": "https://your-domain.com http://192.168.1.100:8065" + } +} +``` + +```{important} +This CORS configuration is specifically required for RTCD deployments and is not needed for integrated mode deployments. Multiple origins should be separated by spaces. +``` + ### STUN/TURN Configuration For clients behind strict firewalls, you may need to configure STUN/TURN servers. In the RTCD configuration file, reference your STUN/TURN servers as follows: diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index 4824e8b1a2b..3c533e63311 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -316,6 +316,43 @@ If you suspect network bandwidth issues: For troubleshooting calls-offloader service issues including recording and transcription problems, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.html#troubleshooting) guide. +### Calls-Offloader Docker Debugging + +If you're running calls-offloader in Docker, use these commands for debugging: + +#### Monitor Live Logs + +To view real-time logs from calls-offloader containers: + +```bash +# Find and follow logs from all calls-related containers +docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {} +``` + +This command finds all running containers with "calls" in the image name and follows their logs. + +#### View Completed Jobs + +To view completed calls-offloader job containers (useful for debugging failed jobs): + +```bash +# List all exited containers to see completed jobs +docker ps -a --filter "status=exited" +``` + +Look for containers with calls-offloader image names that have exited. You can then examine their logs: + +```bash +# View logs from a specific completed container +docker logs +``` + +#### Additional Docker Debugging Tips + +- **Check container resource usage**: `docker stats` to see if containers are hitting resource limits +- **Inspect container configuration**: `docker inspect ` for detailed container settings +- **Check container health**: `docker inspect | grep Health` if health checks are configured + ## Debugging Tools ### Prometheus Metrics Analysis From 6dfd85e729d10747bbba192e494e529673cdf3f9 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 13:44:24 -0400 Subject: [PATCH 21/60] Deleted incorrectly added TODO file --- PULL_REQUEST_REVIEW_ITEMS.md | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 PULL_REQUEST_REVIEW_ITEMS.md diff --git a/PULL_REQUEST_REVIEW_ITEMS.md b/PULL_REQUEST_REVIEW_ITEMS.md deleted file mode 100644 index 9e1bc015231..00000000000 --- a/PULL_REQUEST_REVIEW_ITEMS.md +++ /dev/null @@ -1,30 +0,0 @@ -# Mattermost Calls Documentation TODOs - -This file contains a list of documentation improvements identified for the Mattermost Calls feature. - -## Completed Items - -- ✅ Update `calls-rtcd-setup.rst` with new version endpoint information -- ✅ Update `calls-troubleshooting.rst` ICE configuration section with correct parameter name -- ✅ Add client and RTCD log examples to ICE configuration issues -- ✅ Remove 'Why Use RTCD' section from calls-rtcd-setup.rst - -## High Priority Items - -- Re-order RTCD setup recommendations to prioritize "Bare Metal/VM", then "Docker", then "Kubernetes". I'll share my example systemd unit file and configuration. -- Create documentation for the calls-offloader service used for Calls Recording and Transcription -- Expand CORS documentation or document that `AllowCORSFrom` needs to be set to the SiteURL -- Add call-out/special note that the Calls metrics scraping has issues with `labels` setup in `prometheus.yml` and that the Calls dashboard expects : format, with an example. -- Document a common flow for each piece of the setup: Calls plugin curl/test/telemetry, RTCD curl/test/telemetry, calls-offloader curl/test/telemetry -- Document troubleshooting steps for the error "failed to create recording job: max concurrent jobs reached". - -## Medium Priority Items - -- Document the command `curl http://localhost:9090/api/v1/label/__name__/values | jq '.' | grep rtcd` as a troubleshooting tool in `calls-metrics-monitoring.rst` -- Document that Node Exporter service needs to be bound to the right address -- Document how to check Prometheus Scrape targets using the 'Targets' menu option for status -- Document this command for debugging calls-offloader: `docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {}` -- Document the command `docker ps -a --filter "status=exited"` to view completed calls-offloader job containers -- Improve formatting for Network Requirements table to avoid small side-scrolling view -- Document experimental screen sharing audio feature with limitations and how to enable with `/call experimental on` slash command -- Provide documentation on what settings changes require what service/plugin restarts From 0235ab0b4f5e7d6a30df88023424838e43935424 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 16:12:39 -0400 Subject: [PATCH 22/60] Adapting the nav structure Mixing of rst and markdown caused issues with the LHS navigation --- source/configure/calls-deployment.md | 10 ---------- source/configure/calls-overview.rst | 16 ++++++++++++++++ source/deploy/server/preparations.rst | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 source/configure/calls-overview.rst diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index bd54c0911e7..f5bdea37b62 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -6,16 +6,6 @@ This document provides an overview of Mattermost Calls deployment options for self-hosted environments, including [air-gapped environments](https://docs.mattermost.com/configure/calls-deployment.html#air-gapped-deployments), ensuring private communication without reliance on public internet connectivity with flexible configuration options for complex network requirements. -```{toctree} -:maxdepth: 1 -:hidden: - -calls-rtcd-setup.md -calls-offloader-setup.md -calls-metrics-monitoring.md -calls-kubernetes.md -calls-troubleshooting.md -``` ## Quick Links diff --git a/source/configure/calls-overview.rst b/source/configure/calls-overview.rst new file mode 100644 index 00000000000..8adcf1c79ad --- /dev/null +++ b/source/configure/calls-overview.rst @@ -0,0 +1,16 @@ +Mattermost Calls +================ + +.. include:: ../_static/badges/allplans-cloud-selfhosted.rst + :start-after: :nosearch: + +Mattermost Calls provides integrated audio calling and screen sharing capabilities within Mattermost channels. This section covers deployment, configuration, and management of Mattermost Calls. + +**Calls Documentation:** + +* :doc:`Calls Deployment and Configuration ` - Main deployment overview and architecture guide for Mattermost Calls +* :doc:`RTCD Setup and Configuration ` - Real-time communication daemon setup for enterprise deployments +* :doc:`Calls Offloader Setup and Configuration ` - Configure call recording and transcription services +* :doc:`Calls Metrics and Monitoring ` - Performance monitoring with Prometheus and Grafana +* :doc:`Calls Deployment on Kubernetes ` - Kubernetes deployment guide for scalable Calls infrastructure +* :doc:`Calls Troubleshooting ` - Comprehensive troubleshooting guide for common issues \ No newline at end of file diff --git a/source/deploy/server/preparations.rst b/source/deploy/server/preparations.rst index 7a0e8c10661..d693905ae12 100644 --- a/source/deploy/server/preparations.rst +++ b/source/deploy/server/preparations.rst @@ -10,7 +10,7 @@ This guide outlines the key preparation steps required before installing the Mat Review software and hardware requirements Set up an NGINX proxy - Configure Mattermost Calls + Configure Mattermost Calls Set up TLS Use an image proxy From 732e0f72fa5bdd97df65e53445ae58dd687b6c93 Mon Sep 17 00:00:00 2001 From: "Carrie Warner (Mattermost)" <74422101+cwarnermm@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:45:50 -0400 Subject: [PATCH 23/60] Fixed nav structure, moved Ent badge, applied build fixes --- .../badges}/calls-rtcd-ent-only.md | 0 source/collaborate/make-calls.rst | 2 +- source/configure/calls-deployment.md | 3 +-- source/configure/calls-kubernetes.md | 2 +- source/configure/calls-overview.rst | 23 ++++++++++++++----- source/configure/calls-rtcd-setup.md | 9 +------- 6 files changed, 21 insertions(+), 18 deletions(-) rename source/{configure => _static/badges}/calls-rtcd-ent-only.md (100%) diff --git a/source/configure/calls-rtcd-ent-only.md b/source/_static/badges/calls-rtcd-ent-only.md similarity index 100% rename from source/configure/calls-rtcd-ent-only.md rename to source/_static/badges/calls-rtcd-ent-only.md diff --git a/source/collaborate/make-calls.rst b/source/collaborate/make-calls.rst index fd942c06983..2441fbc97e8 100644 --- a/source/collaborate/make-calls.rst +++ b/source/collaborate/make-calls.rst @@ -10,7 +10,7 @@ Using a web browser, the desktop app, or the mobile app, you can `join a call <# - All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. - For group calls up to 50 concurrent users, Mattermost Enterprise, Professional, or Mattermost Cloud is required. - - Enterprise customers can also `record calls <#record-a-call>`__, enable :ref:`live text captions ` during calls, and `transcribe recorded calls <#transcribe-recorded-calls>`__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the :doc:`dedicated RTCD service `. + - Enterprise customers can also `record calls <#record-a-call>`__, enable :ref:`live text captions ` during calls, and `transcribe recorded calls <#transcribe-recorded-calls>`__. We recommend that Enterprise self-hosted customers looking for group calls beyond 50 concurrent users consider using the :doc:`dedicated RTCD service `. - Mattermost Cloud users can start calling right out of the box. For Mattermost self-hosted deployments, System admins need to enable and configure the plugin :ref:`using the System Console `. .. include:: ../_static/badges/academy-calls.rst diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index f5bdea37b62..888f925e5a1 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -1,5 +1,4 @@ -# Calls Deployment Overview - +# Deploy Mattermost Calls ```{include} ../_static/badges/allplans-cloud-selfhosted.md ``` diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md index 627bff23982..92d1d924e0a 100644 --- a/source/configure/calls-kubernetes.md +++ b/source/configure/calls-kubernetes.md @@ -1,4 +1,4 @@ -# Calls deployment on Kubernetes +# Deploy Calls Kubernetes ```{include} ../_static/badges/allplans-cloud-selfhosted.md ``` diff --git a/source/configure/calls-overview.rst b/source/configure/calls-overview.rst index 8adcf1c79ad..5ba7f5fc8db 100644 --- a/source/configure/calls-overview.rst +++ b/source/configure/calls-overview.rst @@ -6,11 +6,22 @@ Mattermost Calls Mattermost Calls provides integrated audio calling and screen sharing capabilities within Mattermost channels. This section covers deployment, configuration, and management of Mattermost Calls. +.. toctree:: + :maxdepth: 1 + :hidden: + + Deploy Mattermost Calls + RTCD Setup and Configuration + Calls Offloader Setup and Configuration + Calls Metrics and Monitoring + Deploy Calls on Kubernetes + Calls Troubleshooting + **Calls Documentation:** -* :doc:`Calls Deployment and Configuration ` - Main deployment overview and architecture guide for Mattermost Calls -* :doc:`RTCD Setup and Configuration ` - Real-time communication daemon setup for enterprise deployments -* :doc:`Calls Offloader Setup and Configuration ` - Configure call recording and transcription services -* :doc:`Calls Metrics and Monitoring ` - Performance monitoring with Prometheus and Grafana -* :doc:`Calls Deployment on Kubernetes ` - Kubernetes deployment guide for scalable Calls infrastructure -* :doc:`Calls Troubleshooting ` - Comprehensive troubleshooting guide for common issues \ No newline at end of file +* :doc:`Calls Deployment and Configuration ` - Main deployment overview and architecture guide for Mattermost Calls +* :doc:`RTCD Setup and Configuration ` - Real-time communication daemon setup for enterprise deployments +* :doc:`Calls Offloader Setup and Configuration ` - Configure call recording and transcription services +* :doc:`Calls Metrics and Monitoring ` - Performance monitoring with Prometheus and Grafana +* :doc:`Calls Deployment on Kubernetes ` - Kubernetes deployment guide for scalable Calls infrastructure +* :doc:`Calls Troubleshooting ` - Comprehensive troubleshooting guide for common issues \ No newline at end of file diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index d63ed4a94a4..6f7fef5d46e 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -1,17 +1,10 @@ # RTCD Setup and Configuration -```{include} ../_static/badges/ent-only.md +```{include} ../_static/badges/calls-rtcd-ent-only.md ``` This guide provides detailed instructions for setting up, configuring, and validating a Mattermost Calls deployment using the dedicated RTCD service. -- [Prerequisites](#prerequisites) -- [Installation and deployment](#installation-and-deployment) -- [Configuration](#configuration) -- [Validation and testing](#validation-and-testing) -- [Horizontal scaling](#horizontal-scaling) -- [Integration with Mattermost](#integration-with-mattermost) - ## Prerequisites Before deploying RTCD, ensure you have: From 5112c11740e5efcfbdec3f8aeefc8fa52f04427c Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 11 Jun 2025 16:40:54 -0400 Subject: [PATCH 24/60] Fixing navigation breaks From MD to RST to MD transition --- source/configure/calls-deployment.md | 36 ++++----- source/configure/calls-kubernetes.md | 20 ++--- source/configure/calls-metrics-monitoring.md | 13 ++-- source/configure/calls-offloader-setup.md | 12 +-- source/configure/calls-overview.rst | 12 +-- source/configure/calls-rtcd-setup.md | 14 ++-- source/configure/calls-troubleshooting.md | 78 +++----------------- 7 files changed, 64 insertions(+), 121 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 888f925e5a1..8b7424c678b 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -1,4 +1,4 @@ -# Deploy Mattermost Calls +# Calls Deployment Overview ```{include} ../_static/badges/allplans-cloud-selfhosted.md ``` @@ -10,11 +10,11 @@ This document provides an overview of Mattermost Calls deployment options for se For detailed information on specific topics, please refer to these specialized guides: -- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Comprehensive guide for setting up the calls-offloader service for recording and transcription -- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques -- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability -- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments +- {doc}`RTCD Setup and Configuration `: Comprehensive guide for setting up the dedicated RTCD service +- {doc}`Calls Offloader Setup and Configuration `: Comprehensive guide for setting up the calls-offloader service for recording and transcription +- {doc}`Calls Troubleshooting `: Detailed troubleshooting steps and debugging techniques +- {doc}`Calls Metrics and Monitoring `: Guide to monitoring Calls performance using metrics and observability +- {doc}`Calls Deployment on Kubernetes `: Detailed guide for deploying Calls in Kubernetes environments ## About Mattermost Calls @@ -36,8 +36,8 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti ## Key Components - **Calls plugin**: The main plugin that enables calls functionality. Installed by default in Mattermost self-hosted deployments. -- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. See [RTCD Setup and Configuration](calls-rtcd-setup.html) for details. -- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. See [Calls Offloader Setup and Configuration](calls-offloader-setup.html) for setup and troubleshooting details. +- **RTCD service**: Optional dedicated service for offloading media processing (Enterprise feature). Typically deployed to dedicated servers or containers. See [RTCD Setup and Configuration](calls-rtcd-setup.md) for details. +- **calls-offloader**: Service for call recording and transcription (if enabled). Typically deployed to dedicated servers. See [Calls Offloader Setup and Configuration](calls-offloader-setup.md) for setup and troubleshooting details. ## Network Requirements @@ -134,7 +134,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti -For complete network requirements, see the [RTCD Setup and Configuration](calls-rtcd-setup.html) guide. +For complete network requirements, see the [RTCD Setup and Configuration](calls-rtcd-setup.md) guide. #### Air-gapped deployments @@ -189,7 +189,7 @@ Dedicated RTCD services handle media routing for high availability. ### Kubernetes Deployments -RTCD is the only officially supported approach for Kubernetes deployments. For detailed information on deploying Mattermost Calls in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the [Calls Deployment on Kubernetes](calls-kubernetes.html) guide. +RTCD is the only officially supported approach for Kubernetes deployments. For detailed information on deploying Mattermost Calls in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the [Calls Deployment on Kubernetes](calls-kubernetes.md) guide. ## When to Use RTCD @@ -201,7 +201,7 @@ The dedicated RTCD service (available with Enterprise license) is recommended fo - **Call stability**: Calls continue even if Mattermost server needs to restart - **Kubernetes deployments**: Required for officially supported Kubernetes deployments -For detailed RTCD setup instructions, see the [RTCD Setup and Configuration](calls-rtcd-setup.html) guide. +For detailed RTCD setup instructions, see the [RTCD Setup and Configuration](calls-rtcd-setup.md) guide. ## Call Recording and Transcription @@ -428,7 +428,7 @@ Calls performance primarily depends on: - **Network bandwidth**: Both incoming and outgoing traffic increases with participant count - **Active speakers**: Unmuted participants require significantly more resources -For detailed performance metrics, benchmarks, and monitoring guidance, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide. +For detailed performance metrics, benchmarks, and monitoring guidance, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide. ## Frequently Asked Questions @@ -461,7 +461,7 @@ Generally clients should connect directly to either Mattermost or, if deployed, The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). -See [RTCD Setup and Configuration](calls-rtcd-setup.html) for more details on the dedicated RTCD service. +See [RTCD Setup and Configuration](calls-rtcd-setup.md) for more details on the dedicated RTCD service. **Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public?** @@ -490,11 +490,11 @@ When [test mode](https://docs.mattermost.com/configure/plugins-configuration-set ## Troubleshooting -For comprehensive troubleshooting steps and debugging techniques, please refer to the [Calls Troubleshooting](calls-troubleshooting.html) guide. +For comprehensive troubleshooting steps and debugging techniques, please refer to the [Calls Troubleshooting](calls-troubleshooting.md) guide. ## Next Steps -1. For detailed setup instructions, see [RTCD Setup and Configuration](calls-rtcd-setup.html) -2. For monitoring guidance, see [Calls Metrics and Monitoring](calls-metrics-monitoring.html) -3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.html) -4. For Kubernetes deployments, see [Calls Deployment on Kubernetes](calls-kubernetes.html) +1. For detailed setup instructions, see [RTCD Setup and Configuration](calls-rtcd-setup.md) +2. For monitoring guidance, see [Calls Metrics and Monitoring](calls-metrics-monitoring.md) +3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.md) +4. For Kubernetes deployments, see [Calls Deployment on Kubernetes](calls-kubernetes.md) diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md index 92d1d924e0a..b45fda1461c 100644 --- a/source/configure/calls-kubernetes.md +++ b/source/configure/calls-kubernetes.md @@ -18,9 +18,9 @@ This diagram shows how the RTCD standalone service can be deployed in a Kubernet 1. Calls traffic is handled by dedicated RTCD pods 2. RTCD services are exposed through load balancers 3. Scaling is managed through Kubernetes deployment configurations -4. Call recording and transcription is handled by the calls-offloader service (see [Calls Offloader Setup and Configuration](calls-offloader-setup.html)) +4. Call recording and transcription is handled by the calls-offloader service (see [Calls Offloader Setup and Configuration](calls-offloader-setup.md)) -If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the [Kubernetes operator guide](/install/mattermost-kubernetes-operator.html). +If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the [Kubernetes operator guide](/install/mattermost-kubernetes-operator.md). ## Helm Chart Deployment @@ -140,7 +140,7 @@ We recommend deploying Prometheus and Grafana alongside your Calls deployment: 2. Import the official Mattermost Calls dashboard to Grafana 3. Set up alerts for CPU usage, connection failures, and error rates -For detailed information on metrics collection and monitoring, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide. +For detailed information on metrics collection and monitoring, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide. ## Troubleshooting @@ -151,13 +151,13 @@ For Kubernetes-specific troubleshooting: 3. Ensure UDP traffic is properly routed through your ingress/load balancer 4. Verify network policies allow required communication paths -For detailed troubleshooting steps, see the [Calls Troubleshooting](calls-troubleshooting.html) guide. +For detailed troubleshooting steps, see the [Calls Troubleshooting](calls-troubleshooting.md) guide. ## Other Calls Documentation -- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture -- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription -- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability -- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques -3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.html) \ No newline at end of file +- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.md): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability +- [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques +3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.md) \ No newline at end of file diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md index 43e6a7a735b..ed56b878717 100644 --- a/source/configure/calls-metrics-monitoring.md +++ b/source/configure/calls-metrics-monitoring.md @@ -8,9 +8,8 @@ This guide provides detailed information on monitoring Mattermost Calls performa - [Metrics overview](#metrics-overview) - [Setting up monitoring](#setting-up-monitoring) - [Key metrics to monitor](#key-metrics-to-monitor) -- [Grafana dashboards](#grafana-dashboards) -- [Alerting recommendations](#alerting-recommendations) - [Performance baselines](#performance-baselines) +- [Troubleshooting metrics collection](#troubleshooting-metrics-collection) ## Metrics Overview @@ -268,10 +267,10 @@ Each target should show status "UP" in green. If a target shows "DOWN" or errors ## Other Calls Documentation -- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture -- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription -- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments -- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.md): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription +- [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index 79dd55e3c0c..e32c2b32e32 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -356,13 +356,13 @@ tail -f /opt/calls-offloader/calls-offloader.log ### Performance Monitoring -Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.html) for details on setting up metrics and observability. +Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.md) for details on setting up metrics and observability. ## Other Calls Documentation -- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture -- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability -- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments -- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.md): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques - [calls-offloader performance documentation](https://github.com/mattermost/calls-offloader/blob/master/docs/performance.md): Detailed performance tuning and monitoring recommendations \ No newline at end of file diff --git a/source/configure/calls-overview.rst b/source/configure/calls-overview.rst index 5ba7f5fc8db..e73f5bd7015 100644 --- a/source/configure/calls-overview.rst +++ b/source/configure/calls-overview.rst @@ -19,9 +19,9 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti **Calls Documentation:** -* :doc:`Calls Deployment and Configuration ` - Main deployment overview and architecture guide for Mattermost Calls -* :doc:`RTCD Setup and Configuration ` - Real-time communication daemon setup for enterprise deployments -* :doc:`Calls Offloader Setup and Configuration ` - Configure call recording and transcription services -* :doc:`Calls Metrics and Monitoring ` - Performance monitoring with Prometheus and Grafana -* :doc:`Calls Deployment on Kubernetes ` - Kubernetes deployment guide for scalable Calls infrastructure -* :doc:`Calls Troubleshooting ` - Comprehensive troubleshooting guide for common issues \ No newline at end of file +* :doc:`Calls Deployment Overview ` - Main deployment overview and architecture guide for Mattermost Calls +* :doc:`RTCD Setup and Configuration ` - Real-time communication daemon setup for enterprise deployments +* :doc:`Calls Offloader Setup and Configuration ` - Configure call recording and transcription services +* :doc:`Calls Metrics and Monitoring ` - Performance monitoring with Prometheus and Grafana +* :doc:`Calls Deployment on Kubernetes ` - Kubernetes deployment guide for scalable Calls infrastructure +* :doc:`Calls Troubleshooting ` - Comprehensive troubleshooting guide for common issues diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index 6f7fef5d46e..1feb89e9423 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -348,7 +348,7 @@ After deploying RTCD, validate the installation: 4. **Monitor metrics**: - Refer to [Calls Metrics and Monitoring](calls-metrics-monitoring.html) for setting up Calls metrics and monitoring. + Refer to [Calls Metrics and Monitoring](calls-metrics-monitoring.md) for setting up Calls metrics and monitoring. ## Horizontal Scaling @@ -398,10 +398,10 @@ Once RTCD is properly set up and validated, configure Mattermost to use it: ## Other Calls Documentation -- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture -- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription -- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability -- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments -- [Calls Troubleshooting](calls-troubleshooting.html): Detailed troubleshooting steps and debugging techniques +- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture +- [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments +- [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques -For detailed Mattermost Calls configuration options, see the [Calls Plugin Configuration Settings](plugins-configuration-settings.html#calls) documentation. \ No newline at end of file +For detailed Mattermost Calls configuration options, see the [Calls Plugin Configuration Settings](plugins-configuration-settings.rst#calls) documentation. \ No newline at end of file diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index 3c533e63311..e2389ce0d77 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -9,8 +9,6 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa - [Connectivity troubleshooting](#connectivity-troubleshooting) - [Log analysis](#log-analysis) - [Performance issues](#performance-issues) -- [Debugging tools](#debugging-tools) -- [Advanced diagnostics](#advanced-diagnostics) ## Common Issues @@ -68,7 +66,7 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa 1. **Server resources**: - Check CPU usage on RTCD servers - high CPU can cause quality issues - - Refer to the [Calls Metrics and Monitoring](calls-metrics-monitoring.html) guide for detailed instructions on monitoring and optimizing performance + - Refer to the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide for detailed instructions on monitoring and optimizing performance - Monitor network bandwidth usage 2. **Network congestion**: @@ -242,7 +240,7 @@ If RTCD servers show high CPU usage: 1. **Check concurrent calls and participants**: - Access the Prometheus metrics endpoint to see active sessions - - Compare with the benchmark data in the documentation + - Compare with the benchmark data in the {doc}`Calls Metrics and Monitoring ` documentation's Performance Baselines section 2. **Profile CPU usage** (Linux): @@ -314,7 +312,7 @@ If you suspect network bandwidth issues: ## Recording and Transcription Issues -For troubleshooting calls-offloader service issues including recording and transcription problems, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.html#troubleshooting) guide. +For troubleshooting calls-offloader service issues including recording and transcription problems, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.md#troubleshooting) guide. ### Calls-Offloader Docker Debugging @@ -353,66 +351,13 @@ docker logs - **Inspect container configuration**: `docker inspect ` for detailed container settings - **Check container health**: `docker inspect | grep Health` if health checks are configured -## Debugging Tools - -### Prometheus Metrics Analysis +## Prometheus Metrics Analysis Use Prometheus metrics for real-time and historical performance data: -Import the official [Mattermost Calls dashboard](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) into Grafana for visualization. - -## Advanced Diagnostics - -### WebRTC Diagnostic Commands - -For detailed WebRTC diagnostics: - -1. **Test STUN server connectivity**: - - ```bash - # Using stun-client (you may need to install it) - stun-client stun.global.calls.mattermost.com - ``` - - This should return your public IP address if STUN is working correctly. - -2. **Verify TURN server**: - - ```bash - # Using turnutils_uclient (part of coturn) - turnutils_uclient -v -s your-turn-server -u username -p password - ``` - - This tests if your TURN server is correctly configured. - -3. **Test end-to-end latency**: - - Between client locations and RTCD server: - - ```bash - ping -c 10 your-rtcd-server - ``` - - Look for consistent, low latency (<100ms ideally for voice calls). - -### Client-Side Testing Tools - -Tools to help diagnose client-side issues: - -1. **WebRTC Troubleshooter**: - - Direct users to [WebRTC Troubleshooter](https://test.webrtc.org/) for browser capability testing. - -2. **Network Quality Tests**: - - Use [Speedtest](https://www.speedtest.net/) or similar to check internet connection quality. - -3. **Browser-Specific WebRTC Info**: - - - Chrome: chrome://webrtc-internals - - Firefox: about:webrtc +For detailed setup instructions on configuring Prometheus and Grafana for Calls monitoring, see the {doc}`Calls Metrics and Monitoring ` guide. -### When to Contact Support +## When to Contact Support Consider contacting Mattermost Support when: @@ -433,9 +378,8 @@ When contacting support, please include: ## Other Calls Documentation -- [Calls Overview](calls-deployment.html): Overview of deployment options and architecture -- [RTCD Setup and Configuration](calls-rtcd-setup.html): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Offloader Setup and Configuration](calls-offloader-setup.html): Setup guide for call recording and transcription -- [Calls Metrics and Monitoring](calls-metrics-monitoring.html): Guide to monitoring Calls performance using metrics and observability -- [Calls Deployment on Kubernetes](calls-kubernetes.html): Detailed guide for deploying Calls in Kubernetes environments -- Monitoring dashboards screenshots \ No newline at end of file +- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture +- [RTCD Setup and Configuration](calls-rtcd-setup.md): Comprehensive guide for setting up the dedicated RTCD service +- [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription +- [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability +- [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments \ No newline at end of file From c9ff6d238a6d46c3b4f84a6f47b58dcf4dd43df9 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Sat, 14 Jun 2025 17:56:17 -0400 Subject: [PATCH 25/60] Add air-gap Docker registry setup for Calls offloader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced calls documentation with comprehensive air-gapped deployment guidance: - Added Docker registry setup overview to calls-deployment.md - Added detailed air-gap configuration section to calls-offloader-setup.md - Includes setup scripts, manual configuration, verification, and troubleshooting - Addresses Docker image requirements for recording and transcription services 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- source/configure/calls-deployment.md | 24 +++ source/configure/calls-offloader-setup.md | 206 ++++++++++++++++++++++ 2 files changed, 230 insertions(+) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 8b7424c678b..24928674374 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -421,6 +421,30 @@ Mattermost Calls can function in air-gapped environments. Exposing Calls to the +- Users should connect from within the private/local network. This can be done on-premises, through a VPN, or via virtual machines. +- Configuring a STUN server is unnecessary, as all connections occur within the local network. +- The ICE Host Override configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. + +### Docker Registry Setup for Air-Gapped Environments + +When using the calls-offloader service for call recording and transcription in air-gapped environments, you need to set up a local Docker registry since the service creates Docker containers that normally pull images from Docker Hub. + +**Required Docker Images:** +- `mattermost/calls-offloader:v0.9.3` (or latest version) +- `mattermost/calls-transcriber:latest` +- `registry:2` (for the local Docker registry) + +**Setup Overview:** +1. **Preparation phase** (on internet-connected machine): Download and prepare Docker images +2. **Air-gap deployment phase**: Transfer and deploy the local registry with pre-loaded images + +**Key Configuration Changes:** +- Configure Docker daemon to allow insecure registries: `{"insecure-registries": ["localhost:5000"]}` +- Update calls-offloader configuration to use local registry: `image_registry = "localhost:5000/mattermost"` + +For detailed step-by-step instructions, including setup scripts, manual configuration, and troubleshooting, see the comprehensive air-gap setup guide in the [Calls Offloader Setup and Configuration](calls-offloader-setup.md#air-gapped-deployments) documentation. + +## Performance Considerations Calls performance primarily depends on: diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index e32c2b32e32..cb7d6ddb5f3 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -358,6 +358,212 @@ tail -f /opt/calls-offloader/calls-offloader.log Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.md) for details on setting up metrics and observability. +## Air-Gapped Deployments + +When deploying calls-offloader in air-gapped environments, you need to set up a local Docker registry since the service creates Docker containers that normally pull images from Docker Hub. + +### Overview + +The calls-offloader service creates Docker containers to handle: +- **Call Recording**: Creates containers to record audio/video from calls +- **Call Transcription**: Creates containers to transcribe recorded calls using speech-to-text + +These containers are typically pulled from the `mattermost` registry on Docker Hub, but in air-gapped networks, you need to: +1. Set up a local Docker registry +2. Pre-load the required Docker images +3. Configure the calls-offloader to use the local registry + +### Required Docker Images + +The following Docker images are needed for full calls functionality: + +- `mattermost/calls-offloader:v0.9.3` (or latest version) +- `mattermost/calls-transcriber:latest` +- `registry:2` (for the local Docker registry) + +### Setup Process + +#### Phase 1: Preparation (Internet-Connected Environment) + +Run this phase on a machine with internet access to download and prepare the Docker images. + +1. **Run the setup script**: + ```bash + chmod +x air-gap-docker-registry-setup.sh + sudo ./air-gap-docker-registry-setup.sh + ``` + +2. **What the script does**: + - Sets up a local Docker registry on port 5000 + - Downloads required Mattermost Docker images + - Pushes images to the local registry + - Configures Docker daemon for insecure registry access + - Creates deployment scripts for the air-gapped environment + +3. **Export the registry data**: + ```bash + # Create an archive of the registry data + sudo tar -czf docker-registry-data.tar.gz -C /opt/docker-registry/data . + + # Also backup the registry container image + docker save registry:2 | gzip > registry-image.tar.gz + ``` + +#### Phase 2: Air-Gap Deployment + +Transfer the following files to your air-gapped network: +- `docker-registry-data.tar.gz` +- `registry-image.tar.gz` +- `deploy-airgap-calls.sh` (created by setup script) + +1. **Load the registry container**: + ```bash + gunzip -c registry-image.tar.gz | docker load + ``` + +2. **Set up the registry data**: + ```bash + sudo mkdir -p /opt/docker-registry/data + sudo tar -xzf docker-registry-data.tar.gz -C /opt/docker-registry/data + ``` + +3. **Start the local registry**: + ```bash + docker run -d \ + --name local-registry \ + --restart=always \ + -p 5000:5000 \ + -v /opt/docker-registry/data:/var/lib/registry \ + registry:2 + ``` + +4. **Configure Docker and calls-offloader**: + ```bash + sudo /opt/deploy-airgap-calls.sh + ``` + +### Manual Configuration + +If you prefer to configure manually instead of using the scripts: + +#### 1. Docker Daemon Configuration + +Create or update `/etc/docker/daemon.json`: +```json +{ + "insecure-registries": ["localhost:5000"] +} +``` + +Restart Docker: +```bash +sudo systemctl restart docker +``` + +#### 2. Calls-Offloader Configuration + +Update `/opt/calls-offloader/calls-offloader.toml`: + +```toml +[jobs] +# Change this line: +image_registry = "mattermost" + +# To this: +image_registry = "localhost:5000/mattermost" +``` + +Restart the calls-offloader service: +```bash +sudo systemctl restart calls-offloader +``` + +### Verification + +#### Test Registry Access +```bash +# List available repositories +curl http://localhost:5000/v2/_catalog + +# Test pulling an image +docker pull localhost:5000/mattermost/calls-offloader:latest +``` + +#### Test Calls Functionality + +1. **Check calls-offloader logs**: + ```bash + sudo journalctl -u calls-offloader -f + ``` + +2. **Verify calls-offloader API**: + ```bash + curl http://localhost:4545/version + ``` + +3. **Test recording job creation** (requires proper Mattermost integration): + - Start a call in Mattermost + - Enable recording + - Check that Docker containers are created for recording jobs + +### Troubleshooting Air-Gap Deployments + +#### Common Issues + +1. **Registry not accessible**: + - Check that the registry container is running: `docker ps | grep registry` + - Verify Docker daemon configuration includes insecure registry + - Check firewall settings on port 5000 + +2. **Image pull failures**: + - Verify images are in the registry: `curl http://localhost:5000/v2/_catalog` + - Check Docker daemon logs: `sudo journalctl -u docker` + +3. **calls-offloader fails to create jobs**: + - Check calls-offloader logs: `sudo journalctl -u calls-offloader` + - Verify the `image_registry` configuration in calls-offloader.toml + - Ensure the calls-offloader service can reach the registry + +#### Log Locations + +- Setup script logs: `/tmp/air-gap-registry-setup.log` +- calls-offloader logs: `/opt/calls-offloader/calls-offloader.log` +- Docker daemon logs: `sudo journalctl -u docker` +- Registry container logs: `docker logs local-registry` + +#### Security Considerations + +1. **Insecure Registry**: The setup uses an insecure HTTP registry for simplicity. For production, consider: + - Setting up TLS certificates for the registry + - Implementing authentication + - Using proper firewall rules + +2. **Network Access**: Ensure the registry is only accessible within your private network + +3. **Image Verification**: Consider implementing image signing and verification processes + +#### Advanced Configuration + +**Using a Different Registry Host** + +If you want to run the registry on a different host: + +```bash +export REGISTRY_HOST="registry.internal.domain" +export REGISTRY_PORT="5000" +./air-gap-docker-registry-setup.sh +``` + +**Custom Image Versions** + +To use specific versions of the calls images: + +```bash +export CALLS_OFFLOADER_VERSION="v0.8.0" +export CALLS_TRANSCRIBER_VERSION="v1.2.0" +./air-gap-docker-registry-setup.sh +``` + ## Other Calls Documentation - [Calls Overview](calls-deployment.md): Overview of deployment options and architecture From 9d55df900993e4bb1d28a7d9c3b4f68a0ee1f176 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Sat, 14 Jun 2025 18:12:16 -0400 Subject: [PATCH 26/60] Replace script references with direct Docker commands in air-gap setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed references to non-existent setup scripts and replaced with: - Direct Docker commands for registry setup and image management - Manual configuration steps instead of script dependencies - Concrete examples for custom registry hosts and image versions Makes the air-gap setup more reliable and self-contained. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- source/configure/calls-offloader-setup.md | 70 ++++++++++++++++------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index cb7d6ddb5f3..a76ec1c148d 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -387,18 +387,34 @@ The following Docker images are needed for full calls functionality: Run this phase on a machine with internet access to download and prepare the Docker images. -1. **Run the setup script**: +1. **Set up a local Docker registry**: ```bash - chmod +x air-gap-docker-registry-setup.sh - sudo ./air-gap-docker-registry-setup.sh + # Create registry data directory + sudo mkdir -p /opt/docker-registry/data + + # Start a local Docker registry + docker run -d \ + --name local-registry \ + --restart=always \ + -p 5000:5000 \ + -v /opt/docker-registry/data:/var/lib/registry \ + registry:2 ``` -2. **What the script does**: - - Sets up a local Docker registry on port 5000 - - Downloads required Mattermost Docker images - - Pushes images to the local registry - - Configures Docker daemon for insecure registry access - - Creates deployment scripts for the air-gapped environment +2. **Download and push required images**: + ```bash + # Pull required images from Docker Hub + docker pull mattermost/calls-offloader:v0.9.3 + docker pull mattermost/calls-transcriber:latest + + # Tag images for local registry + docker tag mattermost/calls-offloader:v0.9.3 localhost:5000/mattermost/calls-offloader:v0.9.3 + docker tag mattermost/calls-transcriber:latest localhost:5000/mattermost/calls-transcriber:latest + + # Push images to local registry + docker push localhost:5000/mattermost/calls-offloader:v0.9.3 + docker push localhost:5000/mattermost/calls-transcriber:latest + ``` 3. **Export the registry data**: ```bash @@ -413,8 +429,7 @@ Run this phase on a machine with internet access to download and prepare the Doc Transfer the following files to your air-gapped network: - `docker-registry-data.tar.gz` -- `registry-image.tar.gz` -- `deploy-airgap-calls.sh` (created by setup script) +- `registry-image.tar.gz` 1. **Load the registry container**: ```bash @@ -437,14 +452,17 @@ Transfer the following files to your air-gapped network: registry:2 ``` -4. **Configure Docker and calls-offloader**: +4. **Configure Docker daemon for insecure registry access**: ```bash - sudo /opt/deploy-airgap-calls.sh + # Create or update Docker daemon configuration + sudo mkdir -p /etc/docker + echo '{"insecure-registries": ["localhost:5000"]}' | sudo tee /etc/docker/daemon.json + sudo systemctl restart docker ``` ### Manual Configuration -If you prefer to configure manually instead of using the scripts: +For reference, here are the individual configuration steps: #### 1. Docker Daemon Configuration @@ -546,22 +564,30 @@ docker pull localhost:5000/mattermost/calls-offloader:latest **Using a Different Registry Host** -If you want to run the registry on a different host: +If you want to run the registry on a different host, replace `localhost:5000` with your registry host in all commands: ```bash -export REGISTRY_HOST="registry.internal.domain" -export REGISTRY_PORT="5000" -./air-gap-docker-registry-setup.sh +# Example: using a dedicated registry server +REGISTRY_HOST="registry.internal.domain:5000" + +# Update Docker daemon configuration +echo "{\"insecure-registries\": [\"$REGISTRY_HOST\"]}" | sudo tee /etc/docker/daemon.json + +# Update calls-offloader configuration +sed -i "s|localhost:5000|$REGISTRY_HOST|g" /opt/calls-offloader/calls-offloader.toml ``` **Custom Image Versions** -To use specific versions of the calls images: +To use specific versions of the calls images, update the version tags in the docker commands: ```bash -export CALLS_OFFLOADER_VERSION="v0.8.0" -export CALLS_TRANSCRIBER_VERSION="v1.2.0" -./air-gap-docker-registry-setup.sh +# Example: using specific versions +OFFLOADER_VERSION="v0.8.0" +TRANSCRIBER_VERSION="v1.2.0" + +docker pull mattermost/calls-offloader:$OFFLOADER_VERSION +docker pull mattermost/calls-transcriber:$TRANSCRIBER_VERSION ``` ## Other Calls Documentation From ad56133a8c4064921ec9e12a07d0c8e28de91256 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Sun, 22 Jun 2025 09:34:17 -0400 Subject: [PATCH 27/60] Updates after testing the process to move images into Air-Gap w Day2 operations --- scripts/air-gap-docker-registry-setup.sh | 366 +++++++++++++++++++++ source/configure/calls-offloader-setup.md | 378 ++++++++++++++++++++-- 2 files changed, 726 insertions(+), 18 deletions(-) create mode 100755 scripts/air-gap-docker-registry-setup.sh diff --git a/scripts/air-gap-docker-registry-setup.sh b/scripts/air-gap-docker-registry-setup.sh new file mode 100755 index 00000000000..52553102863 --- /dev/null +++ b/scripts/air-gap-docker-registry-setup.sh @@ -0,0 +1,366 @@ +#!/bin/bash + +# Air-Gap Docker Registry Setup for Mattermost Calls Offloader +# This script sets up a local Docker registry and pre-loads required images +# for air-gapped network deployments +# +# Usage: ./air-gap-docker-registry-setup.sh +# Example: ./air-gap-docker-registry-setup.sh v0.8.5 v0.6.3 + +set -e + +# Function to display usage +usage() { + echo "Usage: $0 " + echo "" + echo "Arguments:" + echo " recorder-version Version of mattermost/calls-recorder image (e.g., v0.8.5)" + echo " transcriber-version Version of mattermost/calls-transcriber image (e.g., v0.6.3)" + echo "" + echo "Examples:" + echo " $0 v0.8.5 v0.6.3" + echo " $0 v0.9.0 v0.7.0" + echo "" + echo "To find the correct versions for your Calls plugin:" + echo "1. Check your Calls plugin version in System Console > Plugins > Plugin Management" + echo "2. Visit: https://github.com/mattermost/mattermost-plugin-calls/blob/v/plugin.json" + echo "3. Look for 'RecorderImage' and 'TranscriberImage' entries (near the bottom)" + echo "" + echo "Environment variables (optional):" + echo " REGISTRY_HOST Docker registry host (default: localhost)" + echo " REGISTRY_PORT Docker registry port (default: 5000)" + echo " REGISTRY_DATA_DIR Registry data directory (default: /opt/docker-registry/data)" + exit 1 +} + +# Check if required arguments are provided +if [ $# -ne 2 ]; then + echo "ERROR: Missing required arguments" + echo "" + usage +fi + +# Validate version format (should start with 'v' followed by semantic version) +validate_version() { + local version=$1 + local image_name=$2 + + if [[ ! $version =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Invalid version format for $image_name: $version" + echo "Expected format: vX.Y.Z (e.g., v0.8.5)" + exit 1 + fi +} + +# Parse and validate arguments +CALLS_RECORDER_VERSION="$1" +CALLS_TRANSCRIBER_VERSION="$2" + +validate_version "$CALLS_RECORDER_VERSION" "calls-recorder" +validate_version "$CALLS_TRANSCRIBER_VERSION" "calls-transcriber" + +# Configuration variables +REGISTRY_HOST="${REGISTRY_HOST:-localhost}" +REGISTRY_PORT="${REGISTRY_PORT:-5000}" +REGISTRY_DATA_DIR="${REGISTRY_DATA_DIR:-/opt/docker-registry/data}" +REGISTRY_CONFIG_DIR="${REGISTRY_CONFIG_DIR:-/opt/docker-registry/config}" + +LOG_FILE=/tmp/air-gap-registry-setup.log + +echo "Setting up Air-Gap Docker Registry for Mattermost Calls" | tee $LOG_FILE +echo "Recorder version: $CALLS_RECORDER_VERSION" | tee -a $LOG_FILE +echo "Transcriber version: $CALLS_TRANSCRIBER_VERSION" | tee -a $LOG_FILE + +# Function to check if running with internet access (for image pulling phase) +check_internet() { + if ! curl -s --connect-timeout 5 https://hub.docker.com > /dev/null 2>&1; then + echo "ERROR: This script requires internet access during the image preparation phase." | tee -a $LOG_FILE + echo "Please run this script on a machine with internet access first, then transfer the images." | tee -a $LOG_FILE + return 1 + fi +} + +# Function to setup local Docker registry +setup_registry() { + echo "Setting up local Docker registry..." | tee -a $LOG_FILE + + # Create directories + sudo mkdir -p $REGISTRY_DATA_DIR + sudo mkdir -p $REGISTRY_CONFIG_DIR + + # Create registry configuration + cat > /tmp/registry-config.yml << EOF +version: 0.1 +log: + level: info +storage: + filesystem: + rootdirectory: /var/lib/registry +http: + addr: 0.0.0.0:5000 + headers: + X-Content-Type-Options: [nosniff] +EOF + + sudo mv /tmp/registry-config.yml $REGISTRY_CONFIG_DIR/config.yml + + # Pull and run registry container + echo "Starting Docker registry container..." | tee -a $LOG_FILE + docker pull registry:2 >> $LOG_FILE 2>&1 + + # Stop existing registry if running + docker stop local-registry 2>/dev/null || true + docker rm local-registry 2>/dev/null || true + + # Start registry container + docker run -d \ + --name local-registry \ + --restart=always \ + -p $REGISTRY_PORT:5000 \ + -v $REGISTRY_DATA_DIR:/var/lib/registry \ + -v $REGISTRY_CONFIG_DIR/config.yml:/etc/docker/registry/config.yml \ + registry:2 >> $LOG_FILE 2>&1 + + # Wait for registry to be ready + echo "Waiting for registry to be ready..." | tee -a $LOG_FILE + sleep 10 + + # Test registry + if curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/ > /dev/null; then + echo "Local Docker registry is running at $REGISTRY_HOST:$REGISTRY_PORT" | tee -a $LOG_FILE + else + echo "ERROR: Failed to start local Docker registry" | tee -a $LOG_FILE + return 1 + fi +} + +# Function to download and push Mattermost images +setup_mattermost_images() { + echo "Downloading and pushing Mattermost Calls images..." | tee -a $LOG_FILE + + # Images to process + declare -A IMAGES=( + ["mattermost/calls-recorder"]="$CALLS_RECORDER_VERSION" + ["mattermost/calls-transcriber"]="$CALLS_TRANSCRIBER_VERSION" + ) + + for image in "${!IMAGES[@]}"; do + version="${IMAGES[$image]}" + echo "Processing $image:$version..." | tee -a $LOG_FILE + + # Pull from Docker Hub + echo " Pulling $image:$version from Docker Hub..." | tee -a $LOG_FILE + docker pull $image:$version >> $LOG_FILE 2>&1 + + # Tag for local registry + local_tag="$REGISTRY_HOST:$REGISTRY_PORT/$image:$version" + echo " Tagging as $local_tag..." | tee -a $LOG_FILE + docker tag $image:$version $local_tag >> $LOG_FILE 2>&1 + + # Push to local registry + echo " Pushing to local registry..." | tee -a $LOG_FILE + docker push $local_tag >> $LOG_FILE 2>&1 + + # Also tag as 'latest' for convenience + if [ "$version" != "latest" ]; then + latest_tag="$REGISTRY_HOST:$REGISTRY_PORT/$image:latest" + docker tag $image:$version $latest_tag >> $LOG_FILE 2>&1 + docker push $latest_tag >> $LOG_FILE 2>&1 + fi + + echo " Successfully pushed $image:$version to local registry" | tee -a $LOG_FILE + done + + # Create registry data archive for transfer + echo "Creating registry data archive..." | tee -a $LOG_FILE + sudo tar -czf docker-registry-data.tar.gz -C $REGISTRY_DATA_DIR . + + # Create registry container image archive + echo "Creating registry container image archive..." | tee -a $LOG_FILE + docker save -o registry-image.tar registry:2 + gzip registry-image.tar + + echo "Created archives for air-gap transfer:" | tee -a $LOG_FILE + echo " - docker-registry-data.tar.gz" | tee -a $LOG_FILE + echo " - registry-image.tar.gz" | tee -a $LOG_FILE +} + +# Function to configure calls-offloader for local registry +configure_calls_offloader() { + echo "Configuring calls-offloader for local registry..." | tee -a $LOG_FILE + + # Create a modified calls-offloader config + if [ -f "/opt/calls-offloader/calls-offloader.toml" ]; then + sudo cp /opt/calls-offloader/calls-offloader.toml /opt/calls-offloader/calls-offloader.toml.backup + + # Update image_registry setting + sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/calls-offloader.toml + + echo "Updated calls-offloader configuration to use local registry" | tee -a $LOG_FILE + echo "Backup created at /opt/calls-offloader/calls-offloader.toml.backup" | tee -a $LOG_FILE + else + echo "Warning: calls-offloader.toml not found. You'll need to manually configure:" | tee -a $LOG_FILE + echo " image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" | tee -a $LOG_FILE + fi +} + +# Function to create docker daemon configuration for insecure registry +configure_docker_daemon() { + echo "Configuring Docker daemon for insecure registry..." | tee -a $LOG_FILE + + # Create or update Docker daemon configuration + sudo mkdir -p /etc/docker + + # Check if daemon.json exists + if [ -f "/etc/docker/daemon.json" ]; then + sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.backup + echo "Backed up existing daemon.json" | tee -a $LOG_FILE + fi + + # Create new daemon.json with insecure registry configuration + cat > /tmp/daemon.json << EOF +{ + "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] +} +EOF + + sudo mv /tmp/daemon.json /etc/docker/daemon.json + + # Restart Docker daemon + echo "Restarting Docker daemon..." | tee -a $LOG_FILE + sudo systemctl restart docker >> $LOG_FILE 2>&1 + + # Wait for Docker to restart + sleep 10 + + echo "Docker daemon configured for insecure registry access" | tee -a $LOG_FILE +} + +# Function to verify setup +verify_setup() { + echo "Verifying air-gap setup..." | tee -a $LOG_FILE + + # Check registry is accessible + if curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/_catalog | grep -q repositories; then + echo "✓ Local registry is accessible" | tee -a $LOG_FILE + else + echo "✗ Local registry is not accessible" | tee -a $LOG_FILE + return 1 + fi + + # List available images + echo "Available images in local registry:" | tee -a $LOG_FILE + curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/_catalog | jq '.repositories[]' 2>/dev/null || echo "Could not list repositories (jq not available)" | tee -a $LOG_FILE + + # Test pulling from local registry + test_image="$REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-offloader:latest" + echo "Testing pull from local registry: $test_image" | tee -a $LOG_FILE + if docker pull $test_image >> $LOG_FILE 2>&1; then + echo "✓ Successfully pulled test image from local registry" | tee -a $LOG_FILE + else + echo "✗ Failed to pull test image from local registry" | tee -a $LOG_FILE + return 1 + fi +} + +# Function to create air-gap deployment script +create_airgap_deployment_script() { + echo "Creating air-gap deployment script..." | tee -a $LOG_FILE + + cat > /tmp/deploy-airgap-calls.sh << 'EOF' +#!/bin/bash + +# Air-Gap Calls Deployment Script +# Run this script on the air-gapped network after setting up the local registry + +REGISTRY_HOST="${REGISTRY_HOST:-localhost}" +REGISTRY_PORT="${REGISTRY_PORT:-5000}" + +echo "Deploying Mattermost Calls in air-gapped environment..." + +# Configure Docker for local registry +sudo mkdir -p /etc/docker +cat > /tmp/daemon.json << EOD +{ + "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] +} +EOD +sudo mv /tmp/daemon.json /etc/docker/daemon.json +sudo systemctl restart docker +sleep 10 + +# Update calls-offloader configuration +if [ -f "/opt/calls-offloader/calls-offloader.toml" ]; then + sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/calls-offloader.toml + + # Restart calls-offloader service + sudo systemctl restart calls-offloader + + echo "Calls-offloader configured for air-gap deployment" +else + echo "Warning: /opt/calls-offloader/calls-offloader.toml not found" + echo "Please manually configure image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" +fi + +echo "Air-gap deployment configuration complete" +echo "" +echo "IMPORTANT: Additional configuration required on Mattermost server:" +echo "On your Mattermost server, add this environment variable:" +echo " MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY=\"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" +echo "" +echo "Add it to /opt/mattermost/config/mattermost.environment and restart Mattermost:" +echo " echo 'MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY=\"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"' | sudo tee -a /opt/mattermost/config/mattermost.environment" +echo " sudo systemctl restart mattermost" +EOF + + chmod +x /tmp/deploy-airgap-calls.sh + mv /tmp/deploy-airgap-calls.sh ./deploy-airgap-calls.sh + + echo "Air-gap deployment script created at ./deploy-airgap-calls.sh" | tee -a $LOG_FILE +} + +# Main execution +main() { + echo "Starting air-gap Docker registry setup..." | tee -a $LOG_FILE + + # Check if we have internet access for image pulling + if ! check_internet; then + echo "Skipping image download phase - run this script with internet access first" | tee -a $LOG_FILE + else + # Setup local registry + setup_registry + + # Download and push images + setup_mattermost_images + fi + + # Configure Docker daemon + configure_docker_daemon + + # Configure calls-offloader + configure_calls_offloader + + # Verify setup + verify_setup + + # Create air-gap deployment script + create_airgap_deployment_script + + echo "" | tee -a $LOG_FILE + echo "=== Air-Gap Setup Complete ===" | tee -a $LOG_FILE + echo "Local registry running at: http://$REGISTRY_HOST:$REGISTRY_PORT" | tee -a $LOG_FILE + echo "Registry data stored at: $REGISTRY_DATA_DIR" | tee -a $LOG_FILE + echo "" | tee -a $LOG_FILE + echo "Next steps for air-gapped deployment:" | tee -a $LOG_FILE + echo "1. Transfer these files to your air-gapped network:" | tee -a $LOG_FILE + echo " - docker-registry-data.tar.gz" | tee -a $LOG_FILE + echo " - registry-image.tar.gz" | tee -a $LOG_FILE + echo " - deploy-airgap-calls.sh" | tee -a $LOG_FILE + echo "2. Run the local registry container in the air-gapped network" | tee -a $LOG_FILE + echo "3. Execute ./deploy-airgap-calls.sh on the air-gapped systems" | tee -a $LOG_FILE + echo "" | tee -a $LOG_FILE + echo "Log file: $LOG_FILE" | tee -a $LOG_FILE +} + +# Run main function +main "$@" \ No newline at end of file diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index a76ec1c148d..ea007010bbe 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -13,6 +13,7 @@ This guide provides detailed instructions for setting up, configuring, and valid - [Validation and testing](#validation-and-testing) - [Integration with Mattermost](#integration-with-mattermost) - [Troubleshooting](#troubleshooting) +- [Air-Gapped Deployments](#air-gapped-deployments) ## Overview @@ -377,16 +378,73 @@ These containers are typically pulled from the `mattermost` registry on Docker H The following Docker images are needed for full calls functionality: -- `mattermost/calls-offloader:v0.9.3` (or latest version) -- `mattermost/calls-transcriber:latest` +- `mattermost/calls-recorder:v0.8.5` (or version matching your plugin) +- `mattermost/calls-transcriber:v0.6.3` (or version matching your plugin) - `registry:2` (for the local Docker registry) +```{warning} +**Disk Space Requirements**: Ensure you have sufficient disk space before starting the setup process. The Docker images can be quite large: +- **calls-recorder image**: ~1.5-2GB +- **calls-transcriber image**: ~1.5-2GB +- **Registry container + data**: ~500MB + +**Total recommended free space**: At least 5GB to accommodate image downloads, local registry data, and archive creation. +``` + +#### Determining the Correct Image Versions + +**Important**: The exact versions of `calls-offloader` and `calls-transcriber` images must match what your installed Calls plugin expects. These versions are defined in the Calls plugin source code. + +To find the correct versions for your Calls plugin: + +1. **Determine your Calls plugin version**: + - In Mattermost, go to **System Console > Plugins > Plugin Management** + - Find the **Calls** plugin and note the version number (e.g., `v1.9.0`) + +2. **Look up the required image versions**: + - Visit the Calls plugin repository: https://github.com/mattermost/mattermost-plugin-calls + - Navigate to the tag or branch corresponding to your plugin version + - Open the `plugin.json` file + - Find the `RecorderImage` and `TranscriberImage` entries (around line 719-720) + + Example from plugin.json: + ```json + "RecorderImage": "mattermost/calls-recorder:v0.8.5", + "TranscriberImage": "mattermost/calls-transcriber:v0.6.3" + ``` + +3. **Use these exact versions** in your air-gap setup instead of `latest` tags + +**Direct link format**: For plugin version `v1.9.0`, the plugin.json would be at: +`https://github.com/mattermost/mattermost-plugin-calls/blob/v1.9.0/plugin.json` + +**Why this matters**: Using mismatched image versions can cause recording and transcription jobs to fail in air-gapped environments where the calls-offloader cannot automatically pull the correct images. + ### Setup Process #### Phase 1: Preparation (Internet-Connected Environment) Run this phase on a machine with internet access to download and prepare the Docker images. +**Automated Setup Script** + +For convenience, you can use the automated setup script: + +```bash +# Download the setup script +curl -O https://docs.mattermost.com/scripts/air-gap-docker-registry-setup.sh +chmod +x air-gap-docker-registry-setup.sh + +# Run the setup script +sudo ./air-gap-docker-registry-setup.sh +``` + +The script will automatically create the required archive files (`docker-registry-data.tar.gz` and `registry-image.tar.gz`) for transfer to your air-gapped environment. + +**Manual Setup Steps** + +If you prefer to set up manually or need to customize the process: + 1. **Set up a local Docker registry**: ```bash # Create registry data directory @@ -404,16 +462,16 @@ Run this phase on a machine with internet access to download and prepare the Doc 2. **Download and push required images**: ```bash # Pull required images from Docker Hub - docker pull mattermost/calls-offloader:v0.9.3 - docker pull mattermost/calls-transcriber:latest + docker pull mattermost/calls-recorder:v0.8.5 + docker pull mattermost/calls-transcriber:v0.6.3 # Tag images for local registry - docker tag mattermost/calls-offloader:v0.9.3 localhost:5000/mattermost/calls-offloader:v0.9.3 - docker tag mattermost/calls-transcriber:latest localhost:5000/mattermost/calls-transcriber:latest + docker tag mattermost/calls-recorder:v0.8.5 localhost:5000/mattermost/calls-recorder:v0.8.5 + docker tag mattermost/calls-transcriber:v0.6.3 localhost:5000/mattermost/calls-transcriber:v0.6.3 # Push images to local registry - docker push localhost:5000/mattermost/calls-offloader:v0.9.3 - docker push localhost:5000/mattermost/calls-transcriber:latest + docker push localhost:5000/mattermost/calls-recorder:v0.8.5 + docker push localhost:5000/mattermost/calls-transcriber:v0.6.3 ``` 3. **Export the registry data**: @@ -428,22 +486,31 @@ Run this phase on a machine with internet access to download and prepare the Doc #### Phase 2: Air-Gap Deployment Transfer the following files to your air-gapped network: -- `docker-registry-data.tar.gz` -- `registry-image.tar.gz` +- `docker-registry-data.tar.gz` (contains the registry data with pre-loaded images) +- `registry-image.tar.gz` (contains the Docker registry container image) +- `deploy-airgap-calls.sh` (deployment script created by the setup script) -1. **Load the registry container**: +**Complete Air-Gap Deployment Steps:** + +1. **Load the registry container image**: ```bash - gunzip -c registry-image.tar.gz | docker load + # Extract and load the registry container from the gzipped archive + gunzip registry-image.tar.gz + docker load -i registry-image.tar ``` -2. **Set up the registry data**: +2. **Set up the registry data directory**: ```bash + # Create the registry data directory sudo mkdir -p /opt/docker-registry/data + + # Extract the pre-loaded registry data sudo tar -xzf docker-registry-data.tar.gz -C /opt/docker-registry/data ``` -3. **Start the local registry**: +3. **Start the local registry with pre-loaded data**: ```bash + # Start the registry container with the extracted data docker run -d \ --name local-registry \ --restart=always \ @@ -460,6 +527,24 @@ Transfer the following files to your air-gapped network: sudo systemctl restart docker ``` +5. **Configure Mattermost server environment variable**: + ```bash + # Add the registry configuration to Mattermost environment + echo 'MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY="localhost:5000/mattermost"' | sudo tee -a /opt/mattermost/config/mattermost.environment + + # Restart Mattermost to apply the environment variable + sudo systemctl restart mattermost + ``` + +6. **Run the air-gap deployment script** (if using the automated setup): + ```bash + # Make the deployment script executable and run it + chmod +x deploy-airgap-calls.sh + sudo ./deploy-airgap-calls.sh + ``` + + Or configure calls-offloader manually (see Manual Configuration section below). + ### Manual Configuration For reference, here are the individual configuration steps: @@ -504,7 +589,7 @@ sudo systemctl restart calls-offloader curl http://localhost:5000/v2/_catalog # Test pulling an image -docker pull localhost:5000/mattermost/calls-offloader:latest +docker pull localhost:5000/mattermost/calls-recorder:latest ``` #### Test Calls Functionality @@ -542,6 +627,41 @@ docker pull localhost:5000/mattermost/calls-offloader:latest - Verify the `image_registry` configuration in calls-offloader.toml - Ensure the calls-offloader service can reach the registry +4. **"invalid Runner value: failed to validate runner" error**: + This error occurs when calls-offloader cannot validate Docker images from the local registry. + + **Common causes and solutions:** + - **Image not found**: Verify the exact image names and tags in your local registry: + ```bash + curl http://localhost:5000/v2/_catalog + curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list + curl http://localhost:5000/v2/mattermost/calls-transcriber/tags/list + ``` + + - **Registry configuration mismatch**: Ensure the `image_registry` setting in calls-offloader.toml matches your registry: + ```bash + grep image_registry /opt/calls-offloader/calls-offloader.toml + # Should show: image_registry = "localhost:5000/mattermost" + ``` + + - **Docker daemon can't reach registry**: Test that Docker can pull from the local registry: + ```bash + docker pull localhost:5000/mattermost/calls-recorder:latest + docker pull localhost:5000/mattermost/calls-transcriber:latest + ``` + + - **Image tag mismatch**: The calls-offloader may be looking for specific image tags. Check what the plugin expects vs what's in your registry: + ```bash + # Check what tags are available + curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list + # Compare with what your plugin.json specifies + ``` + + **Solution steps:** + 1. Restart calls-offloader after confirming registry configuration: `sudo systemctl restart calls-offloader` + 2. If the issue persists, check the exact image names and versions expected by your Calls plugin version + 3. Ensure both versioned tags (e.g., `v0.8.5`) and `latest` tags are present in your local registry + #### Log Locations - Setup script logs: `/tmp/air-gap-registry-setup.log` @@ -583,13 +703,235 @@ To use specific versions of the calls images, update the version tags in the doc ```bash # Example: using specific versions -OFFLOADER_VERSION="v0.8.0" -TRANSCRIBER_VERSION="v1.2.0" +RECORDER_VERSION="v0.8.5" +TRANSCRIBER_VERSION="v0.6.3" -docker pull mattermost/calls-offloader:$OFFLOADER_VERSION +docker pull mattermost/calls-recorder:$RECORDER_VERSION docker pull mattermost/calls-transcriber:$TRANSCRIBER_VERSION ``` +### Day 2 Operations: Upgrading Images in Air-Gap Environments + +When you upgrade your Mattermost Calls plugin to a newer version, you'll need to update the Docker images in your air-gapped registry to match the new plugin requirements. + +#### Upgrade Process Overview + +**When to upgrade**: After upgrading the Calls plugin in Mattermost, you must update the Docker images to match the versions expected by the new plugin version. + +**Two approaches available**: + +1. **Complete Rebuild Method**: Re-run the entire air-gap setup process with new image versions +2. **Incremental Update Method**: Transfer only the new images to minimize data transfer + +#### Method 1: Complete Rebuild (Recommended for Major Updates) + +This approach rebuilds the entire registry dataset with new image versions: + +1. **On internet-connected machine**, run the air-gap setup script with new versions: + ```bash + # Find new versions from your updated plugin.json + ./air-gap-docker-registry-setup.sh v0.8.5 v0.6.3 + ``` + +2. **Transfer new archives** to air-gapped environment: + - `docker-registry-data.tar.gz` (contains all images including new versions) + - `deploy-airgap-calls.sh` (updated deployment script) + +3. **In air-gapped environment**, replace the registry data: + ```bash + # Stop the existing registry + docker stop local-registry + docker rm local-registry + + # Backup existing data (optional) + sudo mv /opt/docker-registry/data /opt/docker-registry/data.backup + + # Extract new registry data + sudo mkdir -p /opt/docker-registry/data + sudo tar -xzf docker-registry-data.tar.gz -C /opt/docker-registry/data + + # Restart registry with new data + docker run -d \ + --name local-registry \ + --restart=always \ + -p 5000:5000 \ + -v /opt/docker-registry/data:/var/lib/registry \ + registry:2 + ``` + +#### Method 2: Incremental Update (Efficient for Minor Updates) + +This approach transfers only the new image versions without rebuilding the entire registry: + +**Phase 1: Preparation (Internet-Connected Environment)** + +1. **Download new images**: + ```bash + # Determine new versions from updated plugin.json + NEW_RECORDER_VERSION="v0.8.5" + NEW_TRANSCRIBER_VERSION="v0.6.3" + + # Pull new images + docker pull mattermost/calls-recorder:$NEW_RECORDER_VERSION + docker pull mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION + ``` + +2. **Create individual image archives**: + ```bash + # Save each image as a separate tar file + docker save mattermost/calls-recorder:$NEW_RECORDER_VERSION -o calls-recorder-$NEW_RECORDER_VERSION.tar + docker save mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION -o calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar + + # Compress the files for transfer + gzip calls-recorder-$NEW_RECORDER_VERSION.tar + gzip calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar + ``` + +3. **Create update script**: + ```bash + cat > update-air-gap-images.sh << 'EOF' + #!/bin/bash + + # Air-Gap Image Update Script + set -e + + NEW_RECORDER_VERSION="v0.8.5" + NEW_TRANSCRIBER_VERSION="v0.6.3" + REGISTRY_HOST="${REGISTRY_HOST:-localhost}" + REGISTRY_PORT="${REGISTRY_PORT:-5000}" + + echo "Updating air-gap registry with new image versions..." + echo "Recorder: $NEW_RECORDER_VERSION" + echo "Transcriber: $NEW_TRANSCRIBER_VERSION" + + # Load new images into Docker + echo "Loading new images..." + gunzip calls-recorder-$NEW_RECORDER_VERSION.tar.gz + gunzip calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar.gz + + docker load -i calls-recorder-$NEW_RECORDER_VERSION.tar + docker load -i calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar + + # Tag images for local registry + echo "Tagging images for local registry..." + docker tag mattermost/calls-recorder:$NEW_RECORDER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:$NEW_RECORDER_VERSION + docker tag mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION + + # Also update 'latest' tags + docker tag mattermost/calls-recorder:$NEW_RECORDER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest + docker tag mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:latest + + # Push to local registry + echo "Pushing images to local registry..." + docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:$NEW_RECORDER_VERSION + docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION + docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest + docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:latest + + echo "Image update complete!" + echo "" + echo "Verification commands:" + echo "curl http://$REGISTRY_HOST:$REGISTRY_PORT/v2/mattermost/calls-recorder/tags/list" + echo "curl http://$REGISTRY_HOST:$REGISTRY_PORT/v2/mattermost/calls-transcriber/tags/list" + + # Clean up temporary files + rm calls-recorder-$NEW_RECORDER_VERSION.tar + rm calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar + + echo "" + echo "Next steps:" + echo "1. Restart calls-offloader service: sudo systemctl restart calls-offloader" + echo "2. Test call recording functionality to verify the update" + EOF + + chmod +x update-air-gap-images.sh + ``` + +**Phase 2: Air-Gap Update** + +1. **Transfer files to air-gapped environment**: + - `calls-recorder-v0.8.5.tar.gz` + - `calls-transcriber-v0.6.3.tar.gz` + - `update-air-gap-images.sh` + +2. **Run the update script**: + ```bash + chmod +x update-air-gap-images.sh + sudo ./update-air-gap-images.sh + ``` + +3. **Restart calls-offloader**: + ```bash + sudo systemctl restart calls-offloader + ``` + +4. **Verify the update**: + ```bash + # Check available image tags + curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list + curl http://localhost:5000/v2/mattermost/calls-transcriber/tags/list + + # Test calls-offloader functionality + curl http://localhost:4545/version + ``` + +#### Advantages of Each Method + +**Complete Rebuild Method:** +- ✅ Ensures clean state with no leftover data +- ✅ Recommended for major version upgrades +- ✅ Simpler process (reuse existing automation) +- ❌ Larger data transfer requirements +- ❌ More downtime during registry replacement + +**Incremental Update Method:** +- ✅ Minimal data transfer (only new images) +- ✅ Faster deployment process +- ✅ Preserves existing registry data +- ✅ Less downtime (registry stays running) +- ❌ More complex process +- ❌ Potential for version conflicts if not managed carefully + +#### Choosing the Right Method + +**Use Complete Rebuild when:** +- Upgrading across major plugin versions (e.g., v1.8.x to v1.9.x) +- Registry has accumulated significant old/unused images +- You want to ensure a completely clean state +- Data transfer size is not a primary concern + +**Use Incremental Update when:** +- Applying minor version updates (e.g., v1.9.0 to v1.9.1) +- Bandwidth or transfer time is limited +- You need to minimize downtime +- The registry is working correctly and just needs new image versions + +#### Post-Update Verification + +After either upgrade method, perform these verification steps: + +1. **Test recording functionality**: + - Start a call in Mattermost + - Enable call recording + - Verify recording starts without errors + +2. **Check job container creation**: + ```bash + # Monitor for new job containers during recording + docker ps --format "{{.ID}} {{.Image}}" | grep calls + ``` + +3. **Monitor calls-offloader logs**: + ```bash + sudo journalctl -u calls-offloader -f + ``` + +4. **Verify image versions**: + ```bash + # Check that the new image versions are being used + docker ps --format "{{.Image}}" | grep calls + ``` + ## Other Calls Documentation - [Calls Overview](calls-deployment.md): Overview of deployment options and architecture From 5c26d6223f88c00f73c25dde784210eac5c2347c Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Tue, 24 Jun 2025 10:13:57 -0400 Subject: [PATCH 28/60] Edits from reviews and rebase conflict resolution --- source/configure/calls-deployment.md | 244 +------------------ source/configure/calls-metrics-monitoring.md | 218 ++++++++++++++++- 2 files changed, 213 insertions(+), 249 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 24928674374..705eb144546 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -103,7 +103,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 UDP (incoming) -Mattermost clients (Web/Desktop/Mobile) +Mattermost clients (Web/Desktop/Mobile) and calls-offloader Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that UDP traffic is correctly routed both ways (from/to clients). @@ -111,7 +111,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 TCP (incoming) -Mattermost clients (Web/Desktop/Mobile) +Mattermost clients (Web/Desktop/Mobile) and calls-offloader Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that TCP traffic is correctly routed both ways (from/to clients). This can be used as a backup channel in case clients are unable to connect using UDP. It requires rtcd version >= v0.11 and Calls version >= v0.17. @@ -136,14 +136,6 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti For complete network requirements, see the [RTCD Setup and Configuration](calls-rtcd-setup.md) guide. -#### Air-gapped deployments - -Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: - -- Users should connect from within the private/local network. This can be done on-premises, through a VPN, or via virtual machines. -- Configuring a STUN server is unnecessary, as all connections occur within the local network. -- The [ICE Host Override](https://docs.mattermost.com/configure/plugins-configuration-settings.html#ice-host-override) configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. - ## Limitations - All Mattermost customers can start, join, and participate in 1:1 audio calls with optional screen sharing. @@ -153,7 +145,7 @@ Mattermost Calls can function in air-gapped environments. Exposing Calls to the ## Configuration -For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in the [System Console](/configure/plugins-configuration-settings.html#calls). +For Mattermost self-hosted customers, the calls plugin is pre-packaged, installed, and enabled. Configuration to allow end-users to use it can be found in ``System Console > Plugins > Calls``. ## Deployment Architecture Options @@ -211,238 +203,16 @@ For call recording and transcription, you need to: 2. Configure the service URL in the System Console 3. Enable call recordings and/or transcriptions in the plugin settings +For detailed setup instructions, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.md) guide. + ## Air-Gapped Deployments Mattermost Calls can function in air-gapped environments. Exposing Calls to the public internet is only necessary when users need to connect from outside the local network, and no existing method supports that connection. In such setups: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CallsParticipants/callUnmuted/callScreen sharingCPU (avg)Memory (avg)Bandwidth (in/out)Instance type (RTCD)
110002no47%1.46GB1Mbps / 194Mbpsc7i.xlarge
18001yes64%1.43GB2.7Mbps / 1.36Gbpsc7i.xlarge
110001yes79%1.54GB2.9Mbps / 1.68Gbpsc7i.xlarge
101001yes74%1.56GB18.2Mbps / 1.68Gbpsc7i.xlarge
100102no49%1.46GB18.7Mbps / 175Mbpsc7i.xlarge
100101yes84%1.73GB171Mbps / 1.53Gbpsc7i.xlarge
110002no20%1.44GB1.4Mbps / 194Mbpsc7i.2xlarge
110002yes49%1.53GB3.6Mbps / 1.79Gbpsc7i.2xlarge
210001yes73%2.38GB5.7Mbps / 3.06Gbpsc7i.2xlarge
100102yes60%1.74GB181Mbps / 1.62Gbpsc7i.2xlarge
150101yes72%2.26GB257Mbps / 2.30Gbpsc7i.2xlarge
150102yes79%2.34GB271Mbps / 2.41Gbpsc7i.2xlarge
250102no58%2.66GB47Mbps / 439Mbpsc7i.2xlarge
100022no78%2.31GB178Mbps / 195Mbpsc7i.2xlarge
210002yes41%2.6GB7.23Mbps / 3.60Gbpsc7i.4xlarge
310002yes63%3.53GB10.9Mbps / 5.38Gbpsc7i.4xlarge
410002yes83%4.40GB14.5Mbps / 7.17Gbpsc7i.4xlarge
250102yes79%3.49GB431Mbps / 3.73Gbpsc7i.4xlarge
50022yes71%2.54GB896Mbps / 919Mbpsc7i.4xlarge
- Users should connect from within the private/local network. This can be done on-premises, through a VPN, or via virtual machines. - Configuring a STUN server is unnecessary, as all connections occur within the local network. -- The ICE Host Override configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. - -### Docker Registry Setup for Air-Gapped Environments - -When using the calls-offloader service for call recording and transcription in air-gapped environments, you need to set up a local Docker registry since the service creates Docker containers that normally pull images from Docker Hub. - -**Required Docker Images:** -- `mattermost/calls-offloader:v0.9.3` (or latest version) -- `mattermost/calls-transcriber:latest` -- `registry:2` (for the local Docker registry) - -**Setup Overview:** -1. **Preparation phase** (on internet-connected machine): Download and prepare Docker images -2. **Air-gap deployment phase**: Transfer and deploy the local registry with pre-loaded images - -**Key Configuration Changes:** -- Configure Docker daemon to allow insecure registries: `{"insecure-registries": ["localhost:5000"]}` -- Update calls-offloader configuration to use local registry: `image_registry = "localhost:5000/mattermost"` - -For detailed step-by-step instructions, including setup scripts, manual configuration, and troubleshooting, see the comprehensive air-gap setup guide in the [Calls Offloader Setup and Configuration](calls-offloader-setup.md#air-gapped-deployments) documentation. +- The [ICE Host Override](https://docs.mattermost.com/configure/plugins-configuration-settings.html#ice-host-override) configuration setting can be optionally set with a local IP address (e.g., 192.168.1.45), depending on the specific network configuration and topology. +- For call recording and transcription in air-gapped environments, see the [Air-Gapped Deployments](calls-offloader-setup.md#air-gapped-deployments) section in the Calls Offloader Setup documentation. ## Performance Considerations diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md index ed56b878717..fdb2bc6ff16 100644 --- a/source/configure/calls-metrics-monitoring.md +++ b/source/configure/calls-metrics-monitoring.md @@ -220,18 +220,212 @@ The following performance benchmarks provide baseline metrics for RTCD deploymen Below are the detailed benchmarks based on internal performance testing: -| Calls | Users/call | Unmuted/call | Screen sharing | CPU (avg) | Memory (avg) | Bandwidth (in/out) | Instance (EC2) | -|-------|------------|--------------|----------------|-----------|--------------|--------------------|--------------| -| 100 | 8 | 2 | no | 60% | 0.5GB | 22Mbps / 125Mbps | c6i.xlarge | -| 100 | 8 | 2 | no | 30% | 0.5GB | 22Mbps / 125Mbps | c6i.2xlarge | -| 100 | 8 | 2 | yes | 86% | 0.7GB | 280Mbps / 2.2Gbps | c6i.2xlarge | -| 10 | 50 | 2 | no | 35% | 0.3GB | 5.25Mbps / 86Mbps | c6i.xlarge | -| 10 | 50 | 2 | no | 16% | 0.3GB | 5.25Mbps / 86Mbps | c6i.2xlarge | -| 10 | 50 | 2 | yes | 90% | 0.3GB | 32Mbps / 1.33Gbps | c6i.xlarge | -| 10 | 50 | 2 | yes | 45% | 0.3GB | 32Mbps / 1.33Gbps | c6i.2xlarge | -| 5 | 200 | 2 | no | 65% | 0.6GB | 8.2Mbps / 180Mbps | c6i.xlarge | -| 5 | 200 | 2 | no | 30% | 0.6GB | 8.2Mbps / 180Mbps | c6i.2xlarge | -| 5 | 200 | 2 | yes | 90% | 0.7GB | 31Mbps / 2.2Gbps | c6i.2xlarge | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CallsParticipants/callUnmuted/callScreen sharingCPU (avg)Memory (avg)Bandwidth (in/out)Instance type (RTCD)
110002no47%1.46GB1Mbps / 194Mbpsc7i.xlarge
18001yes64%1.43GB2.7Mbps / 1.36Gbpsc7i.xlarge
110001yes79%1.54GB2.9Mbps / 1.68Gbpsc7i.xlarge
101001yes74%1.56GB18.2Mbps / 1.68Gbpsc7i.xlarge
100102no49%1.46GB18.7Mbps / 175Mbpsc7i.xlarge
100101yes84%1.73GB171Mbps / 1.53Gbpsc7i.xlarge
110002no20%1.44GB1.4Mbps / 194Mbpsc7i.2xlarge
110002yes49%1.53GB3.6Mbps / 1.79Gbpsc7i.2xlarge
210001yes73%2.38GB5.7Mbps / 3.06Gbpsc7i.2xlarge
100102yes60%1.74GB181Mbps / 1.62Gbpsc7i.2xlarge
150101yes72%2.26GB257Mbps / 2.30Gbpsc7i.2xlarge
150102yes79%2.34GB271Mbps / 2.41Gbpsc7i.2xlarge
250102no58%2.66GB47Mbps / 439Mbpsc7i.2xlarge
100022no78%2.31GB178Mbps / 195Mbpsc7i.2xlarge
210002yes41%2.6GB7.23Mbps / 3.60Gbpsc7i.4xlarge
310002yes63%3.53GB10.9Mbps / 5.38Gbpsc7i.4xlarge
410002yes83%4.40GB14.5Mbps / 7.17Gbpsc7i.4xlarge
250102yes79%3.49GB431Mbps / 3.73Gbpsc7i.4xlarge
50022yes71%2.54GB896Mbps / 919Mbpsc7i.4xlarge
## Troubleshooting Metrics Collection From aa3202d18e294c3c2c1b45b59f5eeb47870acf54 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Tue, 24 Jun 2025 11:23:53 -0400 Subject: [PATCH 29/60] Minor tweaks and adjustments from review --- source/configure/calls-offloader-setup.md | 21 +--- source/configure/calls-rtcd-setup.md | 137 +++++++++++++++++----- 2 files changed, 109 insertions(+), 49 deletions(-) diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index ea007010bbe..7eb7652ff44 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -309,7 +309,7 @@ Check the following: - Verify the calls-offloader service is running: `sudo systemctl status calls-offloader` - Ensure network connectivity between Mattermost and calls-offloader -- Check Docker daemon is running and accessible by the user running `calls-offloader`: `docker ps` +- Check Docker daemon is running and accessible by the user running the Calls Offloader service (E.g., user: ``calls-offloader``) - Verify authentication configuration matches between services - Review service logs for specific error messages @@ -418,8 +418,6 @@ To find the correct versions for your Calls plugin: **Direct link format**: For plugin version `v1.9.0`, the plugin.json would be at: `https://github.com/mattermost/mattermost-plugin-calls/blob/v1.9.0/plugin.json` -**Why this matters**: Using mismatched image versions can cause recording and transcription jobs to fail in air-gapped environments where the calls-offloader cannot automatically pull the correct images. - ### Setup Process #### Phase 1: Preparation (Internet-Connected Environment) @@ -435,8 +433,8 @@ For convenience, you can use the automated setup script: curl -O https://docs.mattermost.com/scripts/air-gap-docker-registry-setup.sh chmod +x air-gap-docker-registry-setup.sh -# Run the setup script -sudo ./air-gap-docker-registry-setup.sh +# Run the setup script with the required image versions +sudo ./air-gap-docker-registry-setup.sh ``` The script will automatically create the required archive files (`docker-registry-data.tar.gz` and `registry-image.tar.gz`) for transfer to your air-gapped environment. @@ -650,7 +648,7 @@ docker pull localhost:5000/mattermost/calls-recorder:latest docker pull localhost:5000/mattermost/calls-transcriber:latest ``` - - **Image tag mismatch**: The calls-offloader may be looking for specific image tags. Check what the plugin expects vs what's in your registry: + - **Image tag mismatch**: The calls-offloader will be looking for specific image tags. Check what the plugin expects vs what's in your registry: ```bash # Check what tags are available curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list @@ -669,17 +667,6 @@ docker pull localhost:5000/mattermost/calls-recorder:latest - Docker daemon logs: `sudo journalctl -u docker` - Registry container logs: `docker logs local-registry` -#### Security Considerations - -1. **Insecure Registry**: The setup uses an insecure HTTP registry for simplicity. For production, consider: - - Setting up TLS certificates for the registry - - Implementing authentication - - Using proper firewall rules - -2. **Network Access**: Ensure the registry is only accessible within your private network - -3. **Image Verification**: Consider implementing image signing and verification processes - #### Advanced Configuration **Using a Different Registry Host** diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index 1feb89e9423..89571355371 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -16,13 +16,88 @@ Before deploying RTCD, ensure you have: The following network connectivity is required: -| Service | Ports | Protocols | Source | Target | -|-------------------|--------|-----------------|-------------------------|------------------------| -| Calls plugin API | 80,443 | TCP (incoming) | Mattermost clients | Mattermost server | -| RTC media | 8443 | UDP (incoming) | Mattermost clients | Mattermost or RTCD | -| RTC media | 8443 | TCP (incoming) | Mattermost clients | Mattermost or RTCD | -| RTCD API | 8045 | TCP (incoming) | Mattermost server | RTCD service | -| STUN | 3478 | UDP (outgoing) | Mattermost or RTCD | STUN servers | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ServicePortsProtocolsSourceTargetPurpose
API (Calls plugin)80,443TCP (incoming)Mattermost clients (web/desktop/mobile)Mattermost instance (Calls plugin)To allow for HTTP and WebSocket connectivity from clients to Calls plugin. This API is exposed on the same connection as Mattermost, so there's likely no need to change anything.
RTC (Calls plugin or rtcd)8443UDP (incoming)Mattermost clients (Web/Desktop/Mobile) and calls-offloaderMattermost instance or rtcd serviceTo allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that UDP traffic is correctly routed both ways (from/to clients).
RTC (Calls plugin or rtcd)8443TCP (incoming)Mattermost clients (Web/Desktop/Mobile) and calls-offloaderMattermost instance or rtcd serviceTo allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that TCP traffic is correctly routed both ways (from/to clients). This can be used as a backup channel in case clients are unable to connect using UDP. It requires rtcd version >= v0.11 and Calls version >= v0.17.
API (rtcd)8045TCP (incoming)Mattermost instance(s) (Calls plugin)rtcd serviceTo allow for HTTP/WebSocket connectivity from Calls plugin to rtcd service. Can be expose internally as the service only needs to be reachable by the instance(s) running the Mattermost server.
STUN (Calls plugin or rtcd)3478UDP (outgoing)Mattermost Instance(s) (Calls plugin) or rtcd serviceConfigured STUN servers(Optional) To allow for either Calls plugin or rtcd service to discover their instance public IP. Only needed if configuring STUN/TURN servers. This requirement does not apply when manually setting an IP or hostname through the ICE Host Override config option.
## Installation and Deployment @@ -30,7 +105,7 @@ There are multiple ways to deploy RTCD, depending on your environment. We recomm ### Bare Metal or VM Deployment (Recommended) -This is the recommended deployment method for production environments as it provides the best performance and operational control. +This is the recommended deployment method for non-Kubernetes production environments as it provides the best performance and operational control. For Kubernetes deployments, see the [Calls Deployment on Kubernetes](calls-kubernetes.md) guide. 1. Download the latest release from the [RTCD GitHub repository](https://github.com/mattermost/rtcd/releases) @@ -69,18 +144,22 @@ This is the recommended deployment method for production environments as it prov file_level = "INFO" file_location = "/opt/rtcd/rtcd.log" enable_color = true + ``` + +3. Create a dedicated user for the RTCD service: - [mattermost] - host = "http://YOUR_MATTERMOST_SERVER:8065" + ```bash + sudo useradd --system --no-create-home --shell /bin/false mattermost ``` -3. Create the data directory: +4. Create the data directory and set ownership: ```bash sudo mkdir -p /opt/rtcd/data/db + sudo chown -R mattermost:mattermost /opt/rtcd ``` -4. Create a systemd service file (`/etc/systemd/system/rtcd.service`): +5. Create a systemd service file (`/etc/systemd/system/rtcd.service`): ```ini [Unit] @@ -89,7 +168,8 @@ This is the recommended deployment method for production environments as it prov [Service] Type=simple - User=root + User=mattermost + Group=mattermost ExecStart=/opt/rtcd/rtcd --config /opt/rtcd/rtcd.toml Restart=always RestartSec=10 @@ -121,7 +201,7 @@ Docker deployment is suitable for development, testing, or containerized product ```bash docker run -d --name rtcd \ - -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_LOGGER_ENABLEFILE=true" \ -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ -p 8443:8443/udp \ -p 8443:8443/tcp \ @@ -133,7 +213,7 @@ Docker deployment is suitable for development, testing, or containerized product ```bash docker run -d --name rtcd \ - -e "RTCD_LOGGER_ENABLEFILE=false" \ + -e "RTCD_LOGGER_ENABLEFILE=true" \ -e "RTCD_LOGGER_CONSOLELEVEL=DEBUG" \ -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ -p 8443:8443/udp \ @@ -188,18 +268,16 @@ For Kubernetes deployments, use the official Helm chart: ### RTCD Configuration File -The RTCD service uses a TOML configuration file. Here's a comprehensive example with commonly used settings: +The RTCD service uses a TOML configuration file. Here's an example with commonly used settings: ```toml [api] # The address and port to which the HTTP API server will listen http.listen_address = ":8045" # Security settings for authentication -security.allow_self_registration = false +security.allow_self_registration = true security.enable_admin = true security.admin_secret_key = "YOUR_API_KEY" -# Configure allowed origins for CORS -security.allowed_origins = ["https://mattermost.example.com"] [rtc] # The UDP address and port for media traffic @@ -209,7 +287,7 @@ ice_port_udp = 8443 ice_address_tcp = "" ice_port_tcp = 8443 # Public hostname or IP that clients will use to connect -ice_host_override = "rtcd.example.com" +ice_host_override = "RTCD_SERVER_PUBLIC_IP" [logger] # Logging configuration @@ -218,13 +296,8 @@ console_json = false console_level = "INFO" enable_file = true file_json = true -file_level = "DEBUG" -file_location = "rtcd.log" - -[metrics] -# Prometheus metrics configuration -enable_prom = true -prom_port = 9090 +file_level = "INFO" +file_location = "/opt/rtcd/rtcd.log" ``` Key Configuration Options: @@ -235,7 +308,6 @@ Key Configuration Options: - **rtc.ice_address_tcp**: The TCP address for fallback media traffic - **rtc.ice_port_tcp**: The TCP port for fallback media traffic - **rtc.ice_host_override**: The public hostname or IP address clients will use to connect to RTCD -- **api.security.allowed_origins**: List of allowed origins for CORS - **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD ### Required Mattermost Server Configuration @@ -281,10 +353,11 @@ For clients behind strict firewalls, you may need to configure STUN/TURN servers ```toml [rtc] # STUN/TURN server configuration -ice_servers = [ - { urls = ["stun:stun.example.com:3478"] }, - { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } -] + ice_servers = [ + { urls = ["stun:stun.global.calls.mattermost.com:3478"] } + # { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } + ] + ``` We recommend using [coturn](https://github.com/coturn/coturn) for your TURN server implementation. From 4048a349c2055dc419357de75df33af7255e8d7c Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 27 Jun 2025 08:35:01 -0400 Subject: [PATCH 30/60] Expanding direction for installing RTCD binary --- source/configure/calls-rtcd-setup.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index 89571355371..6fece97e085 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -107,9 +107,28 @@ There are multiple ways to deploy RTCD, depending on your environment. We recomm This is the recommended deployment method for non-Kubernetes production environments as it provides the best performance and operational control. For Kubernetes deployments, see the [Calls Deployment on Kubernetes](calls-kubernetes.md) guide. -1. Download the latest release from the [RTCD GitHub repository](https://github.com/mattermost/rtcd/releases) +1. **Download and install the RTCD binary**: -2. Create a configuration file (`/opt/rtcd/rtcd.toml`) with the following settings: + Download the latest release from the [RTCD GitHub repository](https://github.com/mattermost/rtcd/releases): + + ```bash + # Create the RTCD directory structure + sudo mkdir -p /opt/rtcd + + # Download the latest RTCD binary (adjust URL for your architecture) + # For Linux x86_64: + wget https://github.com/mattermost/rtcd/releases/latest/download/rtcd-linux-amd64 + + # Make the binary executable and move it to the installation directory + chmod +x rtcd-linux-amd64 + sudo mv rtcd-linux-amd64 /opt/rtcd/rtcd + ``` + + ```{note} + Replace `rtcd-linux-amd64` with the appropriate binary for your system architecture (e.g., `rtcd-linux-arm64` for ARM64 systems). The binary should be placed at `/opt/rtcd/rtcd` as this is the expected location referenced in systemd service files and other documentation. + ``` + +2. **Create a configuration file** (`/opt/rtcd/rtcd.toml`) with the following settings: ```toml [api] From 90d72d9f981c3ced1f3599330de0c9265e8bd855 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Wed, 9 Jul 2025 11:07:09 -0400 Subject: [PATCH 31/60] Minor edits to config example and section header --- source/configure/calls-offloader-setup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index 7eb7652ff44..01218fcddcd 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -69,8 +69,8 @@ Call recordings can consume significant storage space: http.tls.cert_file = "" http.tls.cert_key = "" security.allow_self_registration = true - security.enable_admin = true - security.admin_secret_key = "changeme" + security.enable_admin = false + security.admin_secret_key = "" security.session_cache.expiration_minutes = 1440 [store] @@ -79,7 +79,7 @@ Call recordings can consume significant storage space: [jobs] api_type = "docker" max_concurrent_jobs = 2 - failed_jobs_retention_time = "7d" + failed_jobs_retention_time = "30d" image_registry = "mattermost" [logger] @@ -256,7 +256,7 @@ After deploying calls-offloader, validate the installation: - Network connectivity between Mattermost and calls-offloader servers - calls-offloader service binding configuration (ensure it's not bound to localhost only) -3. **Verify Docker integration** (if using docker api_type): +3. **Verify Docker service** (if using docker api_type): ```bash # Check that system user running calls-offloader can access Docker From 0f32682c02c97e1cff4279a78df23dc1f7be20b0 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Thu, 10 Jul 2025 10:12:11 -0400 Subject: [PATCH 32/60] Edits from @streamer45 review --- source/configure/calls-deployment.md | 33 ++++++++++++++++------- source/configure/calls-kubernetes.md | 18 +++++-------- source/configure/calls-troubleshooting.md | 11 ++++---- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 705eb144546..38308fc53cb 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -103,7 +103,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 UDP (incoming) -Mattermost clients (Web/Desktop/Mobile) and calls-offloader +Mattermost clients (Web/Desktop/Mobile) and ``calls-offloader`` spawned jobs (Recorder, Transcriber) Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that UDP traffic is correctly routed both ways (from/to clients). @@ -111,7 +111,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 TCP (incoming) -Mattermost clients (Web/Desktop/Mobile) and calls-offloader +Mattermost clients (Web/Desktop/Mobile) and ``calls-offloader`` spawned jobs (Recorder, Transcriber) Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that TCP traffic is correctly routed both ways (from/to clients). This can be used as a backup channel in case clients are unable to connect using UDP. It requires rtcd version >= v0.11 and Calls version >= v0.17. @@ -185,13 +185,25 @@ RTCD is the only officially supported approach for Kubernetes deployments. For d ## When to Use RTCD -The dedicated RTCD service (available with Enterprise license) is recommended for: +This section will help you understand when and why your organization would want to use the dedicated RTCD service. -- **Production environments**: Isolates call traffic from other Mattermost services -- **Performance optimization**: Dedicated service tuned for real-time media -- **Scalability**: Add RTCD instances as call volume grows -- **Call stability**: Calls continue even if Mattermost server needs to restart -- **Kubernetes deployments**: Required for officially supported Kubernetes deployments +```{note} +RTCD is a standalone service, which adds operational complexity, maintenance costs, and requires an Enterprise license. For those who are evaluating Calls, and for many small instances of Mattermost, the integrated SFU (the one included in the Calls plugin) may be sufficient initially. +``` + +The RTCD service is the recommended way to host Calls for the following reasons: + +- **Performance of the main Mattermost server(s)**: When the Calls plugin runs the SFU, calls traffic is added to the processing load of the server running the rest of your Mattermost services. If Calls traffic spikes, it can negatively affect the responsiveness of these services. Using an RTCD service isolates the calls traffic processing to those RTCD instances, and also reduces costs by minimizing CPU usage spikes. + +- **Performance, scalability, and stability of the Calls product**: If Calls traffic spikes, or more overall capacity is needed, RTCD servers can be added to balance the load. As an added benefit, if the Mattermost traffic spikes, or if a Mattermost instance needs to be restarted, those people in a current call will not be affected - current calls won't be dropped. + + Some caveats apply here. WebSocket events (for example: emoji reactions, hand raising, muting/unmuting) will not be transmitted while the main Mattermost server is down. But the call itself will continue while the main server restarts. + +- **Kubernetes deployments**: In a Kubernetes deployment, RTCD is strongly recommended; it is currently the only officially supported way to run Calls. + +- **Technical benefits**: The dedicated RTCD service has been optimized and tuned at the system/network level for real-time audio/video traffic, where latency is generally more important than throughput. + +In general, RTCD is the preferred solution for a performant and scalable deployment. With RTCD, the Mattermost server will be minimally impacted when hosting a high number of calls. For detailed RTCD setup instructions, see the [RTCD Setup and Configuration](calls-rtcd-setup.md) guide. @@ -219,15 +231,16 @@ Mattermost Calls can function in air-gapped environments. Exposing Calls to the Calls performance primarily depends on: - **CPU resources**: More participants require more processing power -- **Network bandwidth**: Both incoming and outgoing traffic increases with participant count +- **Network bandwidth**: Both incoming and outgoing traffic increases with participant count. Due to the nature of the service, the bottleneck is always going to be the outgoing/egress path - **Active speakers**: Unmuted participants require significantly more resources +- **Presenters**: Screen sharing participants require even more resources than active speakers For detailed performance metrics, benchmarks, and monitoring guidance, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide. ## Frequently Asked Questions **Is calls traffic encrypted?** -Yes, using WebRTC security standards (DTLS/SRTP). Traffic is encrypted in transit. +Media (audio/video) is encrypted using security standards as part of WebRTC. It's mainly a combination of DTLS and SRTP. It's not e2e encrypted in the sense that in the current design all media needs to go through Mattermost which acts as a media router and has complete access to it. Media is then encrypted back to the clients so it's secured during transit. In short: only the participant clients and the Mattermost server have access to unencrypted call data. **Are there any third-party services involved?** Only a Mattermost STUN server (`stun.global.calls.mattermost.com`) is used by default. This can be removed if you set the ICE Host Override configuration. diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md index b45fda1461c..a8519f1dfc8 100644 --- a/source/configure/calls-kubernetes.md +++ b/source/configure/calls-kubernetes.md @@ -59,19 +59,13 @@ For complete configuration options, see the [Calls-Offloader Helm chart document ### Network Configuration -For Kubernetes deployments, you need to ensure: +For Kubernetes deployments, you need to ensure specific connectivity paths: -1. UDP traffic is properly routed to RTCD pods (for media) -2. TCP traffic can reach both the Mattermost pods and RTCD pods -3. Load balancers are properly configured to handle UDP traffic -4. Network policies allow the required communications between services - -Recommended annotations for AWS environments: - -```yaml -service.beta.kubernetes.io/aws-load-balancer-backend-protocol: udp -service.beta.kubernetes.io/aws-load-balancer-type: nlb -``` +1. **Client to RTCD connectivity**: UDP traffic on port 8443 is properly routed from clients to RTCD pods (for media) +2. **Mattermost to RTCD API connectivity**: TCP traffic on port 8045 must have a clear connectivity path from Mattermost pods to RTCD pods (for API communication) +3. **Client to RTCD TCP fallback**: TCP traffic on port 8443 can reach RTCD pods (for fallback connections when UDP fails) +4. **Load balancer configuration**: Load balancers must be properly configured to handle UDP traffic routing to RTCD pods +5. **Network policies**: Network policies must allow the required communications between Mattermost and RTCD services ### Resource Requirements diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index e2389ce0d77..d964a24d086 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -320,14 +320,15 @@ If you're running calls-offloader in Docker, use these commands for debugging: #### Monitor Live Logs -To view real-time logs from calls-offloader containers: +For easier log management, configure calls-offloader to capture job logs directly in the calls-offloader log file by adding the following to your `calls-offloader.toml`: -```bash -# Find and follow logs from all calls-related containers -docker ps --format "{{.ID}} {{.Image}}" | grep "calls" | awk '{print $1}' | xargs -I {} docker logs -f {} +```toml +[jobs.docker] +# Whether to output job logs to the console. Default is false. +output_logs = true ``` -This command finds all running containers with "calls" in the image name and follows their logs. +With this configuration enabled, all job logs will be written to the main calls-offloader log file. #### View Completed Jobs From a3c879d21fcfcea41f9372b16eb35b9a06405b12 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 11 Jul 2025 09:40:01 -0400 Subject: [PATCH 33/60] Update source/configure/calls-troubleshooting.md Co-authored-by: Christopher Poile --- source/configure/calls-troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index d964a24d086..68702369ad6 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -328,7 +328,7 @@ For easier log management, configure calls-offloader to capture job logs directl output_logs = true ``` -With this configuration enabled, all job logs will be written to the main calls-offloader log file. +With this configuration enabled, all logs from recorder and transcriber docker containers will be written to the main calls-offloader log file. #### View Completed Jobs From 6093b67f4ca69832d5610568d3eb7b58c5a44a44 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 11 Jul 2025 09:40:19 -0400 Subject: [PATCH 34/60] Update source/configure/calls-troubleshooting.md Co-authored-by: Christopher Poile --- source/configure/calls-troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index 68702369ad6..f42420b1862 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -339,7 +339,7 @@ To view completed calls-offloader job containers (useful for debugging failed jo docker ps -a --filter "status=exited" ``` -Look for containers with calls-offloader image names that have exited. You can then examine their logs: +Look for containers with recorder and transcriber image names that have exited. You can then examine their logs: ```bash # View logs from a specific completed container From ff5b61d09d4712f284c8341b8ee6586687fec60b Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Fri, 11 Jul 2025 10:57:41 -0400 Subject: [PATCH 35/60] format update --- source/configure/calls-deployment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 38308fc53cb..dff70c3f03c 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -103,7 +103,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 UDP (incoming) -Mattermost clients (Web/Desktop/Mobile) and ``calls-offloader`` spawned jobs (Recorder, Transcriber) +Mattermost clients (Web/Desktop/Mobile) and jobs spawned by Calls Offloader (Recorder, Transcriber) Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that UDP traffic is correctly routed both ways (from/to clients). @@ -111,7 +111,7 @@ Mattermost Calls provides integrated audio calling and screen sharing capabiliti RTC (Calls plugin or rtcd) 8443 TCP (incoming) -Mattermost clients (Web/Desktop/Mobile) and ``calls-offloader`` spawned jobs (Recorder, Transcriber) +Mattermost clients (Web/Desktop/Mobile) and jobs spawned by Calls Offloader (Recorder, Transcriber) Mattermost instance or rtcd service To allow clients to establish connections that transport calls related media (e.g. audio, video). This should be open on any network component (e.g. NAT, firewalls) in between the instance running the plugin (or rtcd) and the clients joining calls so that TCP traffic is correctly routed both ways (from/to clients). This can be used as a backup channel in case clients are unable to connect using UDP. It requires rtcd version >= v0.11 and Calls version >= v0.17. From 8d9205652f6a561189e27820c9a23d47b0850300 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 11 Jul 2025 12:24:45 -0400 Subject: [PATCH 36/60] Update source/configure/calls-offloader-setup.md Co-authored-by: Christopher Poile --- source/configure/calls-offloader-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index 01218fcddcd..420c3fee48b 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -287,7 +287,7 @@ Once calls-offloader is properly set up and validated, configure Mattermost to u - Find the **Calls** plugin and click **Disable** - Wait a few seconds, then click **Enable** -6. Test by starting a call and enabling recording or live captions +6. Test by starting a call and starting a recording ## Troubleshooting From 88b0d4cdb1fc5adad51a1701a8581c8774f4c712 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 11 Jul 2025 16:20:27 -0400 Subject: [PATCH 37/60] Update source/configure/calls-metrics-monitoring.md Co-authored-by: Claudio Costa --- source/configure/calls-metrics-monitoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md index fdb2bc6ff16..d5028896d27 100644 --- a/source/configure/calls-metrics-monitoring.md +++ b/source/configure/calls-metrics-monitoring.md @@ -81,7 +81,7 @@ To monitor Calls metrics, you'll need: labels: service_name: 'rtcd' - - job_name: 'calls_offloader-node-exporter' + - job_name: 'calls-offloader-node-exporter' metrics_path: /metrics static_configs: - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] From 8463001df61efd1ac3ca78c14f40b624c83707e2 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Thu, 5 Mar 2026 15:13:37 -0500 Subject: [PATCH 38/60] Update calls-deployment.md FAQ items to use headings --- source/configure/calls-deployment.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index dff70c3f03c..9dd0d218448 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -239,13 +239,13 @@ For detailed performance metrics, benchmarks, and monitoring guidance, see the [ ## Frequently Asked Questions -**Is calls traffic encrypted?** +### Is calls traffic encrypted? Media (audio/video) is encrypted using security standards as part of WebRTC. It's mainly a combination of DTLS and SRTP. It's not e2e encrypted in the sense that in the current design all media needs to go through Mattermost which acts as a media router and has complete access to it. Media is then encrypted back to the clients so it's secured during transit. In short: only the participant clients and the Mattermost server have access to unencrypted call data. -**Are there any third-party services involved?** +### Are there any third-party services involved? Only a Mattermost STUN server (`stun.global.calls.mattermost.com`) is used by default. This can be removed if you set the ICE Host Override configuration. -**Is using UDP a requirement?** +### Is using UDP a requirement? UDP is recommended protocol to serve real-time media as it allows for the lowest latency between peers, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. If clients are unable to connect using UDP (due to limitations or strict firewalls), you have a few options: @@ -254,27 +254,27 @@ If clients are unable to connect using UDP (due to limitations or strict firewal - Run calls through an external TURN server that listens on TCP and relays all media traffic between peers. However, this is a sub-optimal solution that should be avoided if possible as it will introduce extra latency along with added infrastructural cost. -**Do I need a TURN server?** +### Do I need a TURN server? Only if clients are behind restrictive firewalls that block UDP. We recommend (and officially support) [coturn](https://github.com/coturn/coturn) if needed. -**Can RTCD traffic be kept internal?** +### Can RTCD traffic be kept internal? Yes, and it's recommended. Only the media ports need to be accessible to end-users. -**How will this work with an existing reverse proxy sitting in front of Mattermost?** +### How will this work with an existing reverse proxy sitting in front of Mattermost? Generally clients should connect directly to either Mattermost or, if deployed, the dedicated `rtcd` service through the configured UDP port. However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. -**Do calls require a dedicated server to work or can they run alongside Mattermost?** +### Do calls require a dedicated server to work or can they run alongside Mattermost? The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). See [RTCD Setup and Configuration](calls-rtcd-setup.md) for more details on the dedicated RTCD service. -**Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public?** +### Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public? When possible, it's recommended to keep communication between the Mattermost cluster and the dedicated `rtcd` service under the same private network as this can greatly simplify deployment and security. There's no requirement to expose `rtcd`'s HTTP API to the public internet. -**Can Calls be rolled out on a per-channel basis?** +### Can Calls be rolled out on a per-channel basis? ```{include} ../_static/badges/selfhosted-only.md ``` From 72329ecf12400d1e4370dbc80881f3aee1830d5e Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Thu, 5 Mar 2026 15:13:56 -0500 Subject: [PATCH 39/60] Update calls-kubernetes.md based on PR feedback --- source/configure/calls-kubernetes.md | 42 ++++++---------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md index a8519f1dfc8..7af1fc5e040 100644 --- a/source/configure/calls-kubernetes.md +++ b/source/configure/calls-kubernetes.md @@ -35,10 +35,7 @@ helm repo add mattermost https://helm.mattermost.com helm repo update helm install mattermost-rtcd mattermost/mattermost-rtcd \ - --set ingress.enabled=true \ - --set ingress.host=rtcd.example.com \ - --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ - --set rtcd.ice.hostOverride=rtcd.example.com + --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp ``` For complete configuration options, see the [RTCD Helm chart documentation](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-rtcd). @@ -61,31 +58,16 @@ For complete configuration options, see the [Calls-Offloader Helm chart document For Kubernetes deployments, you need to ensure specific connectivity paths: -1. **Client to RTCD connectivity**: UDP traffic on port 8443 is properly routed from clients to RTCD pods (for media) -2. **Mattermost to RTCD API connectivity**: TCP traffic on port 8045 must have a clear connectivity path from Mattermost pods to RTCD pods (for API communication) -3. **Client to RTCD TCP fallback**: TCP traffic on port 8443 can reach RTCD pods (for fallback connections when UDP fails) -4. **Load balancer configuration**: Load balancers must be properly configured to handle UDP traffic routing to RTCD pods -5. **Network policies**: Network policies must allow the required communications between Mattermost and RTCD services +1. **Client to RTCD connectivity**: UDP and TCP traffic on port 8443 is properly routed from clients to RTCD pods (for media, with TCP acting as a fallback). +2. **Mattermost to RTCD API connectivity**: There needs to be a clear connectivity path between Mattermost and RTCD on the API port (TCP 8045) +3. **Load balancer configuration**: Load balancers must be properly configured to handle UDP and TCP traffic routing to RTCD pods +4. **Network policies**: Network policies must allow the required communications between Mattermost and RTCD services ### Resource Requirements -For optimal performance in Kubernetes environments: - -1. **CPU**: At least 2 CPU cores per RTCD pod -2. **Memory**: At least 1GB RAM per RTCD pod -3. **Network**: Sufficient bandwidth for expected call volume (see benchmarks) - -We recommend setting resource limits and requests in your deployment: +Resource requirements for RTCD pods depend heavily on the expected call volume, participant count, and whether screen sharing is used. -```yaml -resources: - requests: - cpu: 1000m - memory: 1Gi - limits: - cpu: 2000m - memory: 2Gi -``` +We strongly recommend reviewing the [Performance Baselines](calls-metrics-monitoring.md#performance-baselines) to determine the appropriate CPU, memory, and network requests and limits for your specific deployment needs rather than relying on generic defaults. ### Scaling Considerations @@ -100,7 +82,7 @@ Horizontal scaling of RTCD pods is possible, but remember: Due to the inherent complexities of hosting a WebRTC service, some limitations apply when deploying Calls in a Kubernetes environment. -One key requirement is that each `rtcd` process must live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally not go through a standard ingress but directly to the pod running the `rtcd` process. +One key requirement is that each `rtcd` process must live in a dedicated Kubernetes node. This is necessary to forward the data correctly while allowing for horizontal scaling. Data should generally direct directly to the pod running the `rtcd` process, as routing this traffic through a standard ingress is not recommended for RTCD deployments. The general recommendation is to expose one external IP address per `rtcd` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. @@ -118,7 +100,7 @@ This case requires a couple of extra configurations: * The `RTCD_RTC_ICEHOSTPORTOVERRIDE` config should be used to pass a full mapping of node IPs and their respective port. - * Example: `RTCD_RTC_ICEHOSTPORTOVERRIDE=rtcdA_IP/8443,rtcdB_IP/8444,rtcdC_IP/8445` + * Example: `RTCD_RTC_ICEHOSTPORTOVERRIDE=/8443,/8444,/8445` * The `RTCD_RTC_ICEHOSTOVERRIDE` should be used to set the external IP address. @@ -128,12 +110,6 @@ One option to limit these static mappings is to reduce the size of the local sub ## Monitoring and Metrics -We recommend deploying Prometheus and Grafana alongside your Calls deployment: - -1. Configure Prometheus to scrape metrics from both Mattermost and RTCD pods -2. Import the official Mattermost Calls dashboard to Grafana -3. Set up alerts for CPU usage, connection failures, and error rates - For detailed information on metrics collection and monitoring, see the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide. ## Troubleshooting From 73e455ac8b3f6e7054fa61c0f6e792455814deff Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Thu, 5 Mar 2026 16:24:21 -0500 Subject: [PATCH 40/60] Update calls-rtcd-setup.md based on PR feedback --- source/configure/calls-rtcd-setup.md | 173 ++++----------------------- 1 file changed, 24 insertions(+), 149 deletions(-) diff --git a/source/configure/calls-rtcd-setup.md b/source/configure/calls-rtcd-setup.md index 6fece97e085..923314bfe5f 100644 --- a/source/configure/calls-rtcd-setup.md +++ b/source/configure/calls-rtcd-setup.md @@ -128,42 +128,9 @@ This is the recommended deployment method for non-Kubernetes production environm Replace `rtcd-linux-amd64` with the appropriate binary for your system architecture (e.g., `rtcd-linux-arm64` for ARM64 systems). The binary should be placed at `/opt/rtcd/rtcd` as this is the expected location referenced in systemd service files and other documentation. ``` -2. **Create a configuration file** (`/opt/rtcd/rtcd.toml`) with the following settings: +2. **Create a configuration file** (`/opt/rtcd/rtcd.toml`): - ```toml - [api] - http.listen_address = ":8045" - security.allow_self_registration = true - - [rtc] - ice_address_udp = "" - ice_port_udp = 8443 - ice_address_tcp = "" - ice_port_tcp = 8443 - ice_host_override = "YOUR_RTCD_SERVER_PUBLIC_IP" - - # UDP port range for WebRTC connections - ice.port_range.min = 9000 - ice.port_range.max = 10000 - - # STUN/TURN server configuration - ice_servers = [ - { urls = ["stun:stun.global.calls.mattermost.com:3478"] } - ] - - [store] - data_source = "/opt/rtcd/data/db" - - [logger] - enable_console = true - console_json = true - console_level = "INFO" - enable_file = true - file_json = true - file_level = "INFO" - file_location = "/opt/rtcd/rtcd.log" - enable_color = true - ``` + Mattermost recommends using the official [config.sample.toml](https://github.com/mattermost/rtcd/blob/master/config/config.sample.toml) as a starting point. Download this file and use it as your base configuration. 3. Create a dedicated user for the RTCD service: @@ -221,20 +188,22 @@ Docker deployment is suitable for development, testing, or containerized product ```bash docker run -d --name rtcd \ -e "RTCD_LOGGER_ENABLEFILE=true" \ - -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ -p 8443:8443/udp \ -p 8443:8443/tcp \ -p 8045:8045/tcp \ mattermost/rtcd:latest ``` + ```{note} + If you optionally use the `RTCD_API_SECURITY_ALLOWSELFREGISTRATION` setting, please note that it defaults to `false`. If enabled, it allows anyone who can connect to the service on the API port (8045) to successfully initiate calls. Understand the security implications of this setting before enabling it. + ``` + 2. For debugging purposes, you can enable more detailed logging: ```bash docker run -d --name rtcd \ -e "RTCD_LOGGER_ENABLEFILE=true" \ -e "RTCD_LOGGER_CONSOLELEVEL=DEBUG" \ - -e "RTCD_API_SECURITY_ALLOWSELFREGISTRATION=true" \ -p 8443:8443/udp \ -p 8443:8443/tcp \ -p 8045:8045/tcp \ @@ -262,119 +231,27 @@ For a complete sample configuration file, see the [RTCD config.sample.toml](http ### Kubernetes Deployment -For Kubernetes deployments, use the official Helm chart: - -1. Add the Mattermost Helm repository: - - ```bash - helm repo add mattermost https://helm.mattermost.com - helm repo update - ``` - -2. Install the RTCD chart: - - ```bash - helm install mattermost-rtcd mattermost/mattermost-rtcd \ - --set ingress.enabled=true \ - --set ingress.host=rtcd.example.com \ - --set service.annotations."service\\.beta\\.kubernetes\\.io/aws-load-balancer-backend-protocol"=udp \ - --set rtcd.ice.hostOverride=rtcd.example.com - ``` - - Refer to the [RTCD Helm chart documentation](https://github.com/mattermost/mattermost-helm/tree/master/charts/mattermost-rtcd) for additional configuration options. +For detailed information on deploying RTCD in Kubernetes environments, including Helm chart configurations, resource requirements, and scaling considerations, see the [Calls Deployment on Kubernetes](calls-kubernetes.md) guide. ## Configuration ### RTCD Configuration File -The RTCD service uses a TOML configuration file. Here's an example with commonly used settings: - -```toml -[api] -# The address and port to which the HTTP API server will listen -http.listen_address = ":8045" -# Security settings for authentication -security.allow_self_registration = true -security.enable_admin = true -security.admin_secret_key = "YOUR_API_KEY" - -[rtc] -# The UDP address and port for media traffic -ice_address_udp = "" -ice_port_udp = 8443 -# The TCP address and port for fallback connections -ice_address_tcp = "" -ice_port_tcp = 8443 -# Public hostname or IP that clients will use to connect -ice_host_override = "RTCD_SERVER_PUBLIC_IP" - -[logger] -# Logging configuration -enable_console = true -console_json = false -console_level = "INFO" -enable_file = true -file_json = true -file_level = "INFO" -file_location = "/opt/rtcd/rtcd.log" -``` - -Key Configuration Options: - -- **api.http.listen_address**: The address and port where the RTCD HTTP API service listens -- **rtc.ice_address_udp**: The UDP address for media traffic (empty means listen on all interfaces) -- **rtc.ice_port_udp**: The UDP port for media traffic -- **rtc.ice_address_tcp**: The TCP address for fallback media traffic -- **rtc.ice_port_tcp**: The TCP port for fallback media traffic -- **rtc.ice_host_override**: The public hostname or IP address clients will use to connect to RTCD -- **api.security.admin_secret_key**: API key for Mattermost servers to authenticate with RTCD - -### Required Mattermost Server Configuration - -When using RTCD, you must configure the Mattermost server's CORS settings to allow proper communication between the server and the RTCD service. - -#### CORS Configuration - -The `AllowCorsFrom` setting must include your SiteURL and, if using calls-offloader in a private network, the Mattermost server's private IP address: - -**Using mmctl:** -```bash -# Basic RTCD configuration - include your SiteURL -mmctl config set ServiceSettings.AllowCorsFrom "https://your-domain.com" - -# If using calls-offloader in a private network, also include Mattermost's private IP with port 8065 -mmctl config set ServiceSettings.AllowCorsFrom "https://your-domain.com http://192.168.1.100:8065" -``` - -**Using System Console:** -1. Go to **System Console > Environment > Web Server** -2. Set **Allow cross-origin requests from** to include: - - Your SiteURL (e.g., `https://your-domain.com`) - - If using calls-offloader in a private network: Also include Mattermost's private IP with port 8065 (e.g., `http://192.168.1.100:8065`) - -**Using config.json:** -```json -{ - "ServiceSettings": { - "AllowCorsFrom": "https://your-domain.com http://192.168.1.100:8065" - } -} -``` +The RTCD service uses a TOML configuration file. Mattermost recommends using the official [config.sample.toml](https://github.com/mattermost/rtcd/blob/master/config/config.sample.toml) as your base configuration file. -```{important} -This CORS configuration is specifically required for RTCD deployments and is not needed for integrated mode deployments. Multiple origins should be separated by spaces. +```{note} +A notable setting to be aware of is `ice_host_override` under the `[rtc]` section. You may need to configure this setting explicitly, particularly when RTCD is deployed behind NAT, in complex network topologies, or when automatic address discovery via STUN is unreliable. Setting `ice_host_override` directly to your server's public IP address or hostname is the preferred approach. ``` -### STUN/TURN Configuration +### TURN Configuration -For clients behind strict firewalls, you may need to configure STUN/TURN servers. In the RTCD configuration file, reference your STUN/TURN servers as follows: +For clients behind strict firewalls, you may need to configure TURN servers. In the RTCD configuration file, reference your TURN servers as follows: ```toml [rtc] -# STUN/TURN server configuration +# TURN server configuration ice_servers = [ - { urls = ["stun:stun.global.calls.mattermost.com:3478"] } - # { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } + { urls = ["turn:turn.example.com:3478"], username = "turnuser", credential = "turnpassword" } ] ``` @@ -414,6 +291,12 @@ After deploying RTCD, validate the installation: 2. **Test UDP connectivity**: + Before testing, ensure the RTCD service is stopped, as it binds to the same port. + + ```bash + sudo systemctl stop rtcd + ``` + On the RTCD server: ```bash @@ -428,12 +311,6 @@ After deploying RTCD, validate the installation: Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. - Note: This test must be run with the RTCD service stopped, as it binds to the same port. - - ```bash - sudo systemctl stop rtcd - ``` - 3. **Test TCP connectivity** (if enabled): Similar to the UDP test, but remove the `-u` flag from both commands. @@ -478,15 +355,13 @@ Once RTCD is properly set up and validated, configure Mattermost to use it: 2. Enable the **Enable RTCD Service** option -3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname) - -4. If configured, enter the **RTCD API Key** that matches the one in your RTCD configuration +3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname). Ensure you provide any generated credentials formulated in the URI (e.g., `http://clientID:authKey@rtcd.local`). For detailed capability/credential configuration, reference the [RTCD Service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtcd-service-url) documentation. -5. Save the configuration +4. Save the configuration -6. Test by creating a new call in any Mattermost channel +5. Test by creating a new call in any Mattermost channel -7. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics +6. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics ## Other Calls Documentation From f05c6ad45f24bfe2016ae7fbd7c1a9af505d4dfe Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 09:35:25 -0500 Subject: [PATCH 41/60] Update calls-metrics-monitoring.md based on PR feedback --- source/configure/calls-metrics-monitoring.md | 174 +++++++------------ 1 file changed, 61 insertions(+), 113 deletions(-) diff --git a/source/configure/calls-metrics-monitoring.md b/source/configure/calls-metrics-monitoring.md index d5028896d27..a9953c68d42 100644 --- a/source/configure/calls-metrics-monitoring.md +++ b/source/configure/calls-metrics-monitoring.md @@ -26,114 +26,73 @@ The metrics are exposed through HTTP endpoints: - **Calls Plugin**: `/plugins/com.mattermost.calls/metrics` - **RTCD Service**: `/metrics` (default) or a configured endpoint -## Setting Up Monitoring - -### Prerequisites - -To monitor Calls metrics, you'll need: - -1. **Prometheus**: For collecting and storing metrics -2. **Grafana**: For visualizing metrics (optional but recommended) - -### Installing Prometheus - -1. **Download and install Prometheus**: - - Visit the [Prometheus download page](https://prometheus.io/download/) for installation instructions. - -2. **Configure Prometheus** to scrape metrics from all Calls-related services: - - Complete `prometheus.yml` configuration for Calls monitoring: - - ```yaml - global: - scrape_interval: 15s - evaluation_interval: 15s +Resource utilization metrics (CPU, memory, network) are mainly provided by an external service ([`node-exporter`](https://prometheus.io/docs/guides/node-exporter/)). - scrape_configs: - - job_name: 'prometheus' - static_configs: - - targets: ['PROMETHEUS_IP:9090'] +> Metrics for the calls plugin are exposed through the `/plugins/com.mattermost.calls/metrics` subpath under the existing Mattermost server metrics endpoint. This is controlled by the [Listen address for performance](https://docs.mattermost.com/configure/environment-configuration-settings.html#listen-address-for-performance) configuration setting. It defaults to port 8067. For example: `http://localhost:8067/plugins/com.mattermost.calls/metrics` +> The RTCD Service `/metrics` endpoint is exposed on the HTTP API (e.g. `http://localhost:8045/metrics`). - - job_name: 'mattermost' - metrics_path: /metrics - static_configs: - - targets: ['MATTERMOST_SERVER_IP:8067'] - - - job_name: 'calls-plugin' - metrics_path: /plugins/com.mattermost.calls/metrics - static_configs: - - targets: ['MATTERMOST_SERVER_IP:8067'] - labels: - service_name: 'calls-plugin' - - - job_name: 'rtcd' - metrics_path: /metrics - static_configs: - - targets: ['RTCD_SERVER_IP:8045'] - labels: - service_name: 'rtcd' - - - job_name: 'rtcd-node-exporter' - metrics_path: /metrics - static_configs: - - targets: ['RTCD_SERVER_IP:9100'] - labels: - service_name: 'rtcd' - - - job_name: 'calls-offloader-node-exporter' - metrics_path: /metrics - static_configs: - - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] - labels: - service_name: 'offloader' - ``` - - Replace the placeholder IP addresses with your actual server addresses: - - - `MATTERMOST_SERVER_IP`: IP address of your Mattermost server - - `RTCD_SERVER_IP`: IP address of your RTCD server - - `CALLS_OFFLOADER_SERVER_IP`: IP address of your calls-offloader server (if deployed) - - `PROMETHEUS_IP`: IP address of your Prometheus server - - **Note**: The configuration above uses the default ports (RTCD: `8045`, Mattermost metrics: `8067`, etc.). Adjust these ports in `prometheus.yml` if you have customized them. - - ```{important} - **Metrics Path**: Ensure the metrics paths are correct. The RTCD service exposes metrics at `/metrics` by default, and the Calls plugin at `/plugins/com.mattermost.calls/metrics`. - ``` +## Setting Up Monitoring - ```{important} - **Metrics Configuration Notice**: Use the `service_name` labels as shown in the configuration above. These labels help organize metrics in dashboards and enable proper service identification. - ``` +For instructions on deploying Prometheus and Grafana for Mattermost, please refer to the [Deploy Prometheus and Grafana for Performance Monitoring](https://docs.mattermost.com/scale/deploy-prometheus-grafana-for-performance-monitoring.html) guide. + +Once Prometheus and Grafana are set up, you will need to configure Prometheus to scrape metrics from the Calls-related services. + +### Prometheus Scrape Configuration + +Add the following jobs to your `prometheus.yml` configuration: + +```yaml +scrape_configs: + - job_name: 'calls-plugin' + metrics_path: /plugins/com.mattermost.calls/metrics + static_configs: + - targets: ['MATTERMOST_SERVER_IP:8067'] + labels: + service_name: 'calls-plugin' + + - job_name: 'rtcd' + metrics_path: /metrics + static_configs: + - targets: ['RTCD_SERVER_IP:8045'] + labels: + service_name: 'rtcd' + + - job_name: 'rtcd-node-exporter' + metrics_path: /metrics + static_configs: + - targets: ['RTCD_SERVER_IP:9100'] + labels: + service_name: 'rtcd' + + - job_name: 'calls-offloader-node-exporter' + metrics_path: /metrics + static_configs: + - targets: ['CALLS_OFFLOADER_SERVER_IP:9100'] + labels: + service_name: 'offloader' +``` - ```{note} - - **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See [node_exporter setup guide](https://prometheus.io/docs/guides/node-exporter/) for installation instructions. - - **calls-offloader**: Only needed if you have call recording/transcription enabled - ``` +Replace the placeholder IP addresses with your actual server addresses: -### Installing Grafana +- `MATTERMOST_SERVER_IP`: IP address of your Mattermost server +- `RTCD_SERVER_IP`: IP address of your RTCD server +- `CALLS_OFFLOADER_SERVER_IP`: IP address of your calls-offloader server (if deployed) -1. **Download and install Grafana**: +```{important} +**Metrics Configuration Notice**: Use the `service_name` labels as shown in the configuration above. These labels help organize metrics in dashboards and enable proper service identification. +``` - Visit the [Grafana download page](https://grafana.com/grafana/download) for installation instructions. +```{note} +- **node_exporter**: Optional but recommended for system-level metrics (CPU, memory, disk, network). See [node_exporter setup guide](https://prometheus.io/docs/guides/node-exporter/) for installation instructions. +- **calls-offloader**: Only needed if you have call recording/transcription enabled. +``` -2. **Configure Grafana** to use Prometheus as a data source: - - - Add a new data source in Grafana - - Select Prometheus as the type - - Enter the URL of your Prometheus server - - Test and save the configuration +### Mattermost Calls Grafana Dashboard -3. **Import the Mattermost Calls dashboard**: +You can use the official [Mattermost Calls Performance Monitoring](https://grafana.com/grafana/dashboards/23225-mattermost-calls-performance-monitoring/) dashboard to visualize these metrics. - - Navigate to Dashboards > Import in Grafana - - Enter dashboard ID: `23225` or use the direct link: [Mattermost Calls Performance Monitoring](https://grafana.com/grafana/dashboards/23225-mattermost-calls-performance-monitoring/) - - Select your Prometheus data source, and enter values for the - - Confirm the port used for RTCD metrics (default is `8045`), and the port used for the Calls plugin metrics (default is `8067`) - - Click Import to add the dashboard to your Grafana instance - - ```{note} - The dashboard is also available as JSON source from the [Mattermost performance assets repository](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) for manual import or customization. - ``` +- To import it directly into Grafana, use dashboard ID: `23225`. +- The dashboard is also available as JSON source from the [Mattermost performance assets repository](https://github.com/mattermost/mattermost-performance-assets/blob/master/grafana/mattermost-calls-performance-monitoring.json) for manual import or customization. ## Key Metrics to Monitor @@ -149,11 +108,7 @@ These metrics help monitor the health and resource usage of the RTCD process: - `rtcd_process_resident_memory_bytes`: Memory usage in bytes - `rtcd_process_virtual_memory_bytes`: Virtual memory used -**Interpretation**: -- High CPU usage (>70%) may indicate the need for additional RTCD instances -- Steadily increasing memory usage might indicate a memory leak -- High number of file descriptors could indicate connection handling issues #### WebRTC Connection Metrics @@ -164,24 +119,16 @@ These metrics track the WebRTC connections and media flow: - `rtcd_rtc_rtp_tracks_total{direction="X"}`: Count of RTP tracks (incoming/outgoing) - `rtcd_rtc_sessions_total`: Total number of active RTC sessions -**Interpretation**: -- Increasing error counts may indicate connectivity or configuration issues -- Track by state to see if connections are failing to establish or dropping -- Larger track counts require proportionally more CPU and bandwidth #### WebSocket Metrics These metrics track the signaling channel: -- `rtcd_ws_connections_total`: Total number of active WebSocket connections +- `rtcd_ws_connections_total`: Total number of active WebSocket connections. This is about RTCD <-> MM, so the connection count should match the number of MM nodes. - `rtcd_ws_messages_total{direction="X"}`: Count of WebSocket messages (sent/received) -**Interpretation**: -- Connection count should match expected participant numbers -- Unusually high message counts might indicate protocol issues -- Connection drops might indicate network issues ### Calls Plugin Metrics @@ -220,7 +167,7 @@ The following performance benchmarks provide baseline metrics for RTCD deploymen Below are the detailed benchmarks based on internal performance testing: - +
@@ -467,4 +414,5 @@ Each target should show status "UP" in green. If a target shows "DOWN" or errors - [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments - [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques -Configure Prometheus storage accordingly to balance disk usage with retention needs. \ No newline at end of file +**Note:** +Configure Prometheus storage accordingly to balance disk usage with retention needs. If you need to be tight on storage, you can use a short retention period. If you have lots of storage you can keep the retention length longer. \ No newline at end of file From b5f940783762db0580cf6b0315f052df718c4b4f Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 09:45:21 -0500 Subject: [PATCH 42/60] Update calls-offloader-setup.md based on PR feedback --- source/configure/calls-offloader-setup.md | 35 ++++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/source/configure/calls-offloader-setup.md b/source/configure/calls-offloader-setup.md index 420c3fee48b..862276e92f3 100644 --- a/source/configure/calls-offloader-setup.md +++ b/source/configure/calls-offloader-setup.md @@ -31,9 +31,8 @@ Before deploying calls-offloader, ensure you have: - A Mattermost Enterprise license - A properly configured Mattermost Calls deployment (either integrated or with RTCD) -- Docker installed and running (for Docker-based job execution) +- A moderately powerful server with Docker installed and running - Sufficient storage space for recordings (see [Storage Requirements](#storage-requirements)) -- A server or container environment with adequate resources ### System Requirements @@ -41,10 +40,13 @@ For detailed system requirements and performance recommendations, refer to the [ ### Storage Requirements -Call recordings can consume significant storage space: +Call recordings can consume significant storage space. Based on average recording sizes with screen sharing on (including one audio track), storage usage by quality chosen is approximately: -- Audio-only recordings: ~1MB per minute per participant -- Screen sharing recordings: ~10-50MB per minute depending on content +- **Low**: ~0.5GB/hour (or ~8MB/minute) +- **Medium**: ~0.7GB/hour (or ~12MB/minute) +- **High**: ~1.2GB/hour (or ~20MB/minute) + +*Note: Audio-only recordings consume approximately 1MB per minute per participant.* ## Installation and Deployment @@ -78,7 +80,7 @@ Call recordings can consume significant storage space: [jobs] api_type = "docker" - max_concurrent_jobs = 2 + max_concurrent_jobs = 100 failed_jobs_retention_time = "30d" image_registry = "mattermost" @@ -88,7 +90,7 @@ Call recordings can consume significant storage space: console_level = "INFO" enable_file = true file_json = true - file_level = "INFO" + file_level = "DEBUG" file_location = "/opt/calls-offloader/calls-offloader.log" enable_color = true ``` @@ -152,7 +154,7 @@ The API section controls how the service accepts requests: Controls persistent data storage: -- **data_source**: Path to directory for storing job metadata and state +- **data_source**: Path to directory for storing client (i.e., connecting Mattermost nodes) IDs and credentials ### Jobs Configuration @@ -183,6 +185,12 @@ In such cases, you can override the site URL used by recorder jobs or transcribe - **MM_CALLS_RECORDER_SITE_URL**: Override the site URL used by recording jobs - **MM_CALLS_TRANSCRIBER_SITE_URL**: Override the site URL used by transcription jobs +```{note} +When these Site URL overrides are used, the `ServiceSettings.AllowCorsFrom` setting on your Mattermost server may need to be adjusted accordingly to ensure CORS does not block requests. + +Additionally, this override configuration is particularly useful if your Mattermost public Site URL uses HTTPS, because pointing the offloader directly to an internal HTTP endpoint bypasses the need to deal with client-side certificates. +``` + Example configuration: Create or edit the Mattermost environment file (`/opt/mattermost/config/mattermost.environment`): @@ -254,7 +262,6 @@ After deploying calls-offloader, validate the installation: - Firewall rules or SELinux policies on the calls-offloader server (port 4545 must be accessible) - Network connectivity between Mattermost and calls-offloader servers - - calls-offloader service binding configuration (ensure it's not bound to localhost only) 3. **Verify Docker service** (if using docker api_type): @@ -295,7 +302,7 @@ Once calls-offloader is properly set up and validated, configure Mattermost to u **"failed to create recording job: max concurrent jobs reached"** -This error occurs when the calls-offloader service has reached its configured job limit. +This error occurs when the calls-offloader service has reached its configured job limit, and it will usually result in a failure message on the Mattermost Calls plugin side (such as a timeout). Solutions: @@ -367,7 +374,7 @@ When deploying calls-offloader in air-gapped environments, you need to set up a The calls-offloader service creates Docker containers to handle: - **Call Recording**: Creates containers to record audio/video from calls -- **Call Transcription**: Creates containers to transcribe recorded calls using speech-to-text +- **Call Transcription / Live Captioning**: Creates containers to transcribe recorded calls and produce live captions using speech-to-text These containers are typically pulled from the `mattermost` registry on Docker Hub, but in air-gapped networks, you need to: 1. Set up a local Docker registry @@ -405,12 +412,12 @@ To find the correct versions for your Calls plugin: - Visit the Calls plugin repository: https://github.com/mattermost/mattermost-plugin-calls - Navigate to the tag or branch corresponding to your plugin version - Open the `plugin.json` file - - Find the `RecorderImage` and `TranscriberImage` entries (around line 719-720) + - Find the `calls_recorder_version` and `calls_transcriber_version` entries (located near the bottom of the file). Example from plugin.json: ```json - "RecorderImage": "mattermost/calls-recorder:v0.8.5", - "TranscriberImage": "mattermost/calls-transcriber:v0.6.3" + "calls_recorder_version": "v0.8.8", + "calls_transcriber_version": "v0.7.1" ``` 3. **Use these exact versions** in your air-gap setup instead of `latest` tags From 0e49c0d04494aa68cd2eb090af05f48d8ae0e0e8 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 10:00:14 -0500 Subject: [PATCH 43/60] Update calls-troubleshooting.md based on PR feedback --- source/configure/calls-troubleshooting.md | 73 ++++------------------- 1 file changed, 12 insertions(+), 61 deletions(-) diff --git a/source/configure/calls-troubleshooting.md b/source/configure/calls-troubleshooting.md index f42420b1862..5b70e232215 100644 --- a/source/configure/calls-troubleshooting.md +++ b/source/configure/calls-troubleshooting.md @@ -52,7 +52,6 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa 2. **Network quality**: - High latency or packet loss can cause audio issues - - Try testing with TCP fallback enabled (requires RTCD v0.11+ and Calls v0.17+) 3. **Audio device configuration**: - Users should verify their audio input/output settings @@ -62,6 +61,10 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa **Symptoms**: Calls connect but quality is poor, with latency, echo, or distortion. +```{note} +Echo and noise issues are generally related to client input/output devices (e.g., microphones and speakers), as the Mattermost Calls services do not process (e.g., denoise) the audio during transmission. +``` + **Possible causes and solutions**: 1. **Server resources**: @@ -84,21 +87,26 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa 1. **HTTP API connectivity test**: - Test if the RTCD API is reachable: + Test if the RTCD API is reachable (this test requires the RTCD service to be *running*): ```bash curl http://YOUR_RTCD_SERVER:8045/version - # Example response: {"buildDate":"2025-04-02 21:33","buildVersion":"v1.1.0","buildHash":"7bc1f7a","goVersion":"go1.23.6","goOS":"linux","goArch":"amd64"} ``` + # Example response: {"buildDate":"2025-04-02 21:33","buildVersion":"v1.1.0","buildHash":"7bc1f7a","goVersion":"go1.23.6","goOS":"linux","goArch":"amd64"} + ``` 2. **UDP connectivity test**: + ```{important} + This test must be performed while the RTCD service is **stopped** (so `nc` can bind to the port) and should be run from the Mattermost server machine(s). + ``` + On the RTCD server: ```bash nc -l -u -p 8443 ``` - On a client machine: + On the Mattermost server machine: ```bash nc -v -u YOUR_RTCD_SERVER 8443 @@ -122,38 +130,6 @@ This guide provides comprehensive troubleshooting steps for Mattermost Calls, pa nc -v YOUR_RTCD_SERVER 8443 ``` -### Network Packet Analysis - -To capture and analyze network traffic: - -1. **Capture UDP traffic on the RTCD server**: - - ```bash - sudo tcpdump -n 'udp port 8443' -i any - ``` - -2. **Capture TCP API traffic**: - - ```bash - sudo tcpdump -n 'tcp port 8045' -i any - ``` - -3. **Analyze traffic patterns**: - - - Verify packets are flowing both ways - - Look for ICMP errors that might indicate firewall issues - - Check for patterns of packet loss - -4. **Use Wireshark for deeper analysis**: - - For more detailed packet inspection, capture traffic with tcpdump and analyze with Wireshark: - - ```bash - sudo tcpdump -n -w calls_traffic.pcap 'port 8443' - ``` - - Then analyze the `calls_traffic.pcap` file with Wireshark. - ### Firewall Configuration Checks 1. **Check iptables rules** (Linux): @@ -195,7 +171,6 @@ The RTCD service logs important events and errors. Set the log level to "debug" 2. **Common log patterns to look for**: - **Connection errors**: Look for "failed to connect" or "connection error" messages - - **ICE negotiation failures**: Look for "ICE failed" or "ICE timeout" messages - **API authentication issues**: Look for "unauthorized" or "invalid API key" messages ### Mattermost Logs @@ -254,30 +229,6 @@ If RTCD servers show high CPU usage: ps -eLo pid,ppid,tid,pcpu,comm | grep rtcd ``` -3. **Enable pprof profiling** (if needed): - - Add to your RTCD configuration: - - ```json - { - "debug": { - "pprof": true, - "pprofPort": 6060 - } - } - ``` - - Then capture a CPU profile: - - ```bash - curl http://localhost:6060/debug/pprof/profile > cpu.profile - ``` - - Analyze with: - - ```bash - go tool pprof -http=:8080 cpu.profile - ``` ### Diagnosing Network Bottlenecks From 876619a88973a3ccda11bbcee4af06ea416e19aa Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 10:06:53 -0500 Subject: [PATCH 44/60] Update calls-deployment.md based on PR feedback --- source/configure/calls-deployment.md | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/source/configure/calls-deployment.md b/source/configure/calls-deployment.md index 9dd0d218448..d1cad1f318f 100644 --- a/source/configure/calls-deployment.md +++ b/source/configure/calls-deployment.md @@ -197,7 +197,7 @@ The RTCD service is the recommended way to host Calls for the following reasons: - **Performance, scalability, and stability of the Calls product**: If Calls traffic spikes, or more overall capacity is needed, RTCD servers can be added to balance the load. As an added benefit, if the Mattermost traffic spikes, or if a Mattermost instance needs to be restarted, those people in a current call will not be affected - current calls won't be dropped. - Some caveats apply here. WebSocket events (for example: emoji reactions, hand raising, muting/unmuting) will not be transmitted while the main Mattermost server is down. But the call itself will continue while the main server restarts. + Some caveats apply here. While the main Mattermost server is down, things will quickly start to go awry: WebSocket events (for example: emoji reactions, hand raising, muting/unmuting) will not be transmitted, and new media track negotiations will fail. While existing media streams will continue initially, if the main server does not come back up within a reasonable timeframe (e.g., 1 minute), clients will begin to drop from the call entirely as their WebSocket re-connect attempts will hit the maximum allowed. - **Kubernetes deployments**: In a Kubernetes deployment, RTCD is strongly recommended; it is currently the only officially supported way to run Calls. @@ -243,7 +243,7 @@ For detailed performance metrics, benchmarks, and monitoring guidance, see the [ Media (audio/video) is encrypted using security standards as part of WebRTC. It's mainly a combination of DTLS and SRTP. It's not e2e encrypted in the sense that in the current design all media needs to go through Mattermost which acts as a media router and has complete access to it. Media is then encrypted back to the clients so it's secured during transit. In short: only the participant clients and the Mattermost server have access to unencrypted call data. ### Are there any third-party services involved? -Only a Mattermost STUN server (`stun.global.calls.mattermost.com`) is used by default. This can be removed if you set the ICE Host Override configuration. +Only a Mattermost STUN server (`stun.global.calls.mattermost.com`) is used by default. No user information, call metadata, or media traffic is ever sent to or shared with this STUN service; its sole purpose is to help WebRTC clients discover their public IP address and port mapping. Furthermore, this dependency can be entirely removed if you manually configure the ICE Host Override setting. ### Is using UDP a requirement? UDP is recommended protocol to serve real-time media as it allows for the lowest latency between peers, but TCP fallback is supported since plugin version 0.17 and RTCD version 0.11. @@ -257,22 +257,9 @@ If clients are unable to connect using UDP (due to limitations or strict firewal ### Do I need a TURN server? Only if clients are behind restrictive firewalls that block UDP. We recommend (and officially support) [coturn](https://github.com/coturn/coturn) if needed. -### Can RTCD traffic be kept internal? -Yes, and it's recommended. Only the media ports need to be accessible to end-users. - -### How will this work with an existing reverse proxy sitting in front of Mattermost? - -Generally clients should connect directly to either Mattermost or, if deployed, the dedicated `rtcd` service through the configured UDP port. However, it's also possible to route the traffic through an existing load balancer as long as this has support for routing the UDP protocol (e.g. nginx). Of course this will require additional configuration and potential changes to how the plugin is run as it won't be possible to load balance the UDP flow across multiple instances like it happens for HTTP. - -### Do calls require a dedicated server to work or can they run alongside Mattermost? - -The plugin can function in different modes. By default calls are handled completely by the plugin which runs as part of Mattermost. It's also possible to use a dedicated service to offload the computational and bandwidth costs and scale further (Enterprise only). - -See [RTCD Setup and Configuration](calls-rtcd-setup.md) for more details on the dedicated RTCD service. - ### Can the traffic between Mattermost and `rtcd` be kept internal or should it be opened to the public? -When possible, it's recommended to keep communication between the Mattermost cluster and the dedicated `rtcd` service under the same private network as this can greatly simplify deployment and security. There's no requirement to expose `rtcd`'s HTTP API to the public internet. +Yes, the `rtcd` <-> Mattermost communication (HTTP/WebSocket API over TCP port 8045) should remain internal in almost all cases. When possible, it's highly recommended to keep communication between the Mattermost cluster and the dedicated `rtcd` service under the same private network as this minimizes latency and greatly simplifies deployment and security. There is no requirement to expose `rtcd`'s HTTP API to the public internet. Only the media ports (UDP/TCP 8443) need to be accessible to end-users. ### Can Calls be rolled out on a per-channel basis? From 440ac40dd88446ca129d67a140fe8f117c1d098b Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 10:12:32 -0500 Subject: [PATCH 45/60] Update calls-kubernetes.md based on PR feedback --- source/configure/calls-kubernetes.md | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/source/configure/calls-kubernetes.md b/source/configure/calls-kubernetes.md index 7af1fc5e040..26ed6210e2c 100644 --- a/source/configure/calls-kubernetes.md +++ b/source/configure/calls-kubernetes.md @@ -86,27 +86,7 @@ One key requirement is that each `rtcd` process must live in a dedicated Kuberne The general recommendation is to expose one external IP address per `rtcd` instance (Kubernetes node). This makes it simpler to scale as the application is able to detect its own external address (through STUN) and advertise it to clients to achieve connectivity with minimal configuration. -If, for some reason, exposing multiple IP addresses is not possible in your environment, port mapping (NAT) can be used. In this scenario different ports are used to map the respective `rtcd` nodes behind the single external IP. Example: -```text -EXT_IP:8443 -> rtcdA:8443 -EXT_IP:8444 -> rtcdB:8443 -EXT_IP:8445 -> rtcdC:8443 -``` - -This case requires a couple of extra configurations: - -* NAT mappings need to be in place for every `rtcd` node. This is usually done at the ingress point (e.g., ELB, NLB, etc). - -* The `RTCD_RTC_ICEHOSTPORTOVERRIDE` config should be used to pass a full mapping of node IPs and their respective port. - - * Example: `RTCD_RTC_ICEHOSTPORTOVERRIDE=/8443,/8444,/8445` - -* The `RTCD_RTC_ICEHOSTOVERRIDE` should be used to set the external IP address. - -```{note} -One option to limit these static mappings is to reduce the size of the local subnet (e.g., to `/29`). -``` ## Monitoring and Metrics @@ -118,7 +98,7 @@ For Kubernetes-specific troubleshooting: 1. Check pod logs: `kubectl logs -f deployment/mattermost-rtcd` 2. Verify service connectivity: `kubectl port-forward service/mattermost-rtcd 8045:8045` -3. Ensure UDP traffic is properly routed through your ingress/load balancer +3. Ensure UDP and TCP traffic is properly routed through your load balancer 4. Verify network policies allow required communication paths For detailed troubleshooting steps, see the [Calls Troubleshooting](calls-troubleshooting.md) guide. From d0b845101698f64ab56858f373094a832acfbe5c Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Fri, 6 Mar 2026 12:17:55 -0500 Subject: [PATCH 46/60] Update calls-troubleshooting.md log filter --- source/administration-guide/configure/calls-troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/administration-guide/configure/calls-troubleshooting.md b/source/administration-guide/configure/calls-troubleshooting.md index e197205e9f1..2bcdc7f6af6 100644 --- a/source/administration-guide/configure/calls-troubleshooting.md +++ b/source/administration-guide/configure/calls-troubleshooting.md @@ -182,7 +182,7 @@ Check the Mattermost server logs for Calls plugin related issues: 2. **Filter for Calls-related logs**: ```bash - grep -i "calls" /path/to/mattermost.log + grep -i "com.mattermost.calls" /path/to/mattermost.log ``` 3. **Look for common patterns**: From 0cd2cb449db7a7b635f2db54d2055e9082b5fec9 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 17:19:51 -0400 Subject: [PATCH 47/60] Add screenshot to troubleshooting docs under Browser Console Logs --- .../configure/calls-troubleshooting.md | 2 ++ source/images/developer-tools-call-widget.png | Bin 0 -> 550982 bytes 2 files changed, 2 insertions(+) create mode 100644 source/images/developer-tools-call-widget.png diff --git a/source/administration-guide/configure/calls-troubleshooting.md b/source/administration-guide/configure/calls-troubleshooting.md index 2bcdc7f6af6..c9d49393f53 100644 --- a/source/administration-guide/configure/calls-troubleshooting.md +++ b/source/administration-guide/configure/calls-troubleshooting.md @@ -206,6 +206,8 @@ Instruct users to check their browser console logs: - "ICE connection" failures - WebSocket connection errors +![Developer Tools for Call Widget](../../images/developer-tools-call-widget.png) + ## Performance Issues ### Diagnosing High CPU Usage diff --git a/source/images/developer-tools-call-widget.png b/source/images/developer-tools-call-widget.png new file mode 100644 index 0000000000000000000000000000000000000000..54cc679cc5d24529a2db0b68a066d4fb9bcbab39 GIT binary patch literal 550982 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 a3D$>I5m3& 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

9*@NQ!2ADGAq*yR9Kfb^6~6SLv= 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


76UcmDj*YA(F#4YH@ISM_@bpue629TttL~&F2 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%0DN6`(2Ne*Apkr)GF5 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 Date: Tue, 10 Mar 2026 17:33:28 -0400 Subject: [PATCH 48/60] Add references to community calls installation scripts --- .../administration-guide/configure/calls-offloader-setup.md | 4 ++++ source/administration-guide/configure/calls-rtcd-setup.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index e595671a6a2..d5d012e41ad 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -52,6 +52,10 @@ Call recordings can consume significant storage space. Based on average recordin ### Bare Metal or VM Deployment +```{tip} +Looking for an automated setup? Check out these community-maintained [Calls Installation Scripts](https://github.com/bgardner8008/calls-install-scripts) for quick provisioning of the Calls Offloader service on Ubuntu/Debian systems. +``` + 1. Download the latest release from the [calls-offloader GitHub repository](https://github.com/mattermost/calls-offloader/releases) 2. Create the necessary directories: diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index 5ac7616fe84..92f96cbd393 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -107,6 +107,10 @@ There are multiple ways to deploy RTCD, depending on your environment. We recomm This is the recommended deployment method for non-Kubernetes production environments as it provides the best performance and operational control. For Kubernetes deployments, see the [Calls Deployment on Kubernetes](calls-kubernetes.md) guide. +```{tip} +Looking for an automated setup? Check out these community-maintained [Calls Installation Scripts](https://github.com/bgardner8008/calls-install-scripts) for quick provisioning of the RTCD service on Ubuntu/Debian systems. +``` + 1. **Download and install the RTCD binary**: Download the latest release from the [RTCD GitHub repository](https://github.com/mattermost/rtcd/releases): From 420fc0981a356228f7de37ff42b582245af93550 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 17:35:25 -0400 Subject: [PATCH 49/60] Update network requirements link in install-docker.rst --- source/deployment-guide/server/containers/install-docker.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/deployment-guide/server/containers/install-docker.rst b/source/deployment-guide/server/containers/install-docker.rst index 0f49edabc48..bf301bcce8f 100644 --- a/source/deployment-guide/server/containers/install-docker.rst +++ b/source/deployment-guide/server/containers/install-docker.rst @@ -206,7 +206,7 @@ Looking for a way to evaluate Mattermost on a single local machine using Docker? - This local image is self-contained (i.e., it has an internal database and works out of the box). Dropping a container using this image removes data and configuration as expected. You can see the :doc:`configuration settings ` documentation to learn more about customizing your trial deployment. - **Preview Mode** shouldn't be used in a production environment, as it uses a known password string, contains other non-production configuration settings, has email disabled, keeps no persistent data (all data lives inside the container), and doesn't support upgrades. - - If you are planning to use the calling functionality in **Preview Mode** on a non-local environment, you should ensure that the server is running on a secure (HTTPs) connection and that the :ref:`network requirements ` to run calls are met. + - If you are planning to use the calling functionality in **Preview Mode** on a non-local environment, you should ensure that the server is running on a secure (HTTPs) connection and that the :ref:`network requirements ` to run calls are met. 1. Install `Docker `__. From 2af78b88ccb61d8bbf573580abf5116df7b930f5 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 17:40:16 -0400 Subject: [PATCH 50/60] Restore reworked version of calls-troubleshooting.md --- .../configure/calls-troubleshooting.md | 335 +----------------- 1 file changed, 14 insertions(+), 321 deletions(-) diff --git a/source/administration-guide/configure/calls-troubleshooting.md b/source/administration-guide/configure/calls-troubleshooting.md index c9d49393f53..b376587465d 100644 --- a/source/administration-guide/configure/calls-troubleshooting.md +++ b/source/administration-guide/configure/calls-troubleshooting.md @@ -3,337 +3,30 @@ ```{include} ../../_static/badges/all-commercial.md ``` -This guide provides comprehensive troubleshooting steps for Mattermost Calls, particularly focusing on the dedicated RTCD deployment model. Follow these steps to identify and resolve common issues. +When troubleshooting Mattermost Calls, gathering the appropriate log files for analysis is critical. The required logs include: -- [Common issues](#common-issues) -- [Connectivity troubleshooting](#connectivity-troubleshooting) -- [Log analysis](#log-analysis) -- [Performance issues](#performance-issues) +## RTCD logs -## Common Issues +The location of the RTCD log file is determined by the settings in your RTCD `config.toml` file. If you are running Calls using the integrated RTCD, these logs are included within the standard Mattermost server logs. -### Calls Not Connecting +## Client logs -**Symptoms**: Users can start calls but cannot connect, or calls connect but drop quickly. +You can retrieve basic client logs by running the `/call logs` slash command to output the log for the most recent call. However, capturing the JavaScript console logs is often more helpful. The method for capturing these logs depends on your client: -**Possible causes and solutions**: - -1. **Network connectivity issues**: - - Verify that UDP port 8443 (or your configured port) is open between clients and RTCD servers - - Ensure TCP port 8045 is open between Mattermost and RTCD servers - - Check that any load balancers are properly configured for UDP traffic - -2. **ICE configuration issues**: - - Verify the `rtc.ice_host_override` setting in RTCD configuration matches the publicly accessible hostname or IP of the RTCD server - - If this setting is incorrect, client browser console may show errors like: `com.mattermost.calls: peer error timed out waiting for rtc connection` - - Meanwhile, RTCD `trace` level logs might show internal IP addresses in ICE connection logs: - - ```json - {"timestamp":"2025-05-14 10:29:08.935 Z","level":"trace","msg":"Ping STUN from udp4 host 172.31.29.117:8443 (resolved: 172.31.29.117:8443) to udp4 host 192.168.64.1:59737 (resolved: 192.168.64.1:59737)","caller":"rtc/logger.go:54","origin":"ice/v4.(*Agent).sendBindingRequest github.com/pion/ice/v4@v4.0.3/agent.go:921"} - ``` - -3. **API connectivity**: - - Verify that Mattermost servers can reach the RTCD API endpoint - - Check that the API key is correctly configured in both Mattermost and RTCD - -4. **Plugin configuration**: - - Ensure the Calls plugin is enabled and properly configured - - Verify the RTCD service URL is correct in the System Console - -### Audio Issues - -**Symptoms**: Users can connect to calls, but audio is one-way, choppy, or not working. - -**Possible causes and solutions**: - -1. **Client permissions**: - - Ensure browser/app has microphone permissions - - Check if users are using multiple audio devices that might interfere - -2. **Network quality**: - - High latency or packet loss can cause audio issues - -3. **Audio device configuration**: - - Users should verify their audio input/output settings - - Try different browsers or the desktop app - -### Call Quality Issues - -**Symptoms**: Calls connect but quality is poor, with latency, echo, or distortion. - -```{note} -Echo and noise issues are generally related to client input/output devices (e.g., microphones and speakers), as the Mattermost Calls services do not process (e.g., denoise) the audio during transmission. -``` - -**Possible causes and solutions**: - -1. **Server resources**: - - Check CPU usage on RTCD servers - high CPU can cause quality issues - - Refer to the [Calls Metrics and Monitoring](calls-metrics-monitoring.md) guide for detailed instructions on monitoring and optimizing performance - - Monitor network bandwidth usage - -2. **Network congestion**: - - Check for packet loss between clients and RTCD - - Consider network QoS settings to prioritize real-time traffic - -3. **Client-side issues**: - - Browser or app limitations - - Hardware limitations (CPU, memory) - - Network congestion at the user's location - -## Connectivity Troubleshooting - -### Basic Connectivity Tests - -1. **HTTP API connectivity test**: - - Test if the RTCD API is reachable (this test requires the RTCD service to be *running*): - - ```bash - curl http://YOUR_RTCD_SERVER:8045/version - # Example response: {"buildDate":"2025-04-02 21:33","buildVersion":"v1.1.0","buildHash":"7bc1f7a","goVersion":"go1.23.6","goOS":"linux","goArch":"amd64"} - ``` - -2. **UDP connectivity test**: - - ```{important} - This test must be performed while the RTCD service is **stopped** (so `nc` can bind to the port) and should be run from the Mattermost server machine(s). - ``` - - On the RTCD server: - - ```bash - nc -l -u -p 8443 - ``` - - On the Mattermost server machine: - - ```bash - nc -v -u YOUR_RTCD_SERVER 8443 - ``` - - Type a message and press Enter. If you see the message on both sides, UDP connectivity is working. - -3. **TCP fallback connectivity test**: - - Same as the UDP test, but without the `-u` flag: - - On the RTCD server: - - ```bash - nc -l -p 8443 - ``` - - On a client machine: - - ```bash - nc -v YOUR_RTCD_SERVER 8443 - ``` - -### Firewall Configuration Checks - -1. **Check iptables rules** (Linux): - - ```bash - sudo iptables -L -n - ``` - - Ensure there are no rules blocking UDP port 8443 or TCP ports 8045/8443. - -2. **Check cloud provider security groups**: - - Verify that security groups or network ACLs allow: - - Inbound UDP on port 8443 from client networks - - Inbound TCP on port 8045 from Mattermost server networks - - Inbound TCP on port 8443 (if TCP fallback is enabled) - -3. **Check intermediate firewalls**: - - - Corporate firewalls might block UDP traffic - - Some networks might require TURN servers for traversal - -## Log Analysis - -### RTCD Logs - -The RTCD service logs important events and errors. Set the log level to "debug" for troubleshooting: - -1. **In the configuration file**: - - ```toml - [logger] - enable_file = true - file_level = "DEBUG" - ``` - - Restart the RTCD service after making these changes - -2. **Common log patterns to look for**: - - - **Connection errors**: Look for "failed to connect" or "connection error" messages - - **API authentication issues**: Look for "unauthorized" or "invalid API key" messages - -### Mattermost Logs - -Check the Mattermost server logs for Calls plugin related issues: - -1. **Enable debug logging** in System Console > Environment > Logging > File Log Level - -2. **Filter for Calls-related logs**: - - ```bash - grep -i "com.mattermost.calls" /path/to/mattermost.log - ``` - -3. **Look for common patterns**: - - - Connection errors to RTCD - - Plugin initialization issues - - WebSocket connection problems - -### Browser Console Logs - -Instruct users to check their browser console logs: - -1. **In Chrome/Edge**: - - Press F12 to open Developer Tools - - Go to the Console tab - - Look for errors related to WebRTC, Calls, or media permissions - -2. **Specific patterns to look for**: - - - "getUserMedia" errors (microphone permission issues) - - "ICE connection" failures - - WebSocket connection errors +- **Desktop App:** While a call is in progress, navigate to **View > Developer Tools > Developer Tools for Call Widget**. Next to the **Filter** field, select **Verbose** from the log level drop-down menu to view the debug output. To save the log, right-click within the console and select **Save as...**. ![Developer Tools for Call Widget](../../images/developer-tools-call-widget.png) -## Performance Issues - -### Diagnosing High CPU Usage - -If RTCD servers show high CPU usage: - -1. **Check concurrent calls and participants**: - - - Access the Prometheus metrics endpoint to see active sessions - - Compare with the benchmark data in the {doc}`Calls Metrics and Monitoring ` documentation's Performance Baselines section - -2. **Profile CPU usage** (Linux): - - ```bash - top -p $(pgrep rtcd) - ``` - - Or for detailed per-thread usage: - - ```bash - ps -eLo pid,ppid,tid,pcpu,comm | grep rtcd - ``` - - -### Diagnosing Network Bottlenecks - -If you suspect network bandwidth issues: - -1. **Monitor network utilization**: - - ```bash - iftop -n - ``` - -2. **Check for packet drops**: - - ```bash - netstat -su | grep -E 'drop|error' - ``` - -3. **Verify system network buffers**: - - ```bash - sysctl -a | grep net.core.rmem - sysctl -a | grep net.core.wmem - ``` - - Ensure these match the recommended values: - - ```bash - net.core.rmem_max = 16777216 - net.core.wmem_max = 16777216 - net.core.optmem_max = 16777216 - ``` - -## Recording and Transcription Issues - -For troubleshooting calls-offloader service issues including recording and transcription problems, see the [Calls Offloader Setup and Configuration](calls-offloader-setup.md#troubleshooting) guide. +- **Chrome browser:** Select the **More menu** (three vertical dots) next to the address bar, then go to **More Tools > Developer Tools**. Select the **Console** tab to view the output. Next to the **Filter** field, select **Verbose** from the log level drop-down menu to view the debug output. To save the log, right-click within the console and select **Save as...**. -### Calls-Offloader Docker Debugging +## Client statistics -If you're running calls-offloader in Docker, use these commands for debugging: +You can gather client call statistics by running the `/call stats` slash command. While you can run this command during an active call, it is best to run it immediately after a call concludes. This command provides valuable information regarding the negotiated connection between the client and RTCD, as well as statistics on media packets sent and lost. -#### Monitor Live Logs +## Mattermost server logs -For easier log management, configure calls-offloader to capture job logs directly in the calls-offloader log file by adding the following to your `calls-offloader.toml`: +The Mattermost server logs often contain entries related to the Calls plugin. If you are using an external RTCD instance, these logs are generally less critical than the RTCD and client logs. -```toml -[jobs.docker] -# Whether to output job logs to the console. Default is false. -output_logs = true -``` - -With this configuration enabled, all logs from recorder and transcriber docker containers will be written to the main calls-offloader log file. - -#### View Completed Jobs - -To view completed calls-offloader job containers (useful for debugging failed jobs): - -```bash -# List all exited containers to see completed jobs -docker ps -a --filter "status=exited" -``` - -Look for containers with recorder and transcriber image names that have exited. You can then examine their logs: - -```bash -# View logs from a specific completed container -docker logs -``` - -#### Additional Docker Debugging Tips - -- **Check container resource usage**: `docker stats` to see if containers are hitting resource limits -- **Inspect container configuration**: `docker inspect ` for detailed container settings -- **Check container health**: `docker inspect | grep Health` if health checks are configured - -## Prometheus Metrics Analysis - -Use Prometheus metrics for real-time and historical performance data: - -For detailed setup instructions on configuring Prometheus and Grafana for Calls monitoring, see the {doc}`Calls Metrics and Monitoring ` guide. - -## When to Contact Support - -Consider contacting Mattermost Support when: - -1. You've tried troubleshooting steps without resolution -2. You're experiencing persistent connection failures across multiple clients -3. You notice unexpected or degraded performance despite proper configuration -4. You need help interpreting diagnostic information -5. You suspect a bug in the Calls plugin or RTCD service - -When contacting support, please include: - -- RTCD version and configuration (with sensitive information redacted) -- Mattermost server version -- Calls plugin version -- Client environments (browsers, OS versions) -- Relevant logs and diagnostic information -- Detailed description of the issue and steps to reproduce - -## Other Calls Documentation - -- [Calls Overview](calls-deployment.md): Overview of deployment options and architecture -- [RTCD Setup and Configuration](calls-rtcd-setup.md): Comprehensive guide for setting up the dedicated RTCD service -- [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription -- [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability -- [Calls Deployment on Kubernetes](calls-kubernetes.md): Detailed guide for deploying Calls in Kubernetes environments \ No newline at end of file +```{note} +Interpreting RTCD and client logs can be challenging, as the Interactive Connectivity Establishment (ICE) negotiation during call setup often logs expected and benign failure or error messages. We strongly recommend providing the complete set of logs to Mattermost Support for analysis. +``` \ No newline at end of file From 58027400d94cd19c0ca7c90e2f4c69da915f5089 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 17:43:32 -0400 Subject: [PATCH 51/60] Restart RTCD after the UDP port test --- source/administration-guide/configure/calls-rtcd-setup.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index 92f96cbd393..f433af151ef 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -315,6 +315,12 @@ After deploying RTCD, validate the installation: Type a message and hit Enter on either side. If messages are received on both ends, UDP connectivity is working. + Restart RTCD after the test: + + ```bash + sudo systemctl start rtcd + ``` + 3. **Test TCP connectivity** (if enabled): Similar to the UDP test, but remove the `-u` flag from both commands. From 939e77ffbc3b1b12fc343ef89489e37fdb2c4160 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 17:54:43 -0400 Subject: [PATCH 52/60] Simplify docker daemon config instructions --- scripts/air-gap-docker-registry-setup.sh | 2 ++ .../configure/calls-offloader-setup.md | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/air-gap-docker-registry-setup.sh b/scripts/air-gap-docker-registry-setup.sh index 52553102863..94e2e298838 100755 --- a/scripts/air-gap-docker-registry-setup.sh +++ b/scripts/air-gap-docker-registry-setup.sh @@ -218,6 +218,7 @@ configure_docker_daemon() { fi # Create new daemon.json with insecure registry configuration + # Note: If an existing daemon.json exists, these settings should be merged manually instead. cat > /tmp/daemon.json << EOF { "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] @@ -280,6 +281,7 @@ echo "Deploying Mattermost Calls in air-gapped environment..." # Configure Docker for local registry sudo mkdir -p /etc/docker +# Note: If an existing daemon.json exists, these settings should be merged manually instead. cat > /tmp/daemon.json << EOD { "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index d5d012e41ad..b01b56126bb 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -532,6 +532,9 @@ Transfer the following files to your air-gapped network: ```bash # Create or update Docker daemon configuration sudo mkdir -p /etc/docker + + # Note: If you already have an existing `/etc/docker/daemon.json` configuration, + # merge the `insecure-registries` key into it manually rather than overwriting. echo '{"insecure-registries": ["localhost:5000"]}' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker ``` @@ -560,7 +563,7 @@ For reference, here are the individual configuration steps: #### 1. Docker Daemon Configuration -Create or update `/etc/docker/daemon.json`: +Create or update `/etc/docker/daemon.json` (ensure you merge this into your existing configuration if the file already exists): ```json { "insecure-registries": ["localhost:5000"] @@ -689,6 +692,8 @@ If you want to run the registry on a different host, replace `localhost:5000` wi REGISTRY_HOST="registry.internal.domain:5000" # Update Docker daemon configuration +# Note: If you already have an existing `/etc/docker/daemon.json` configuration, +# merge the `insecure-registries` key into it manually rather than overwriting. echo "{\"insecure-registries\": [\"$REGISTRY_HOST\"]}" | sudo tee /etc/docker/daemon.json # Update calls-offloader configuration From 6d49b4d1e85486c3a1e1b61a5b3f6e3b62639b4a Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 18:11:42 -0400 Subject: [PATCH 53/60] Address remaining PR reviews --- scripts/air-gap-docker-registry-setup.sh | 16 ++++++++-------- .../configure/calls-offloader-setup.md | 19 ++++++++++--------- .../configure/calls-rtcd-setup.md | 10 ++++------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/scripts/air-gap-docker-registry-setup.sh b/scripts/air-gap-docker-registry-setup.sh index 94e2e298838..3f614e60da5 100755 --- a/scripts/air-gap-docker-registry-setup.sh +++ b/scripts/air-gap-docker-registry-setup.sh @@ -190,16 +190,16 @@ configure_calls_offloader() { echo "Configuring calls-offloader for local registry..." | tee -a $LOG_FILE # Create a modified calls-offloader config - if [ -f "/opt/calls-offloader/calls-offloader.toml" ]; then - sudo cp /opt/calls-offloader/calls-offloader.toml /opt/calls-offloader/calls-offloader.toml.backup + if [ -f "/opt/calls-offloader/config.toml" ]; then + sudo cp /opt/calls-offloader/config.toml /opt/calls-offloader/config.toml.backup # Update image_registry setting - sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/calls-offloader.toml + sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/config.toml echo "Updated calls-offloader configuration to use local registry" | tee -a $LOG_FILE - echo "Backup created at /opt/calls-offloader/calls-offloader.toml.backup" | tee -a $LOG_FILE + echo "Backup created at /opt/calls-offloader/config.toml.backup" | tee -a $LOG_FILE else - echo "Warning: calls-offloader.toml not found. You'll need to manually configure:" | tee -a $LOG_FILE + echo "Warning: config.toml not found. You'll need to manually configure:" | tee -a $LOG_FILE echo " image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" | tee -a $LOG_FILE fi } @@ -292,15 +292,15 @@ sudo systemctl restart docker sleep 10 # Update calls-offloader configuration -if [ -f "/opt/calls-offloader/calls-offloader.toml" ]; then - sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/calls-offloader.toml +if [ -f "/opt/calls-offloader/config.toml" ]; then + sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/config.toml # Restart calls-offloader service sudo systemctl restart calls-offloader echo "Calls-offloader configured for air-gap deployment" else - echo "Warning: /opt/calls-offloader/calls-offloader.toml not found" + echo "Warning: /opt/calls-offloader/config.toml not found" echo "Please manually configure image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" fi diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index b01b56126bb..63c2da5f70d 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -577,7 +577,7 @@ sudo systemctl restart docker #### 2. Calls-Offloader Configuration -Update `/opt/calls-offloader/calls-offloader.toml`: +Update `/opt/calls-offloader/config.toml`: ```toml [jobs] @@ -601,7 +601,8 @@ sudo systemctl restart calls-offloader curl http://localhost:5000/v2/_catalog # Test pulling an image -docker pull localhost:5000/mattermost/calls-recorder:latest +# Replace with the specific tag, e.g., v0.8.5 +docker pull localhost:5000/mattermost/calls-recorder: ``` #### Test Calls Functionality @@ -636,7 +637,7 @@ docker pull localhost:5000/mattermost/calls-recorder:latest 3. **calls-offloader fails to create jobs**: - Check calls-offloader logs: `sudo journalctl -u calls-offloader` - - Verify the `image_registry` configuration in calls-offloader.toml + - Verify the `image_registry` configuration in config.toml - Ensure the calls-offloader service can reach the registry 4. **"invalid Runner value: failed to validate runner" error**: @@ -650,16 +651,16 @@ docker pull localhost:5000/mattermost/calls-recorder:latest curl http://localhost:5000/v2/mattermost/calls-transcriber/tags/list ``` - - **Registry configuration mismatch**: Ensure the `image_registry` setting in calls-offloader.toml matches your registry: + - **Registry configuration mismatch**: Ensure the `image_registry` setting in config.toml matches your registry: ```bash - grep image_registry /opt/calls-offloader/calls-offloader.toml + grep image_registry /opt/calls-offloader/config.toml # Should show: image_registry = "localhost:5000/mattermost" ``` - - **Docker daemon can't reach registry**: Test that Docker can pull from the local registry: + - **Docker daemon can't reach registry**: Test that Docker can pull from the local registry (replace `` with the specific tags): ```bash - docker pull localhost:5000/mattermost/calls-recorder:latest - docker pull localhost:5000/mattermost/calls-transcriber:latest + docker pull localhost:5000/mattermost/calls-recorder: + docker pull localhost:5000/mattermost/calls-transcriber: ``` - **Image tag mismatch**: The calls-offloader will be looking for specific image tags. Check what the plugin expects vs what's in your registry: @@ -697,7 +698,7 @@ REGISTRY_HOST="registry.internal.domain:5000" echo "{\"insecure-registries\": [\"$REGISTRY_HOST\"]}" | sudo tee /etc/docker/daemon.json # Update calls-offloader configuration -sed -i "s|localhost:5000|$REGISTRY_HOST|g" /opt/calls-offloader/calls-offloader.toml +sed -i "s|localhost:5000|$REGISTRY_HOST|g" /opt/calls-offloader/config.toml ``` **Custom Image Versions** diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index f433af151ef..d8b077ca320 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -363,15 +363,13 @@ Once RTCD is properly set up and validated, configure Mattermost to use it: 1. Go to **System Console > Plugins > Calls** -2. Enable the **Enable RTCD Service** option +2. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname). Ensure you provide any generated credentials formulated in the URI (e.g., `http://clientID:authKey@rtcd.local`). For detailed capability/credential configuration, reference the [RTCD Service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtcd-service-url) documentation. -3. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname). Ensure you provide any generated credentials formulated in the URI (e.g., `http://clientID:authKey@rtcd.local`). For detailed capability/credential configuration, reference the [RTCD Service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtcd-service-url) documentation. +3. Save the configuration -4. Save the configuration +4. Test by creating a new call in any Mattermost channel -5. Test by creating a new call in any Mattermost channel - -6. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics +5. Verify that the call is being routed through RTCD by checking the RTCD logs and metrics ## Other Calls Documentation From 7c566e6df7b781c1158cbe715317e1078649a825 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Tue, 10 Mar 2026 18:14:19 -0400 Subject: [PATCH 54/60] Address CodeRabbit PR reviews (list numbering, typos, image names, and bash script control flow) --- scripts/air-gap-docker-registry-setup.sh | 5 +++-- .../administration-guide/configure/calls-offloader-setup.md | 2 +- source/administration-guide/configure/calls-rtcd-setup.md | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/air-gap-docker-registry-setup.sh b/scripts/air-gap-docker-registry-setup.sh index 3f614e60da5..6f09833c3ac 100755 --- a/scripts/air-gap-docker-registry-setup.sh +++ b/scripts/air-gap-docker-registry-setup.sh @@ -229,7 +229,7 @@ EOF # Restart Docker daemon echo "Restarting Docker daemon..." | tee -a $LOG_FILE - sudo systemctl restart docker >> $LOG_FILE 2>&1 + sudo systemctl restart docker 2>&1 | sudo tee -a "$LOG_FILE" >/dev/null # Wait for Docker to restart sleep 10 @@ -254,7 +254,7 @@ verify_setup() { curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/_catalog | jq '.repositories[]' 2>/dev/null || echo "Could not list repositories (jq not available)" | tee -a $LOG_FILE # Test pulling from local registry - test_image="$REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-offloader:latest" + test_image="$REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest" echo "Testing pull from local registry: $test_image" | tee -a $LOG_FILE if docker pull $test_image >> $LOG_FILE 2>&1; then echo "✓ Successfully pulled test image from local registry" | tee -a $LOG_FILE @@ -328,6 +328,7 @@ main() { # Check if we have internet access for image pulling if ! check_internet; then echo "Skipping image download phase - run this script with internet access first" | tee -a $LOG_FILE + exit 1 else # Setup local registry setup_registry diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index 63c2da5f70d..7d3348f392d 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -404,7 +404,7 @@ The following Docker images are needed for full calls functionality: #### Determining the Correct Image Versions -**Important**: The exact versions of `calls-offloader` and `calls-transcriber` images must match what your installed Calls plugin expects. These versions are defined in the Calls plugin source code. +**Important**: The exact versions of `mattermost/calls-recorder` and `mattermost/calls-transcriber` images must match what your installed Calls plugin expects. These versions are defined in the Calls plugin source code. To find the correct versions for your Calls plugin: diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index d8b077ca320..5b1ae729f62 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -86,7 +86,7 @@ The following network connectivity is required:
- + @@ -169,7 +169,7 @@ Looking for an automated setup? Check out these community-maintained [Calls Inst WantedBy=multi-user.target ``` -5. Enable and start the service: +6. Enable and start the service: ```bash sudo systemctl daemon-reload @@ -177,7 +177,7 @@ Looking for an automated setup? Check out these community-maintained [Calls Inst sudo systemctl start rtcd ``` -6. Check the service status: +7. Check the service status: ```bash sudo systemctl status rtcd From ec20cbeab1235211edf80f2ac0fc50657d8c6aa5 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Wed, 11 Mar 2026 10:28:26 -0400 Subject: [PATCH 55/60] Update Horizontal Scaling section to clarify Mattermost CPU-based load distribution --- source/administration-guide/configure/calls-rtcd-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index 5b1ae729f62..8788dfdb0ee 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -337,7 +337,7 @@ To scale RTCD horizontally: Deploy multiple RTCD servers, each with their own unique IP address. -2. **Configure DNS-based load balancing**: +2. **Configure DNS record**: Set up a DNS record that points to multiple RTCD IP addresses: @@ -355,7 +355,7 @@ To scale RTCD horizontally: In the Mattermost System Console, set the **RTCD Service URL** to your DNS name (e.g., `rtcd.example.com`). -The Mattermost Calls plugin will distribute calls among the available RTCD hosts. Remember that a single call will always be hosted on one RTCD instance; sessions belonging to the same call are not spread across different instances. +When a call starts, the Mattermost server examines the available RTCD servers (via the configured DNS record) and starts the call on the RTCD server with the lowest CPU usage. All participants in the call will connect to that RTCD server; a single call cannot be shared across multiple servers. ## Integration with Mattermost From ae365605659745f01de51e60191363c54c54af38 Mon Sep 17 00:00:00 2001 From: Stuart Doherty Date: Wed, 11 Mar 2026 10:53:48 -0400 Subject: [PATCH 56/60] Add mattermost/ prefix to image references --- .../administration-guide/configure/calls-offloader-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index 7d3348f392d..e93caebd60d 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -395,8 +395,8 @@ The following Docker images are needed for full calls functionality: ```{warning} **Disk Space Requirements**: Ensure you have sufficient disk space before starting the setup process. The Docker images can be quite large: -- **calls-recorder image**: ~1.5-2GB -- **calls-transcriber image**: ~1.5-2GB +- **mattermost/calls-recorder image**: ~1.5-2GB +- **mattermost/calls-transcriber image**: ~1.5-2GB - **Registry container + data**: ~500MB **Total recommended free space**: At least 5GB to accommodate image downloads, local registry data, and archive creation. From 563285422cf5c804a9b713596e5068044b7bfbb0 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Mon, 16 Mar 2026 13:42:13 -0400 Subject: [PATCH 57/60] Address PR feedback: content corrections across Calls docs - calls-offloader-setup: remove large sections of content per review - calls-kubernetes: remove inaccurate load balancer references, clarify DNS-based RTCD discovery - calls-deployment, calls-rtcd-setup: minor corrections Co-Authored-By: Claude Sonnet 4.6 --- .../configure/calls-deployment.md | 2 +- .../configure/calls-kubernetes.md | 12 +- .../configure/calls-offloader-setup.md | 595 +++--------------- .../configure/calls-rtcd-setup.md | 2 +- 4 files changed, 82 insertions(+), 529 deletions(-) diff --git a/source/administration-guide/configure/calls-deployment.md b/source/administration-guide/configure/calls-deployment.md index 78a9ea78128..e30424cd8d0 100644 --- a/source/administration-guide/configure/calls-deployment.md +++ b/source/administration-guide/configure/calls-deployment.md @@ -1,4 +1,4 @@ -# Calls Deployment Overview +# Deploy Mattermost Calls ```{include} ../../_static/badges/all-commercial.md ``` diff --git a/source/administration-guide/configure/calls-kubernetes.md b/source/administration-guide/configure/calls-kubernetes.md index 32656896203..5235d007d81 100644 --- a/source/administration-guide/configure/calls-kubernetes.md +++ b/source/administration-guide/configure/calls-kubernetes.md @@ -16,9 +16,8 @@ Mattermost Calls has been designed to integrate well with Kubernetes to offer im This diagram shows how the RTCD standalone service can be deployed in a Kubernetes cluster. In this architecture: 1. Calls traffic is handled by dedicated RTCD pods -2. RTCD services are exposed through load balancers -3. Scaling is managed through Kubernetes deployment configurations -4. Call recording and transcription is handled by the calls-offloader service (see [Calls Offloader Setup and Configuration](calls-offloader-setup.md)) +2. Scaling is managed through Kubernetes deployment configurations +3. Call recording and transcription is handled by the calls-offloader service (see [Calls Offloader Setup and Configuration](calls-offloader-setup.md)) If Mattermost isn't already deployed in your Kubernetes cluster and you want to use this deployment type, visit the [Kubernetes operator guide](/install/mattermost-kubernetes-operator.md). @@ -60,8 +59,7 @@ For Kubernetes deployments, you need to ensure specific connectivity paths: 1. **Client to RTCD connectivity**: UDP and TCP traffic on port 8443 is properly routed from clients to RTCD pods (for media, with TCP acting as a fallback). 2. **Mattermost to RTCD API connectivity**: There needs to be a clear connectivity path between Mattermost and RTCD on the API port (TCP 8045) -3. **Load balancer configuration**: Load balancers must be properly configured to handle UDP and TCP traffic routing to RTCD pods -4. **Network policies**: Network policies must allow the required communications between Mattermost and RTCD services +3. **Network policies**: Network policies must allow the required communications between Mattermost and RTCD services ### Resource Requirements @@ -74,8 +72,8 @@ We strongly recommend reviewing the [Performance Baselines](calls-metrics-monito Horizontal scaling of RTCD pods is possible, but remember: 1. Each call is hosted entirely on a single RTCD pod -2. DNS-based load balancing should be used to distribute calls among pods -3. Health checks should ensure that only healthy pods receive new calls +2. DNS A records should be set up for all RTCD pods so server can discover RTCD servers. +3. Health checks should ensure that only healthy pods are reported via DNS 4. Calls remain on their assigned pod for their entire duration ### Limitations diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index e93caebd60d..04be82236fc 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -192,7 +192,7 @@ In such cases, you can override the site URL used by recorder jobs or transcribe ```{note} When these Site URL overrides are used, the `ServiceSettings.AllowCorsFrom` setting on your Mattermost server may need to be adjusted accordingly to ensure CORS does not block requests. -Additionally, this override configuration is particularly useful if your Mattermost public Site URL uses HTTPS, because pointing the offloader directly to an internal HTTP endpoint bypasses the need to deal with client-side certificates. +This override configuration lets the recorder and transcriber jobs connect to mattermost server using HTTP instead of HTTPS, which should only be used in a private network. ``` Example configuration: @@ -370,571 +370,126 @@ tail -f /opt/calls-offloader/calls-offloader.log Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.md) for details on setting up metrics and observability. -## Air-Gapped Deployments +# Air-Gapped Installation of `calls-offloader` -When deploying calls-offloader in air-gapped environments, you need to set up a local Docker registry since the service creates Docker containers that normally pull images from Docker Hub. +This guide covers deploying `calls-offloader` in an environment without internet access. The process uses scripts from the [calls-install-scripts](https://github.com/bgardner8008/calls-install-scripts) repository and follows a two-phase workflow: preparing a transfer bundle on an internet-connected machine, then deploying it on the isolated target machine. -### Overview - -The calls-offloader service creates Docker containers to handle: -- **Call Recording**: Creates containers to record audio/video from calls -- **Call Transcription / Live Captioning**: Creates containers to transcribe recorded calls and produce live captions using speech-to-text - -These containers are typically pulled from the `mattermost` registry on Docker Hub, but in air-gapped networks, you need to: -1. Set up a local Docker registry -2. Pre-load the required Docker images -3. Configure the calls-offloader to use the local registry - -### Required Docker Images - -The following Docker images are needed for full calls functionality: - -- `mattermost/calls-recorder:v0.8.5` (or version matching your plugin) -- `mattermost/calls-transcriber:v0.6.3` (or version matching your plugin) -- `registry:2` (for the local Docker registry) - -```{warning} -**Disk Space Requirements**: Ensure you have sufficient disk space before starting the setup process. The Docker images can be quite large: -- **mattermost/calls-recorder image**: ~1.5-2GB -- **mattermost/calls-transcriber image**: ~1.5-2GB -- **Registry container + data**: ~500MB - -**Total recommended free space**: At least 5GB to accommodate image downloads, local registry data, and archive creation. -``` - -#### Determining the Correct Image Versions - -**Important**: The exact versions of `mattermost/calls-recorder` and `mattermost/calls-transcriber` images must match what your installed Calls plugin expects. These versions are defined in the Calls plugin source code. - -To find the correct versions for your Calls plugin: - -1. **Determine your Calls plugin version**: - - In Mattermost, go to **System Console > Plugins > Plugin Management** - - Find the **Calls** plugin and note the version number (e.g., `v1.9.0`) - -2. **Look up the required image versions**: - - Visit the Calls plugin repository: https://github.com/mattermost/mattermost-plugin-calls - - Navigate to the tag or branch corresponding to your plugin version - - Open the `plugin.json` file - - Find the `calls_recorder_version` and `calls_transcriber_version` entries (located near the bottom of the file). - - Example from plugin.json: - ```json - "calls_recorder_version": "v0.8.8", - "calls_transcriber_version": "v0.7.1" - ``` +## Overview -3. **Use these exact versions** in your air-gap setup instead of `latest` tags +Because `calls-offloader` relies on Docker images for the recorder and transcriber jobs, an air-gapped deployment requires that those images be pre-pulled and packaged alongside the `calls-offloader` binary before being transferred to the target environment. -**Direct link format**: For plugin version `v1.9.0`, the plugin.json would be at: -`https://github.com/mattermost/mattermost-plugin-calls/blob/v1.9.0/plugin.json` +The install scripts handle this in two stages: -### Setup Process +1. **Prepare** (internet-connected machine) — `setup-airgap-offloader.sh` pulls the required Docker images and downloads the `calls-offloader` binary, then packages everything into a transfer bundle and generates a ready-to-run deployment script. +2. **Deploy** (air-gapped machine) — Transfer the bundle and run the generated `deploy-airgap-offloader.sh` script, which loads the Docker images into a local registry and installs the service. -#### Phase 1: Preparation (Internet-Connected Environment) +## Prerequisites -Run this phase on a machine with internet access to download and prepare the Docker images. +- An internet-connected Linux machine with Docker installed (for the preparation phase) +- A target air-gapped Linux machine with: + - systemd + - Docker installed + - Root or sudo access +- The [calls-install-scripts](https://github.com/bgardner8008/calls-install-scripts) repository cloned on the internet-connected machine -**Automated Setup Script** +## Phase 1: Prepare the Transfer Bundle -For convenience, you can use the automated setup script: +On the **internet-connected machine**, run `setup-airgap-offloader.sh` specifying the versions of each component to package: ```bash -# Download the setup script -curl -O https://docs.mattermost.com/scripts/air-gap-docker-registry-setup.sh -chmod +x air-gap-docker-registry-setup.sh - -# Run the setup script with the required image versions -sudo ./air-gap-docker-registry-setup.sh -``` - -The script will automatically create the required archive files (`docker-registry-data.tar.gz` and `registry-image.tar.gz`) for transfer to your air-gapped environment. - -**Manual Setup Steps** - -If you prefer to set up manually or need to customize the process: - -1. **Set up a local Docker registry**: - ```bash - # Create registry data directory - sudo mkdir -p /opt/docker-registry/data - - # Start a local Docker registry - docker run -d \ - --name local-registry \ - --restart=always \ - -p 5000:5000 \ - -v /opt/docker-registry/data:/var/lib/registry \ - registry:2 - ``` - -2. **Download and push required images**: - ```bash - # Pull required images from Docker Hub - docker pull mattermost/calls-recorder:v0.8.5 - docker pull mattermost/calls-transcriber:v0.6.3 - - # Tag images for local registry - docker tag mattermost/calls-recorder:v0.8.5 localhost:5000/mattermost/calls-recorder:v0.8.5 - docker tag mattermost/calls-transcriber:v0.6.3 localhost:5000/mattermost/calls-transcriber:v0.6.3 - - # Push images to local registry - docker push localhost:5000/mattermost/calls-recorder:v0.8.5 - docker push localhost:5000/mattermost/calls-transcriber:v0.6.3 - ``` - -3. **Export the registry data**: - ```bash - # Create an archive of the registry data - sudo tar -czf docker-registry-data.tar.gz -C /opt/docker-registry/data . - - # Also backup the registry container image - docker save registry:2 | gzip > registry-image.tar.gz - ``` - -#### Phase 2: Air-Gap Deployment - -Transfer the following files to your air-gapped network: -- `docker-registry-data.tar.gz` (contains the registry data with pre-loaded images) -- `registry-image.tar.gz` (contains the Docker registry container image) -- `deploy-airgap-calls.sh` (deployment script created by the setup script) - -**Complete Air-Gap Deployment Steps:** - -1. **Load the registry container image**: - ```bash - # Extract and load the registry container from the gzipped archive - gunzip registry-image.tar.gz - docker load -i registry-image.tar - ``` - -2. **Set up the registry data directory**: - ```bash - # Create the registry data directory - sudo mkdir -p /opt/docker-registry/data - - # Extract the pre-loaded registry data - sudo tar -xzf docker-registry-data.tar.gz -C /opt/docker-registry/data - ``` - -3. **Start the local registry with pre-loaded data**: - ```bash - # Start the registry container with the extracted data - docker run -d \ - --name local-registry \ - --restart=always \ - -p 5000:5000 \ - -v /opt/docker-registry/data:/var/lib/registry \ - registry:2 - ``` - -4. **Configure Docker daemon for insecure registry access**: - ```bash - # Create or update Docker daemon configuration - sudo mkdir -p /etc/docker - - # Note: If you already have an existing `/etc/docker/daemon.json` configuration, - # merge the `insecure-registries` key into it manually rather than overwriting. - echo '{"insecure-registries": ["localhost:5000"]}' | sudo tee /etc/docker/daemon.json - sudo systemctl restart docker - ``` - -5. **Configure Mattermost server environment variable**: - ```bash - # Add the registry configuration to Mattermost environment - echo 'MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY="localhost:5000/mattermost"' | sudo tee -a /opt/mattermost/config/mattermost.environment - - # Restart Mattermost to apply the environment variable - sudo systemctl restart mattermost - ``` - -6. **Run the air-gap deployment script** (if using the automated setup): - ```bash - # Make the deployment script executable and run it - chmod +x deploy-airgap-calls.sh - sudo ./deploy-airgap-calls.sh - ``` - - Or configure calls-offloader manually (see Manual Configuration section below). - -### Manual Configuration - -For reference, here are the individual configuration steps: - -#### 1. Docker Daemon Configuration - -Create or update `/etc/docker/daemon.json` (ensure you merge this into your existing configuration if the file already exists): -```json -{ - "insecure-registries": ["localhost:5000"] -} +./setup-airgap-offloader.sh \ + --offloader v0.9.5 \ + --recorder v0.9.0 \ + --transcriber v0.3.0 \ + --arch amd64 ``` -Restart Docker: -```bash -sudo systemctl restart docker -``` +| Flag | Description | Default | +|------|-------------|---------| +| `--offloader VERSION` | `calls-offloader` binary version (e.g. `v0.9.5`) | required | +| `--recorder VERSION` | `calls-recorder` Docker image version | required | +| `--transcriber VERSION` | `calls-transcriber` Docker image version | required | +| `--arch amd64\|arm64` | Target CPU architecture | `amd64` | -#### 2. Calls-Offloader Configuration +The script will: -Update `/opt/calls-offloader/config.toml`: +1. Pull the `calls-recorder` and `calls-transcriber` Docker images from Docker Hub +2. Download the `calls-offloader` binary from GitHub releases +3. Save the Docker images as `.tar` archives +4. Generate a `deploy-airgap-offloader.sh` deployment script configured for the selected versions +5. Produce a transfer bundle containing all of the above -```toml -[jobs] -# Change this line: -image_registry = "mattermost" +## Phase 2: Transfer to the Air-Gapped Machine -# To this: -image_registry = "localhost:5000/mattermost" -``` +Copy the generated bundle to the target machine using whatever transfer mechanism is available in your environment (USB drive, secure file transfer, etc.): -Restart the calls-offloader service: ```bash -sudo systemctl restart calls-offloader +scp calls-offloader-airgap-bundle.tar.gz user@airgap-host:/tmp/ ``` -### Verification +On the air-gapped machine, extract the bundle: -#### Test Registry Access ```bash -# List available repositories -curl http://localhost:5000/v2/_catalog - -# Test pulling an image -# Replace with the specific tag, e.g., v0.8.5 -docker pull localhost:5000/mattermost/calls-recorder: +tar -xzf calls-offloader-airgap-bundle.tar.gz +cd calls-offloader-airgap-bundle/ ``` -#### Test Calls Functionality - -1. **Check calls-offloader logs**: - ```bash - sudo journalctl -u calls-offloader -f - ``` - -2. **Verify calls-offloader API**: - ```bash - curl http://localhost:4545/version - ``` - -3. **Test recording job creation** (requires proper Mattermost integration): - - Start a call in Mattermost - - Enable recording - - Check that Docker containers are created for recording jobs - -### Troubleshooting Air-Gap Deployments - -#### Common Issues - -1. **Registry not accessible**: - - Check that the registry container is running: `docker ps | grep registry` - - Verify Docker daemon configuration includes insecure registry - - Check firewall settings on port 5000 - -2. **Image pull failures**: - - Verify images are in the registry: `curl http://localhost:5000/v2/_catalog` - - Check Docker daemon logs: `sudo journalctl -u docker` - -3. **calls-offloader fails to create jobs**: - - Check calls-offloader logs: `sudo journalctl -u calls-offloader` - - Verify the `image_registry` configuration in config.toml - - Ensure the calls-offloader service can reach the registry +## Phase 3: Deploy on the Air-Gapped Machine -4. **"invalid Runner value: failed to validate runner" error**: - This error occurs when calls-offloader cannot validate Docker images from the local registry. - - **Common causes and solutions:** - - **Image not found**: Verify the exact image names and tags in your local registry: - ```bash - curl http://localhost:5000/v2/_catalog - curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list - curl http://localhost:5000/v2/mattermost/calls-transcriber/tags/list - ``` - - - **Registry configuration mismatch**: Ensure the `image_registry` setting in config.toml matches your registry: - ```bash - grep image_registry /opt/calls-offloader/config.toml - # Should show: image_registry = "localhost:5000/mattermost" - ``` - - - **Docker daemon can't reach registry**: Test that Docker can pull from the local registry (replace `` with the specific tags): - ```bash - docker pull localhost:5000/mattermost/calls-recorder: - docker pull localhost:5000/mattermost/calls-transcriber: - ``` - - - **Image tag mismatch**: The calls-offloader will be looking for specific image tags. Check what the plugin expects vs what's in your registry: - ```bash - # Check what tags are available - curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list - # Compare with what your plugin.json specifies - ``` - - **Solution steps:** - 1. Restart calls-offloader after confirming registry configuration: `sudo systemctl restart calls-offloader` - 2. If the issue persists, check the exact image names and versions expected by your Calls plugin version - 3. Ensure both versioned tags (e.g., `v0.8.5`) and `latest` tags are present in your local registry - -#### Log Locations - -- Setup script logs: `/tmp/air-gap-registry-setup.log` -- calls-offloader logs: `/opt/calls-offloader/calls-offloader.log` -- Docker daemon logs: `sudo journalctl -u docker` -- Registry container logs: `docker logs local-registry` - -#### Advanced Configuration - -**Using a Different Registry Host** - -If you want to run the registry on a different host, replace `localhost:5000` with your registry host in all commands: +Run the generated deployment script with root or sudo privileges: ```bash -# Example: using a dedicated registry server -REGISTRY_HOST="registry.internal.domain:5000" - -# Update Docker daemon configuration -# Note: If you already have an existing `/etc/docker/daemon.json` configuration, -# merge the `insecure-registries` key into it manually rather than overwriting. -echo "{\"insecure-registries\": [\"$REGISTRY_HOST\"]}" | sudo tee /etc/docker/daemon.json - -# Update calls-offloader configuration -sed -i "s|localhost:5000|$REGISTRY_HOST|g" /opt/calls-offloader/config.toml +sudo ./deploy-airgap-offloader.sh ``` -**Custom Image Versions** +This script will: -To use specific versions of the calls images, update the version tags in the docker commands: +1. Configure the local Docker daemon to use a local image registry +2. Load the packaged Docker images into that registry +3. Install the `calls-offloader` binary to `/usr/local/bin/` +4. Create the `mattermost` system user and add it to the `docker` group +5. Generate and enable a systemd service unit +6. Start the service and verify it is running -```bash -# Example: using specific versions -RECORDER_VERSION="v0.8.5" -TRANSCRIBER_VERSION="v0.6.3" +Once complete, verify the service is up: -docker pull mattermost/calls-recorder:$RECORDER_VERSION -docker pull mattermost/calls-transcriber:$TRANSCRIBER_VERSION +```bash +curl http://localhost:4545/version ``` -### Day 2 Operations: Upgrading Images in Air-Gap Environments - -When you upgrade your Mattermost Calls plugin to a newer version, you'll need to update the Docker images in your air-gapped registry to match the new plugin requirements. - -#### Upgrade Process Overview - -**When to upgrade**: After upgrading the Calls plugin in Mattermost, you must update the Docker images to match the versions expected by the new plugin version. - -**Two approaches available**: - -1. **Complete Rebuild Method**: Re-run the entire air-gap setup process with new image versions -2. **Incremental Update Method**: Transfer only the new images to minimize data transfer - -#### Method 1: Complete Rebuild (Recommended for Major Updates) - -This approach rebuilds the entire registry dataset with new image versions: - -1. **On internet-connected machine**, run the air-gap setup script with new versions: - ```bash - # Find new versions from your updated plugin.json - ./air-gap-docker-registry-setup.sh v0.8.5 v0.6.3 - ``` - -2. **Transfer new archives** to air-gapped environment: - - `docker-registry-data.tar.gz` (contains all images including new versions) - - `deploy-airgap-calls.sh` (updated deployment script) - -3. **In air-gapped environment**, replace the registry data: - ```bash - # Stop the existing registry - docker stop local-registry - docker rm local-registry - - # Backup existing data (optional) - sudo mv /opt/docker-registry/data /opt/docker-registry/data.backup - - # Extract new registry data - sudo mkdir -p /opt/docker-registry/data - sudo tar -xzf docker-registry-data.tar.gz -C /opt/docker-registry/data - - # Restart registry with new data - docker run -d \ - --name local-registry \ - --restart=always \ - -p 5000:5000 \ - -v /opt/docker-registry/data:/var/lib/registry \ - registry:2 - ``` - -#### Method 2: Incremental Update (Efficient for Minor Updates) - -This approach transfers only the new image versions without rebuilding the entire registry: - -**Phase 1: Preparation (Internet-Connected Environment)** - -1. **Download new images**: - ```bash - # Determine new versions from updated plugin.json - NEW_RECORDER_VERSION="v0.8.5" - NEW_TRANSCRIBER_VERSION="v0.6.3" - - # Pull new images - docker pull mattermost/calls-recorder:$NEW_RECORDER_VERSION - docker pull mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION - ``` - -2. **Create individual image archives**: - ```bash - # Save each image as a separate tar file - docker save mattermost/calls-recorder:$NEW_RECORDER_VERSION -o calls-recorder-$NEW_RECORDER_VERSION.tar - docker save mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION -o calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar - - # Compress the files for transfer - gzip calls-recorder-$NEW_RECORDER_VERSION.tar - gzip calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar - ``` - -3. **Create update script**: - ```bash - cat > update-air-gap-images.sh << 'EOF' - #!/bin/bash - - # Air-Gap Image Update Script - set -e - - NEW_RECORDER_VERSION="v0.8.5" - NEW_TRANSCRIBER_VERSION="v0.6.3" - REGISTRY_HOST="${REGISTRY_HOST:-localhost}" - REGISTRY_PORT="${REGISTRY_PORT:-5000}" - - echo "Updating air-gap registry with new image versions..." - echo "Recorder: $NEW_RECORDER_VERSION" - echo "Transcriber: $NEW_TRANSCRIBER_VERSION" - - # Load new images into Docker - echo "Loading new images..." - gunzip calls-recorder-$NEW_RECORDER_VERSION.tar.gz - gunzip calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar.gz - - docker load -i calls-recorder-$NEW_RECORDER_VERSION.tar - docker load -i calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar - - # Tag images for local registry - echo "Tagging images for local registry..." - docker tag mattermost/calls-recorder:$NEW_RECORDER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:$NEW_RECORDER_VERSION - docker tag mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION - - # Also update 'latest' tags - docker tag mattermost/calls-recorder:$NEW_RECORDER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest - docker tag mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:latest - - # Push to local registry - echo "Pushing images to local registry..." - docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:$NEW_RECORDER_VERSION - docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:$NEW_TRANSCRIBER_VERSION - docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest - docker push $REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-transcriber:latest - - echo "Image update complete!" - echo "" - echo "Verification commands:" - echo "curl http://$REGISTRY_HOST:$REGISTRY_PORT/v2/mattermost/calls-recorder/tags/list" - echo "curl http://$REGISTRY_HOST:$REGISTRY_PORT/v2/mattermost/calls-transcriber/tags/list" - - # Clean up temporary files - rm calls-recorder-$NEW_RECORDER_VERSION.tar - rm calls-transcriber-$NEW_TRANSCRIBER_VERSION.tar - - echo "" - echo "Next steps:" - echo "1. Restart calls-offloader service: sudo systemctl restart calls-offloader" - echo "2. Test call recording functionality to verify the update" - EOF - - chmod +x update-air-gap-images.sh - ``` +## Connecting to Mattermost -**Phase 2: Air-Gap Update** +Configure the Mattermost Calls plugin to use the offloader service via **System Console > Plugins > Calls > Job service URL**, setting it to `http://:4545`. -1. **Transfer files to air-gapped environment**: - - `calls-recorder-v0.8.5.tar.gz` - - `calls-transcriber-v0.6.3.tar.gz` - - `update-air-gap-images.sh` +> [!NOTE] +> The first time Mattermost connects to the offloader it will self-register and store its authentication key in the database, provided `API_SECURITY_ALLOWSELFREGISTRATION=true` is set (the default in the deployment script). -2. **Run the update script**: - ```bash - chmod +x update-air-gap-images.sh - sudo ./update-air-gap-images.sh - ``` +## Private Network Considerations -3. **Restart calls-offloader**: - ```bash - sudo systemctl restart calls-offloader - ``` +In air-gapped environments the recorder and transcriber containers typically need to reach the Mattermost server via an internal URL. Set the following environment variables on the **Mattermost server** to override the site URL used by spawned jobs: -4. **Verify the update**: - ```bash - # Check available image tags - curl http://localhost:5000/v2/mattermost/calls-recorder/tags/list - curl http://localhost:5000/v2/mattermost/calls-transcriber/tags/list - - # Test calls-offloader functionality - curl http://localhost:4545/version - ``` - -#### Advantages of Each Method - -**Complete Rebuild Method:** -- ✅ Ensures clean state with no leftover data -- ✅ Recommended for major version upgrades -- ✅ Simpler process (reuse existing automation) -- ❌ Larger data transfer requirements -- ❌ More downtime during registry replacement - -**Incremental Update Method:** -- ✅ Minimal data transfer (only new images) -- ✅ Faster deployment process -- ✅ Preserves existing registry data -- ✅ Less downtime (registry stays running) -- ❌ More complex process -- ❌ Potential for version conflicts if not managed carefully - -#### Choosing the Right Method - -**Use Complete Rebuild when:** -- Upgrading across major plugin versions (e.g., v1.8.x to v1.9.x) -- Registry has accumulated significant old/unused images -- You want to ensure a completely clean state -- Data transfer size is not a primary concern - -**Use Incremental Update when:** -- Applying minor version updates (e.g., v1.9.0 to v1.9.1) -- Bandwidth or transfer time is limited -- You need to minimize downtime -- The registry is working correctly and just needs new image versions +``` +MM_CALLS_RECORDER_SITE_URL=http://internal-mattermost-server:8065 +MM_CALLS_TRANSCRIBER_SITE_URL=http://internal-mattermost-server:8065 +``` -#### Post-Update Verification +You may also need to add the internal URL to [`ServiceSettings.AllowCorsFrom`](https://docs.mattermost.com/configure/integrations-configuration-settings.html#enable-cross-origin-requests-from) in the Mattermost server configuration. -After either upgrade method, perform these verification steps: +> [!NOTE] +> In particularly restrictive environments (e.g., VMs with strict network isolation), set `DOCKER_NETWORK=host` in the `calls-offloader` service environment so that job containers can reach the Mattermost server via its local address. -1. **Test recording functionality**: - - Start a call in Mattermost - - Enable call recording - - Verify recording starts without errors +## Custom Docker Registry -2. **Check job container creation**: - ```bash - # Monitor for new job containers during recording - docker ps --format "{{.ID}} {{.Image}}" | grep calls - ``` +If your air-gapped environment already has an internal Docker registry, you can point `install-offloader.sh` at it directly instead of using the local registry set up by the deployment script: -3. **Monitor calls-offloader logs**: - ```bash - sudo journalctl -u calls-offloader -f - ``` +```bash +sudo ./install-offloader.sh \ + --binary ./calls-offloader-linux-amd64 \ + --image-registry registry.internal.example.com/mattermost \ + --arch amd64 +``` -4. **Verify image versions**: - ```bash - # Check that the new image versions are being used - docker ps --format "{{.Image}}" | grep calls - ``` +The `--image-registry` flag sets the registry prefix used when the offloader pulls recorder and transcriber images for each job. ## Other Calls Documentation diff --git a/source/administration-guide/configure/calls-rtcd-setup.md b/source/administration-guide/configure/calls-rtcd-setup.md index 8788dfdb0ee..52099fca473 100644 --- a/source/administration-guide/configure/calls-rtcd-setup.md +++ b/source/administration-guide/configure/calls-rtcd-setup.md @@ -363,7 +363,7 @@ Once RTCD is properly set up and validated, configure Mattermost to use it: 1. Go to **System Console > Plugins > Calls** -2. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname). Ensure you provide any generated credentials formulated in the URI (e.g., `http://clientID:authKey@rtcd.local`). For detailed capability/credential configuration, reference the [RTCD Service URL](https://docs.mattermost.com/configure/plugins-configuration-settings.html#rtcd-service-url) documentation. +2. Set the **RTCD Service URL** to your RTCD service address (either a single server or DNS load-balanced hostname). Ensure you provide any generated credentials formulated in the URI (e.g., `http://clientID:authKey@rtcd.local`). 3. Save the configuration From b52328c0b2b467918815aa8d7fbe9073dd1659f5 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Mon, 16 Mar 2026 14:57:42 -0400 Subject: [PATCH 58/60] Bump air-gapped section headers down one level Co-Authored-By: Claude Sonnet 4.6 --- .../configure/calls-offloader-setup.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/administration-guide/configure/calls-offloader-setup.md b/source/administration-guide/configure/calls-offloader-setup.md index 04be82236fc..a3e32e6bf87 100644 --- a/source/administration-guide/configure/calls-offloader-setup.md +++ b/source/administration-guide/configure/calls-offloader-setup.md @@ -370,11 +370,11 @@ tail -f /opt/calls-offloader/calls-offloader.log Monitor calls-offloader performance and resource usage to ensure optimal operation. See [Calls Metrics and Monitoring](calls-metrics-monitoring.md) for details on setting up metrics and observability. -# Air-Gapped Installation of `calls-offloader` +## Air-Gapped Installation of `calls-offloader` This guide covers deploying `calls-offloader` in an environment without internet access. The process uses scripts from the [calls-install-scripts](https://github.com/bgardner8008/calls-install-scripts) repository and follows a two-phase workflow: preparing a transfer bundle on an internet-connected machine, then deploying it on the isolated target machine. -## Overview +### Overview Because `calls-offloader` relies on Docker images for the recorder and transcriber jobs, an air-gapped deployment requires that those images be pre-pulled and packaged alongside the `calls-offloader` binary before being transferred to the target environment. @@ -383,7 +383,7 @@ The install scripts handle this in two stages: 1. **Prepare** (internet-connected machine) — `setup-airgap-offloader.sh` pulls the required Docker images and downloads the `calls-offloader` binary, then packages everything into a transfer bundle and generates a ready-to-run deployment script. 2. **Deploy** (air-gapped machine) — Transfer the bundle and run the generated `deploy-airgap-offloader.sh` script, which loads the Docker images into a local registry and installs the service. -## Prerequisites +### Prerequisites - An internet-connected Linux machine with Docker installed (for the preparation phase) - A target air-gapped Linux machine with: @@ -392,7 +392,7 @@ The install scripts handle this in two stages: - Root or sudo access - The [calls-install-scripts](https://github.com/bgardner8008/calls-install-scripts) repository cloned on the internet-connected machine -## Phase 1: Prepare the Transfer Bundle +### Phase 1: Prepare the Transfer Bundle On the **internet-connected machine**, run `setup-airgap-offloader.sh` specifying the versions of each component to package: @@ -419,7 +419,7 @@ The script will: 4. Generate a `deploy-airgap-offloader.sh` deployment script configured for the selected versions 5. Produce a transfer bundle containing all of the above -## Phase 2: Transfer to the Air-Gapped Machine +### Phase 2: Transfer to the Air-Gapped Machine Copy the generated bundle to the target machine using whatever transfer mechanism is available in your environment (USB drive, secure file transfer, etc.): @@ -434,7 +434,7 @@ tar -xzf calls-offloader-airgap-bundle.tar.gz cd calls-offloader-airgap-bundle/ ``` -## Phase 3: Deploy on the Air-Gapped Machine +### Phase 3: Deploy on the Air-Gapped Machine Run the generated deployment script with root or sudo privileges: @@ -457,14 +457,14 @@ Once complete, verify the service is up: curl http://localhost:4545/version ``` -## Connecting to Mattermost +### Connecting to Mattermost Configure the Mattermost Calls plugin to use the offloader service via **System Console > Plugins > Calls > Job service URL**, setting it to `http://:4545`. > [!NOTE] > The first time Mattermost connects to the offloader it will self-register and store its authentication key in the database, provided `API_SECURITY_ALLOWSELFREGISTRATION=true` is set (the default in the deployment script). -## Private Network Considerations +### Private Network Considerations In air-gapped environments the recorder and transcriber containers typically need to reach the Mattermost server via an internal URL. Set the following environment variables on the **Mattermost server** to override the site URL used by spawned jobs: @@ -478,7 +478,7 @@ You may also need to add the internal URL to [`ServiceSettings.AllowCorsFrom`](h > [!NOTE] > In particularly restrictive environments (e.g., VMs with strict network isolation), set `DOCKER_NETWORK=host` in the `calls-offloader` service environment so that job containers can reach the Mattermost server via its local address. -## Custom Docker Registry +### Custom Docker Registry If your air-gapped environment already has an internal Docker registry, you can point `install-offloader.sh` at it directly instead of using the local registry set up by the deployment script: From ad52a6516a83cb54cd57b2fb7a6b1bc751fd7314 Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Mon, 16 Mar 2026 16:10:10 -0400 Subject: [PATCH 59/60] Fix stray numbered list item in calls-kubernetes Other Calls Documentation Co-Authored-By: Claude Sonnet 4.6 --- source/administration-guide/configure/calls-kubernetes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/administration-guide/configure/calls-kubernetes.md b/source/administration-guide/configure/calls-kubernetes.md index 5235d007d81..79967cb17f6 100644 --- a/source/administration-guide/configure/calls-kubernetes.md +++ b/source/administration-guide/configure/calls-kubernetes.md @@ -108,4 +108,4 @@ For detailed troubleshooting steps, see the [Calls Troubleshooting](calls-troubl - [Calls Offloader Setup and Configuration](calls-offloader-setup.md): Setup guide for call recording and transcription - [Calls Metrics and Monitoring](calls-metrics-monitoring.md): Guide to monitoring Calls performance using metrics and observability - [Calls Troubleshooting](calls-troubleshooting.md): Detailed troubleshooting steps and debugging techniques -3. If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.md) \ No newline at end of file +- If you encounter issues, see [Calls Troubleshooting](calls-troubleshooting.md) \ No newline at end of file From f6ccb6bc2e32492457f076b8d07e4bad5b6e4dcb Mon Sep 17 00:00:00 2001 From: Stu Doherty Date: Tue, 17 Mar 2026 11:14:36 -0400 Subject: [PATCH 60/60] Remove air-gap-docker-registry-setup.sh script Superseded by the calls-install-scripts repo approach documented in calls-offloader-setup.md. Script was unreferenced in the docs source. Co-Authored-By: Claude Sonnet 4.6 --- scripts/air-gap-docker-registry-setup.sh | 369 ----------------------- 1 file changed, 369 deletions(-) delete mode 100755 scripts/air-gap-docker-registry-setup.sh diff --git a/scripts/air-gap-docker-registry-setup.sh b/scripts/air-gap-docker-registry-setup.sh deleted file mode 100755 index 6f09833c3ac..00000000000 --- a/scripts/air-gap-docker-registry-setup.sh +++ /dev/null @@ -1,369 +0,0 @@ -#!/bin/bash - -# Air-Gap Docker Registry Setup for Mattermost Calls Offloader -# This script sets up a local Docker registry and pre-loads required images -# for air-gapped network deployments -# -# Usage: ./air-gap-docker-registry-setup.sh -# Example: ./air-gap-docker-registry-setup.sh v0.8.5 v0.6.3 - -set -e - -# Function to display usage -usage() { - echo "Usage: $0 " - echo "" - echo "Arguments:" - echo " recorder-version Version of mattermost/calls-recorder image (e.g., v0.8.5)" - echo " transcriber-version Version of mattermost/calls-transcriber image (e.g., v0.6.3)" - echo "" - echo "Examples:" - echo " $0 v0.8.5 v0.6.3" - echo " $0 v0.9.0 v0.7.0" - echo "" - echo "To find the correct versions for your Calls plugin:" - echo "1. Check your Calls plugin version in System Console > Plugins > Plugin Management" - echo "2. Visit: https://github.com/mattermost/mattermost-plugin-calls/blob/v/plugin.json" - echo "3. Look for 'RecorderImage' and 'TranscriberImage' entries (near the bottom)" - echo "" - echo "Environment variables (optional):" - echo " REGISTRY_HOST Docker registry host (default: localhost)" - echo " REGISTRY_PORT Docker registry port (default: 5000)" - echo " REGISTRY_DATA_DIR Registry data directory (default: /opt/docker-registry/data)" - exit 1 -} - -# Check if required arguments are provided -if [ $# -ne 2 ]; then - echo "ERROR: Missing required arguments" - echo "" - usage -fi - -# Validate version format (should start with 'v' followed by semantic version) -validate_version() { - local version=$1 - local image_name=$2 - - if [[ ! $version =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "ERROR: Invalid version format for $image_name: $version" - echo "Expected format: vX.Y.Z (e.g., v0.8.5)" - exit 1 - fi -} - -# Parse and validate arguments -CALLS_RECORDER_VERSION="$1" -CALLS_TRANSCRIBER_VERSION="$2" - -validate_version "$CALLS_RECORDER_VERSION" "calls-recorder" -validate_version "$CALLS_TRANSCRIBER_VERSION" "calls-transcriber" - -# Configuration variables -REGISTRY_HOST="${REGISTRY_HOST:-localhost}" -REGISTRY_PORT="${REGISTRY_PORT:-5000}" -REGISTRY_DATA_DIR="${REGISTRY_DATA_DIR:-/opt/docker-registry/data}" -REGISTRY_CONFIG_DIR="${REGISTRY_CONFIG_DIR:-/opt/docker-registry/config}" - -LOG_FILE=/tmp/air-gap-registry-setup.log - -echo "Setting up Air-Gap Docker Registry for Mattermost Calls" | tee $LOG_FILE -echo "Recorder version: $CALLS_RECORDER_VERSION" | tee -a $LOG_FILE -echo "Transcriber version: $CALLS_TRANSCRIBER_VERSION" | tee -a $LOG_FILE - -# Function to check if running with internet access (for image pulling phase) -check_internet() { - if ! curl -s --connect-timeout 5 https://hub.docker.com > /dev/null 2>&1; then - echo "ERROR: This script requires internet access during the image preparation phase." | tee -a $LOG_FILE - echo "Please run this script on a machine with internet access first, then transfer the images." | tee -a $LOG_FILE - return 1 - fi -} - -# Function to setup local Docker registry -setup_registry() { - echo "Setting up local Docker registry..." | tee -a $LOG_FILE - - # Create directories - sudo mkdir -p $REGISTRY_DATA_DIR - sudo mkdir -p $REGISTRY_CONFIG_DIR - - # Create registry configuration - cat > /tmp/registry-config.yml << EOF -version: 0.1 -log: - level: info -storage: - filesystem: - rootdirectory: /var/lib/registry -http: - addr: 0.0.0.0:5000 - headers: - X-Content-Type-Options: [nosniff] -EOF - - sudo mv /tmp/registry-config.yml $REGISTRY_CONFIG_DIR/config.yml - - # Pull and run registry container - echo "Starting Docker registry container..." | tee -a $LOG_FILE - docker pull registry:2 >> $LOG_FILE 2>&1 - - # Stop existing registry if running - docker stop local-registry 2>/dev/null || true - docker rm local-registry 2>/dev/null || true - - # Start registry container - docker run -d \ - --name local-registry \ - --restart=always \ - -p $REGISTRY_PORT:5000 \ - -v $REGISTRY_DATA_DIR:/var/lib/registry \ - -v $REGISTRY_CONFIG_DIR/config.yml:/etc/docker/registry/config.yml \ - registry:2 >> $LOG_FILE 2>&1 - - # Wait for registry to be ready - echo "Waiting for registry to be ready..." | tee -a $LOG_FILE - sleep 10 - - # Test registry - if curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/ > /dev/null; then - echo "Local Docker registry is running at $REGISTRY_HOST:$REGISTRY_PORT" | tee -a $LOG_FILE - else - echo "ERROR: Failed to start local Docker registry" | tee -a $LOG_FILE - return 1 - fi -} - -# Function to download and push Mattermost images -setup_mattermost_images() { - echo "Downloading and pushing Mattermost Calls images..." | tee -a $LOG_FILE - - # Images to process - declare -A IMAGES=( - ["mattermost/calls-recorder"]="$CALLS_RECORDER_VERSION" - ["mattermost/calls-transcriber"]="$CALLS_TRANSCRIBER_VERSION" - ) - - for image in "${!IMAGES[@]}"; do - version="${IMAGES[$image]}" - echo "Processing $image:$version..." | tee -a $LOG_FILE - - # Pull from Docker Hub - echo " Pulling $image:$version from Docker Hub..." | tee -a $LOG_FILE - docker pull $image:$version >> $LOG_FILE 2>&1 - - # Tag for local registry - local_tag="$REGISTRY_HOST:$REGISTRY_PORT/$image:$version" - echo " Tagging as $local_tag..." | tee -a $LOG_FILE - docker tag $image:$version $local_tag >> $LOG_FILE 2>&1 - - # Push to local registry - echo " Pushing to local registry..." | tee -a $LOG_FILE - docker push $local_tag >> $LOG_FILE 2>&1 - - # Also tag as 'latest' for convenience - if [ "$version" != "latest" ]; then - latest_tag="$REGISTRY_HOST:$REGISTRY_PORT/$image:latest" - docker tag $image:$version $latest_tag >> $LOG_FILE 2>&1 - docker push $latest_tag >> $LOG_FILE 2>&1 - fi - - echo " Successfully pushed $image:$version to local registry" | tee -a $LOG_FILE - done - - # Create registry data archive for transfer - echo "Creating registry data archive..." | tee -a $LOG_FILE - sudo tar -czf docker-registry-data.tar.gz -C $REGISTRY_DATA_DIR . - - # Create registry container image archive - echo "Creating registry container image archive..." | tee -a $LOG_FILE - docker save -o registry-image.tar registry:2 - gzip registry-image.tar - - echo "Created archives for air-gap transfer:" | tee -a $LOG_FILE - echo " - docker-registry-data.tar.gz" | tee -a $LOG_FILE - echo " - registry-image.tar.gz" | tee -a $LOG_FILE -} - -# Function to configure calls-offloader for local registry -configure_calls_offloader() { - echo "Configuring calls-offloader for local registry..." | tee -a $LOG_FILE - - # Create a modified calls-offloader config - if [ -f "/opt/calls-offloader/config.toml" ]; then - sudo cp /opt/calls-offloader/config.toml /opt/calls-offloader/config.toml.backup - - # Update image_registry setting - sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/config.toml - - echo "Updated calls-offloader configuration to use local registry" | tee -a $LOG_FILE - echo "Backup created at /opt/calls-offloader/config.toml.backup" | tee -a $LOG_FILE - else - echo "Warning: config.toml not found. You'll need to manually configure:" | tee -a $LOG_FILE - echo " image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" | tee -a $LOG_FILE - fi -} - -# Function to create docker daemon configuration for insecure registry -configure_docker_daemon() { - echo "Configuring Docker daemon for insecure registry..." | tee -a $LOG_FILE - - # Create or update Docker daemon configuration - sudo mkdir -p /etc/docker - - # Check if daemon.json exists - if [ -f "/etc/docker/daemon.json" ]; then - sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.backup - echo "Backed up existing daemon.json" | tee -a $LOG_FILE - fi - - # Create new daemon.json with insecure registry configuration - # Note: If an existing daemon.json exists, these settings should be merged manually instead. - cat > /tmp/daemon.json << EOF -{ - "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] -} -EOF - - sudo mv /tmp/daemon.json /etc/docker/daemon.json - - # Restart Docker daemon - echo "Restarting Docker daemon..." | tee -a $LOG_FILE - sudo systemctl restart docker 2>&1 | sudo tee -a "$LOG_FILE" >/dev/null - - # Wait for Docker to restart - sleep 10 - - echo "Docker daemon configured for insecure registry access" | tee -a $LOG_FILE -} - -# Function to verify setup -verify_setup() { - echo "Verifying air-gap setup..." | tee -a $LOG_FILE - - # Check registry is accessible - if curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/_catalog | grep -q repositories; then - echo "✓ Local registry is accessible" | tee -a $LOG_FILE - else - echo "✗ Local registry is not accessible" | tee -a $LOG_FILE - return 1 - fi - - # List available images - echo "Available images in local registry:" | tee -a $LOG_FILE - curl -s http://$REGISTRY_HOST:$REGISTRY_PORT/v2/_catalog | jq '.repositories[]' 2>/dev/null || echo "Could not list repositories (jq not available)" | tee -a $LOG_FILE - - # Test pulling from local registry - test_image="$REGISTRY_HOST:$REGISTRY_PORT/mattermost/calls-recorder:latest" - echo "Testing pull from local registry: $test_image" | tee -a $LOG_FILE - if docker pull $test_image >> $LOG_FILE 2>&1; then - echo "✓ Successfully pulled test image from local registry" | tee -a $LOG_FILE - else - echo "✗ Failed to pull test image from local registry" | tee -a $LOG_FILE - return 1 - fi -} - -# Function to create air-gap deployment script -create_airgap_deployment_script() { - echo "Creating air-gap deployment script..." | tee -a $LOG_FILE - - cat > /tmp/deploy-airgap-calls.sh << 'EOF' -#!/bin/bash - -# Air-Gap Calls Deployment Script -# Run this script on the air-gapped network after setting up the local registry - -REGISTRY_HOST="${REGISTRY_HOST:-localhost}" -REGISTRY_PORT="${REGISTRY_PORT:-5000}" - -echo "Deploying Mattermost Calls in air-gapped environment..." - -# Configure Docker for local registry -sudo mkdir -p /etc/docker -# Note: If an existing daemon.json exists, these settings should be merged manually instead. -cat > /tmp/daemon.json << EOD -{ - "insecure-registries": ["$REGISTRY_HOST:$REGISTRY_PORT"] -} -EOD -sudo mv /tmp/daemon.json /etc/docker/daemon.json -sudo systemctl restart docker -sleep 10 - -# Update calls-offloader configuration -if [ -f "/opt/calls-offloader/config.toml" ]; then - sudo sed -i "s/image_registry = \"mattermost\"/image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT\/mattermost\"/" /opt/calls-offloader/config.toml - - # Restart calls-offloader service - sudo systemctl restart calls-offloader - - echo "Calls-offloader configured for air-gap deployment" -else - echo "Warning: /opt/calls-offloader/config.toml not found" - echo "Please manually configure image_registry = \"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" -fi - -echo "Air-gap deployment configuration complete" -echo "" -echo "IMPORTANT: Additional configuration required on Mattermost server:" -echo "On your Mattermost server, add this environment variable:" -echo " MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY=\"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"" -echo "" -echo "Add it to /opt/mattermost/config/mattermost.environment and restart Mattermost:" -echo " echo 'MM_CALLS_JOB_SERVICE_IMAGE_REGISTRY=\"$REGISTRY_HOST:$REGISTRY_PORT/mattermost\"' | sudo tee -a /opt/mattermost/config/mattermost.environment" -echo " sudo systemctl restart mattermost" -EOF - - chmod +x /tmp/deploy-airgap-calls.sh - mv /tmp/deploy-airgap-calls.sh ./deploy-airgap-calls.sh - - echo "Air-gap deployment script created at ./deploy-airgap-calls.sh" | tee -a $LOG_FILE -} - -# Main execution -main() { - echo "Starting air-gap Docker registry setup..." | tee -a $LOG_FILE - - # Check if we have internet access for image pulling - if ! check_internet; then - echo "Skipping image download phase - run this script with internet access first" | tee -a $LOG_FILE - exit 1 - else - # Setup local registry - setup_registry - - # Download and push images - setup_mattermost_images - fi - - # Configure Docker daemon - configure_docker_daemon - - # Configure calls-offloader - configure_calls_offloader - - # Verify setup - verify_setup - - # Create air-gap deployment script - create_airgap_deployment_script - - echo "" | tee -a $LOG_FILE - echo "=== Air-Gap Setup Complete ===" | tee -a $LOG_FILE - echo "Local registry running at: http://$REGISTRY_HOST:$REGISTRY_PORT" | tee -a $LOG_FILE - echo "Registry data stored at: $REGISTRY_DATA_DIR" | tee -a $LOG_FILE - echo "" | tee -a $LOG_FILE - echo "Next steps for air-gapped deployment:" | tee -a $LOG_FILE - echo "1. Transfer these files to your air-gapped network:" | tee -a $LOG_FILE - echo " - docker-registry-data.tar.gz" | tee -a $LOG_FILE - echo " - registry-image.tar.gz" | tee -a $LOG_FILE - echo " - deploy-airgap-calls.sh" | tee -a $LOG_FILE - echo "2. Run the local registry container in the air-gapped network" | tee -a $LOG_FILE - echo "3. Execute ./deploy-airgap-calls.sh on the air-gapped systems" | tee -a $LOG_FILE - echo "" | tee -a $LOG_FILE - echo "Log file: $LOG_FILE" | tee -a $LOG_FILE -} - -# Run main function -main "$@" \ No newline at end of file
CallsTCP (incoming) Mattermost instance(s) (Calls plugin) rtcd serviceTo allow for HTTP/WebSocket connectivity from Calls plugin to rtcd service. Can be expose internally as the service only needs to be reachable by the instance(s) running the Mattermost server.To allow for HTTP/WebSocket connectivity from Calls plugin to rtcd service. Can be exposed internally as the service only needs to be reachable by the instance(s) running the Mattermost server.
STUN (Calls plugin or rtcd)