Helm Charts

Deploy Tuneloop on Kubernetes using Helm for production environments with high availability and scaling.

Prerequisites

  • A Kubernetes cluster (1.26+)
  • Helm 3.x
  • A Postgres 17 instance (managed or self-hosted)
  • Docker Hub credentials provided by the Tuneloop team (username + access token)

Installation

Create the image pull secret

Tuneloop images are hosted on a private Docker Hub registry. Create a Kubernetes secret with the credentials provided by the Tuneloop team:

kubectl create namespace tuneloop

kubectl create secret docker-registry tuneloop-registry-secret \
  --namespace tuneloop \
  --docker-server=docker.io \
  --docker-username=<username> \
  --docker-password=<access-token>

Install the chart

helm repo add tuneloop https://tuneloop.github.io/tuneloop-helm-charts
helm repo update

helm install tuneloop tuneloop/tuneloop \
  --namespace tuneloop \
  --set global.imagePullSecrets[0].name=tuneloop-registry-secret \
  --set postgres.host=your-postgres-host \
  --set postgres.password=your-password \
  --set ingestToken=your-ingest-token

Architecture

The Helm chart deploys three workloads:

  • web (Deployment) — API server and dashboard. Horizontally scalable. Expose via Ingress.
  • worker (Deployment) — Background analysis pipeline. Scale by increasing replicas or worker concurrency.
  • runner (Deployment) — Benchmark execution. Requires Docker socket access (DinD sidecar or privileged node pool). Optional — omit if you do not use benchmarks.

A migration Job runs on each upgrade before the workloads start, applying any pending schema changes.

Postgres is external — bring your own managed instance (RDS, Cloud SQL, etc.) or deploy one in-cluster.

Configuration

All configuration is via Helm values. See values.yaml for the full reference.

# values.yaml (excerpt)
global:
  imagePullSecrets:
    - name: tuneloop-registry-secret

web:
  replicas: 2
  env:
    TUNELOOP_LLM_PROVIDER: anthropic
    TUNELOOP_LLM_MODEL: claude-haiku-4-5

worker:
  replicas: 2
  concurrency: 4

runner:
  enabled: false

github:
  appClientId: ""
  privateKeySecret: github-app-key
  webhookSecret: ""

jira:
  enabled: false

Ingress & DNS

The web service needs an externally reachable URL. This is the address your team will use for the dashboard and the same address every tuneloop-ingest CLI will upload transcripts to.

Add ingress values to your values.yaml:

web:
  ingress:
    enabled: true
    className: nginx          # or: alb (AWS), gce (GKE)
    hosts:
      - host: tuneloop.yourcompany.com
        paths:
          - path: /
            pathType: Prefix
    tls:
      - hosts:
          - tuneloop.yourcompany.com
        secretName: tuneloop-tls   # cert-manager, ACM, or your own cert
    annotations: {}               # add controller-specific annotations here

After deploying, retrieve the load balancer address:

# AWS (ALB / NLB — returns a hostname)
kubectl get ingress tuneloop-ingress -n tuneloop \
  -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

# GKE / nginx (returns an IP)
kubectl get ingress tuneloop-ingress -n tuneloop \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Create a DNS record pointing your chosen hostname to the load balancer:

  • AWS: CNAME → the ALB/NLB hostname
  • GKE / other: A record → the IP address

Once DNS propagates, the dashboard is live at https://tuneloop.yourcompany.com and the ingest endpoint is at https://tuneloop.yourcompany.com/api/ingest.

Database Setup

AWS RDS

aws rds create-db-instance \
  --db-instance-identifier tuneloop-db \
  --db-instance-class db.t3.medium \
  --engine postgres \
  --engine-version 17 \
  --master-username tuneloop \
  --master-user-password your-secure-password \
  --allocated-storage 50 \
  --storage-type gp3 \
  --db-name tuneloop \
  --no-publicly-accessible

Ensure the RDS security group allows inbound connections from your EKS cluster's security group on port 5432.

Google Cloud SQL

gcloud sql instances create tuneloop-db \
  --database-version=POSTGRES_17 \
  --tier=db-custom-2-7680 \
  --region=us-central1 \
  --root-password=your-secure-password \
  --storage-size=50GB \
  --storage-type=SSD

gcloud sql databases create tuneloop --instance=tuneloop-db

Scaling

# Scale web replicas
helm upgrade tuneloop tuneloop/tuneloop \
  --namespace tuneloop \
  --set web.replicas=4

# Scale worker replicas and concurrency
helm upgrade tuneloop tuneloop/tuneloop \
  --namespace tuneloop \
  --set worker.replicas=3 \
  --set worker.concurrency=4

Updating

helm repo update
helm upgrade tuneloop tuneloop/tuneloop \
  --namespace tuneloop \
  -f my-values.yaml

Migrations run automatically as a pre-upgrade Job.

Teardown

Uninstall the release:

helm uninstall tuneloop --namespace tuneloop

To also remove the namespace and image pull secret:

kubectl delete namespace tuneloop

This does not delete your external Postgres database or its data.

Next Steps

Once deployed:

  1. Configure LLM enrichment and connectors
  2. Set up integrations to start capturing sessions
  3. Connect GitHub and Jira for outcome linking