Setup via Quick Start (kubeadm)

This guide walks through deploying Capacity Private Cloud in an on-premises environment using kubeadm to bootstrap a production-ready Kubernetes cluster. It covers hardware prerequisites, cluster setup, platform installation, basic ASR/TTS verification, and day-two operations: adding worker nodes, upgrading the Helm chart, uninstalling, and switching service meshes. The steps below target Linux-based bare-metal hardware or virtual servers; some commands may vary depending on your specific Linux distribution.

Hardware Requirements

The minimum server requirements are as follows:

ComponentMinimum RequirementNotes
Operating SystemUbuntu, Debian 11 or newer, or RHEL / CentOS / Rocky Linux / AlmaLinux 9 (version 10 is not supported)Requires a supported Linux distribution compatible with the latest stable release of Kubernetes.
CPU Cores8 vCPUs (or physical cores)Minimum per single Kubernetes node (Control Plane or Worker). The CPU must support AVX2; the installer verifies this.
RAM16 GBRequired for the Linux OS, kubeadm components, and the core platform containers.
Disk Space250 GBFor the operating system, container images, and persistent volumes. SSD is strongly recommended.

System Update and Upgrade

Ensure your operating system is fully updated before installing new infrastructure software. This step fixes security vulnerabilities and updates core dependencies that the installer script may rely on.

For Ubuntu or Debian:

sudo apt update && sudo apt upgrade -y

For RHEL, CentOS, Rocky Linux, or AlmaLinux:

sudo yum update -y

Download the Installation Scripts

Download the required installation files from the GitHub repository. Use the git clone command to pull the repository containing the installation script and configuration files onto your machine.

git clone https://github.com/lumenvox/containers-quick-start.git
cd containers-quick-start
git clone https://github.com/lumenvox/mrcp-api.git
git clone https://github.com/lumenvox/mrcp-client.git

Configure Environment Settings in values.yaml

The values.yaml file contains all the customizable settings for the Helm chart that defines your deployment within Kubernetes. You must edit this file to match your environment.

cd ~/containers-quick-start
vi values.yaml

Edit the following settings:

  • clusterGuid
  • hostnameSuffix
  • loggingVerbosity
  • url for external services
  • ASR language(s)
  • TTS voice(s)

Service mesh defaults: The values.yaml in the repository defaults to the Istio service mesh (global.serviceMesh.type: istio, ingress.className: istio, and gateway.namespace: istio-ingress). Leave these settings as they are. If you install with --mesh-stack linkerd, the installer overrides them for Linkerd and nginx.

Create Self-Signed Certificate

The speech components require a TLS certificate key pair, which the installer uses to create the required Kubernetes Secrets for secure communication.

Optional step: If you do not pass server.key and server.crt to the installer, it offers to generate a self-signed pair for you from the hostnameSuffix in values.yaml. Complete the manual steps below only if you prefer to create the pair yourself.

Generate the private key:

openssl genrsa -out server.key 2048

Generate the certificate:

Ensure each subjectAltName entry uses the hostnameSuffix from the values.yaml file. Replace <hostnameSuffix> in the example below with your value.

openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650 \
-addext "subjectAltName = DNS:lumenvox-api.<hostnameSuffix>, \
DNS:biometric-api.<hostnameSuffix>, \
DNS:management-api.<hostnameSuffix>, \
DNS:reporting-api.<hostnameSuffix>, \
DNS:admin-portal.<hostnameSuffix>, \
DNS:deployment-portal.<hostnameSuffix>, \
DNS:file-store.<hostnameSuffix>, \
DNS:grafana.<hostnameSuffix>"

Run the Installer

Set execute permissions on the scripts:

sudo chmod +x *.sh

Execute the installer script:

This script uses the provided configuration file (values.yaml) along with your SSL key and certificate (server.key and server.crt) to begin the installation process.

./lumenvox-control-install.sh values.yaml
  • server.key and server.crt are optional arguments. Without them, the installer prompts you to provide or generate them.
  • Run the installer as a non-root user with sudo privileges.

Set the Service Passwords

When you run the installer, it prompts for four passwords used by the external services integrated with the system: PostgreSQL, MongoDB, RabbitMQ, and Redis. The installer uses them for the external services configuration, the RabbitMQ definitions file, and the Kubernetes secrets. Adhere to the following requirements when defining these passwords:

  • Allowed Characters: Letters and numbers are recommended.
  • Restricted Characters: The passwords must not contain any of these characters: ", \, |, &, !, @, #, $, %.

Installation Time and Infrastructure Setup

Once the passwords are confirmed, the script begins the main installation process. This phase is highly automated and takes a few minutes to complete. During this time, the script installs and configures all the necessary infrastructure components.

The infrastructure deployed includes:

  • Docker: The containerization platform.
  • Kubernetes (K8s): The container orchestration system.
  • Helm: The package manager for Kubernetes.
  • containerd: The container runtime used by Kubernetes.
  • Calico: The cluster networking (CNI) plugin.
  • Gateway API and service mesh: Istio with an ingress Gateway exposed on the node IP at ports 80 and 443 (or Linkerd with the nginx ingress controller, if selected).
  • External services: PostgreSQL, MongoDB, RabbitMQ, and Redis, started with docker compose.

You will see output indicating the progress as these components and the platform services are deployed and brought online.

Important: Kubernetes 1.35 requires cgroup v2. If the node is not already using it, the installer updates the kernel boot arguments and asks to reboot. After the system comes back up, run the installer again to continue.

Verify Pod Status

After the installer script finishes, verify that all services (pods) are coming online successfully. Use the kubectl get po -A command to check the status of all pods across all namespaces.

watch kubectl get po -A

You should see a list of all pods. Look for the following states:

StatusMeaning
RunningThe pod is fully operational and healthy.
Error / CrashLoopBackOffIndicates a problem. Wait a few minutes, as the service may be restarting. If the status persists, troubleshoot further.

Note: Platform pods report 2/2 in the READY column once the service mesh sidecar (Istio or Linkerd) is injected. If they show 1/1 after a Helm upgrade with Istio, see Upgrading the Helm Chart later in this article.

Access the Admin Portal to Create a Deployment

The next step is to create a deployment via the Admin Portal. The Admin Portal is accessed using the following Fully Qualified Domain Name (FQDN):

https://admin-portal.<hostnameSuffix>

Note: The FQDN should match the hostnameSuffix configured in your values.yaml file.

Hosts File Modification

Since there is no public DNS record for the target FQDN, you must manually add entries to your local machine's hosts file. This tells your computer to resolve the domain names directly to the installation machine's IP address.

Add the following entries, replacing [YOUR_MACHINE_IP] with the actual IP address of the server:

[YOUR_MACHINE_IP]  admin-portal.<hostnameSuffix>
[YOUR_MACHINE_IP]  management-api.<hostnameSuffix>
[YOUR_MACHINE_IP]  deployment-portal.<hostnameSuffix>
[YOUR_MACHINE_IP]  lumenvox-api.<hostnameSuffix>
[YOUR_MACHINE_IP]  biometric-api.<hostnameSuffix>
[YOUR_MACHINE_IP]  reporting-api.<hostnameSuffix>
[YOUR_MACHINE_IP]  file-store.<hostnameSuffix>
[YOUR_MACHINE_IP]  grafana.<hostnameSuffix>

The installer prints this same list, with the detected IP address, at the end of the run.

After saving the hosts file, access the management-api portal to load the self-signed certificate:

https://management-api.<hostnameSuffix>

Then access the Admin Portal to create a deployment:

https://admin-portal.<hostnameSuffix>

Click on "CREATE DEPLOYMENT" and enter the connection string information for the external services.

Connection String Examples

Redis:

redis://:password@machine-ip:6379

PostgreSQL:

postgres://lvuser:password@machine-ip:5432/lumenvox_single_db?sslmode=disable&search_path=public

MongoDB:

mongodb://lvuser:password@machine-ip:27017

If successful, the Status should change to Ready. You may need to refresh the page a few times.

Configuring the MRCP API (Media Server)

The MRCP API, also referred to as the Media Server, is the component that communicates directly with your telephony or speech platform (such as Avaya Experience Portal, Cisco UCCX, Asterisk, etc.). This server handles the actual speech processing requests (ASR/TTS).

Navigate to the MRCP API Docker configuration directory:

cd ~/containers-quick-start/mrcp-api/docker

Edit the .env file using your preferred editor:

vi .env

Locate the following variables and set them according to your environment:

  • APPLICATION_DOMAIN
  • MEDIA_SERVER__DEPLOYMENT_ID
  • MEDIA_SERVER__LUMENVOX_API_ADDRESS
  • MEDIA_SERVER__HOST_MAP

After saving the .env file, start the MRCP API (Media Server) containers. The -d flag runs the containers in detached mode (in the background).

docker compose up -d

To ensure the certificate file can be safely copied and accessed by the Docker volumes, bring down the running MRCP API containers:

docker compose down
sudo cp ~/containers-quick-start/server.crt certs/

After copying the server.crt into the designated volume directory, restart the containers to use the new certificate for secure communication:

docker compose up -d

Test Functionality with simple_mrcp_client

To confirm the Media Server (MRCP API) is running correctly and capable of handling speech requests, use the built-in simple_mrcp_client utility. This runs as a standalone Docker container and connects directly to the Media Server.

cd ~/containers-quick-start/mrcp-client
docker compose up -d

Once the container is started, exec into it to interact with the MRCP testing utility:

docker exec -ti simple_mrcp_client bash

ASR Test: Run a basic speech recognition test to verify the Media Server is correctly recognizing speech input.

simple_mrcp_client -v2 -g builtin:grammar/digits -a audio_samples/1234.ulaw

If the connection is successful and the Media Server recognizes the digits, you should see output similar to the following:

TTS Test: Verify the Media Server can generate speech from text and save it as an audio file.

Ensure you are still inside the simple_mrcp_client container, then execute:

simple_mrcp_client -t "This is a test of LumenVox T T S" -o audio/test.wav

If successful, you should see output similar to the following:

The audio file audio/test.wav should now be present inside the container's file system, ready for playback or transfer.

This completes the installation, configuration, and basic ASR/TTS functionality testing for your Capacity Private Cloud deployment.

Adding a Worker Node (Optional)

A worker node adds capacity to the cluster. At the end of the control plane installation, the installer prints the exact join command, which contains the control plane IP address, the kubeadm token, and the CA certificate hash.

Copy lumenvox-worker-install.sh to the worker node and run it as a non-root user with sudo privileges:

./lumenvox-worker-install.sh <control-plane-IP> <token> <hash>
  • The script installs containerd and the Kubernetes components, joins the node to the cluster, and pre-creates the /data directories owned by the installing user so the platform pods can write to them.
  • The supported operating systems are the same as for the control plane.
  • /data is node-local. Language model files downloaded by the resource service are stored on the node where that service runs and are not shared with other nodes. Pods scheduled on a worker start with an empty /data/lang unless the files are copied there (for example, with rsync) or /data is shared between nodes (for example, over NFS).

Upgrading the Helm Chart

To upgrade to a newer chart version, run the following on the control plane. With Istio, helm upgrade resets the namespace labels, which removes the sidecar injection label, so the label must be re-applied and the pods restarted.

helm repo update
helm upgrade lumenvox lumenvox/lumenvox -n lumenvox -f values.yaml && \
kubectl label namespace lumenvox istio-injection=enabled --overwrite && \
kubectl rollout restart deployment -n lumenvox
  • The Istio settings (serviceMesh.type, ingress.className, and gateway.namespace) must be present in values.yaml. Otherwise, an upgrade removes the Gateway and HTTPRoutes.
  • To upgrade to a specific chart version, add --version X.Y.Z to the helm upgrade command.
  • With Linkerd, omit the kubectl label command.

Uninstalling

Run all uninstall scripts as a non-root user with sudo privileges. Each script asks for confirmation before making changes.

  • lumenvox-worker-uninstall.sh <control-plane-user> <control-plane-IP>: Run on a worker node. Drains and deletes the node from the cluster, then removes containerd and the Kubernetes components.
  • lumenvox-control-uninstall.sh: Run on the control plane. Removes the platform, the service mesh, Kubernetes, Helm, Docker, containerd, the external services, and all files under /data. This is irreversible.
  • lumenvox-istio-uninstall.sh [--install-linkerd]: Removes only the Istio service mesh and gateway and keeps the cluster. Optionally installs Linkerd and the nginx ingress controller afterward.

Switching from Istio to Linkerd and ingress-nginx

Important: The platform is unavailable while it is uninstalled and reinstalled. The cluster, external services, secrets, and model files are kept.

helm uninstall lumenvox -n lumenvox
./lumenvox-istio-uninstall.sh --install-linkerd
helm install lumenvox lumenvox/lumenvox -n lumenvox -f values.yaml \
--set global.serviceMesh.type=linkerd \
--set global.lumenvox.ingress.className=nginx

Afterward, edit values.yaml: set serviceMesh.type: linkerd, set ingress.className: nginx, and remove gateway.namespace, so later helm upgrade commands keep this configuration.


Was this article helpful?