Skip to content

jlav/lmnr-helm

 
 

Repository files navigation

Laminar Helm Chart

Deploy Laminar on Kubernetes with a single command.

What's Included

  • Frontend - Web application with ALB ingress
  • App Server - Backend API with NLB for gRPC/HTTP
  • PostgreSQL - Database for metadata (StatefulSet with persistence)
  • ClickHouse - Primary database for user data (StatefulSet with persistence)
  • Redis - Cache and session store
  • RabbitMQ - Message queue (StatefulSet with persistence)
  • Quickwit - Full-text search engine

Quick Start

First, add the Laminar Helm repository:

helm repo add laminar https://lmnr-ai.github.io/lmnr-helm
helm repo update

Then clone this repository to get the laminar.yaml values file, which you'll edit and pass to the chart:

git clone https://github.com/lmnr-ai/lmnr-helm.git
cd lmnr-helm

Then, follow the steps below to install Laminar.

# 1. Edit laminar.yaml — replace ALL placeholder values (e.g. <region>, <bucket-name>)
#    with your actual cloud provider, credentials, S3 buckets, and availability zones.
#    See "Minimal Configuration" below for details.

# 2. Install
helm upgrade -i laminar laminar/laminar -f laminar.yaml

# 3. Get ALB URL (wait 1-2 minutes for provisioning)
ALB_URL=$(kubectl get ingress laminar-frontend-ingress -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')

# 4. Configure frontend URLs
helm upgrade -i laminar laminar/laminar -f laminar.yaml \
  --set frontend.env.nextauthUrl="http://$ALB_URL" \
  --set global.nextPublicUrl="http://$ALB_URL"

# 5. Get the LMNR_BASE_URL (to send traces to)
LMNR_BASE_URL=$(kubectl get svc laminar-app-server-load-balancer -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') && echo $LMNR_BASE_URL

# 6. Initialize the SDK with your self-hosted base URL
#    TypeScript: Laminar.initialize({ baseUrl: "http://$LMNR_BASE_URL" })
#    Python:     Laminar.initialize(base_url="http://$LMNR_BASE_URL")

See QUICKSTART.md for detailed installation steps.

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         External Traffic                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│    ┌──────────────┐                    ┌──────────────┐         │
│    │   AWS ALB    │                    │   AWS NLB    │         │
│    │  (HTTP/S)    │                    │ (gRPC/HTTP)  │         │
│    └──────┬───────┘                    └──────┬───────┘         │
│           │                                   │                 │
│           ▼                                   ▼                 │
│    ┌──────────────┐                    ┌──────────────┐         │
│    │   Frontend   │───────────────────▶│  App Server  │         │
│    │   (Next.js)  │                    │   (Rust)     │         │
│    └──────┬───────┘                    └──────┬───────┘         │
│           │                                   │                 │
├───────────┼───────────────────────────────────┼─────────────────┤
│           │           Internal Services       │                 │
│           │                                   │                 │
│    ┌──────┴───────────────────────────────────┴──────┐          │
│    │                                                 │          │
│    ▼                  ▼                ▼             ▼          │
│ ┌──────┐        ┌──────────┐      ┌──────────┐  ┌──────────┐    │
│ │Redis │        │PostgreSQL│      │ClickHouse│  │ RabbitMQ │    │
│ └──────┘        └──────────┘      └──────────┘  └──────────┘    │
│                                                                 │
│                        ┌──────────┐                             │
│                        │ Quickwit │                             │
│                        └──────────┘                             │
└─────────────────────────────────────────────────────────────────┘

Prerequisites

Note on Namespaces: By default, all resources are created in the default namespace. Advanced users who prefer a custom namespace (e.g., laminar) should add --namespace laminar --create-namespace to helm commands and -n laminar to kubectl commands.

Configuration

Configuration Files

  • laminar.yaml - Your custom configuration (edit this)
  • values.yaml - Base defaults (don't edit, use for reference)

Helm merges both files, with laminar.yaml taking precedence.

Minimal Configuration

Edit laminar.yaml and replace all placeholder values (<region>, <bucket-name>, etc.) with your actual values:

  1. Cloud Provider: Set global.cloudProvider to aws or gcp
  2. Cloud credentials and S3 buckets for trace storage
  3. AEAD_SECRET_KEY — generate with openssl rand -hex 32. Used to encrypt project API keys and model API keys for the playground.
  4. ClickHouse S3 bucket endpoint and region — replace <bucket-name> and <region> with real values
  5. Quickwit S3 bucket — replace your-bucket-name and <region> with real values
  6. Availability zones (required for AWS EBS volumes)
  7. Frontend URLs (can be set after initial deployment)

Important: Angle-bracket placeholders like <region> will produce invalid XML in the ClickHouse config and cause CrashLoopBackOff errors if left unchanged.

secrets:
  data:
    AWS_ACCESS_KEY_ID: "your-key"
    AWS_SECRET_ACCESS_KEY: "your-secret"
    NEXTAUTH_SECRET: "random-secret-string"
    AEAD_SECRET_KEY: "generate with: openssl rand -hex 32"

clickhouse:
  s3:
    endpoint: "https://your-bucket.s3.us-east-1.amazonaws.com/"
    region: "us-east-1"

quickwit:
  s3:
    defaultIndexRootUri: "s3://your-bucket/indexes"
    region: "us-east-1"

storage:
  storageClass:
    zones:
      - "us-east-1b" # Required for AWS EBS, can be empty for GCP

Production Configuration

For production deployments, additionally configure:

  1. OAuth Configuration for logging in to the UI platform. Google and Github are supported.
  2. Secure passwords for PostgreSQL, ClickHouse, and RabbitMQ (in secrets.data)
  3. External secret management (AWS Secrets Manager, HashiCorp Vault, or extraEnv with secretKeyRef for pre-existing K8s Secrets)
  4. HTTPS / TLS — via cert-manager (automatic Let's Encrypt), AWS ACM, or a pre-existing certificate imported as a Kubernetes secret
  5. Custom domain with external-dns or manual DNS
  6. GCS storage for ClickHouse on GCP — requires HMAC credentials (not environment credentials)

See CONFIGURATION.md for complete configuration reference.

Slack Notifications (optional)

To enable Slack notifications and alerts, set an enterprise license key in secrets.data. This connects your self-hosted instance to the official Laminar Slack app:

secrets:
  data:
    LMNR_LICENSE_KEY: "your-enterprise-license-key"

To get a license key, contact founders@lmnr.ai.

Common Operations

Check Status

kubectl get pods
kubectl get svc
kubectl get ingress

View Logs

kubectl logs -l app=laminar-frontend -f
kubectl logs -l app=laminar-app-server -f

Access Databases

# PostgreSQL
kubectl exec -it laminar-postgres-0 -- psql -U lmnr -d lmnr

# ClickHouse
kubectl exec -it laminar-clickhouse-0 -- clickhouse-client

Upgrade

helm upgrade -i laminar ./charts/laminar -f laminar.yaml

Upgrading from <= 0.1.11 to >= 0.1.12 requires deleting the RabbitMQ and Quickwit StatefulSets with --cascade=orphan first — see CONFIGURATION.md — Upgrading the Chart.

Uninstall

helm uninstall laminar

# To also delete persistent data:
kubectl delete pvc -l app=laminar-postgres
kubectl delete pvc -l app=laminar-clickhouse
kubectl delete pvc -l app=laminar-rabbitmq

Documentation

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Go Template 100.0%