Skip to content

Helmfile Deployment

Deploy the complete Kindo stack using Helmfile with pure Helm values. This approach automates the manual steps from the Installation Guide into a single declarative workflow.

Overview

  • Multi-namespace — Each application runs in its own namespace
  • Pure Helm — Per-app values files match chart structure exactly
  • Declarative — Single helmfile sync deploys everything
  • Dependency ordering — Peripheries → Secrets → Applications

Architecture

┌─────────────────────────────────────────────────────────────────┐
│ helmfile.yaml.gotmpl │
│ │
│ environments/default.yaml values/*.yaml │
│ (enable/disable apps) (per-app Helm values) │
└──────────────────────────────────┬──────────────────────────────┘
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────┐ ┌─────────────────────┐
│ PERIPHERIES │ │ kindo-secrets │ │ APPLICATIONS │
│ │ │ (kindo-system) │ │ │
│ - unleash (unleash) │ │ │ │ - api │
│ - unleash-edge │ │ Creates secrets │ │ - next │
│ - qdrant (qdrant) │ │ in all app │ │ - litellm │
│ - presidio │ │ namespaces │ │ - llama-indexer │
│ - speaches │ │ │ │ - credits │
└─────────────────────┘ └─────────────────┘ │ - external-sync │
│ - external-poller │
│ - audit-log-exporter│
│ - cerbos │
│ - ssoready │
│ - prisma-migrations │
└─────────────────────┘

Prerequisites

  • Kubernetes 1.32+
  • Helm 3.8+
  • Helmfile 0.150+
  • helm-diff plugin
  • Access to registry.kindo.ai
  • External infrastructure:
    • PostgreSQL (databases: kindo, litellm, ssoready)
    • Redis
    • RabbitMQ
    • S3-compatible storage

See Infrastructure Requirements for full details.

Quick Start

1. Install Helmfile

Terminal window
brew install helmfile
helm plugin install https://github.com/databus23/helm-diff

Verify installation:

Terminal window
make check-prereqs

2. Generate Secrets

Terminal window
make generate-secrets
vi values/secrets.yaml

Required configuration in values/secrets.yaml:

domains:
base: "your-domain.com"
postgres:
main:
connectionString: "postgresql://user:pass@host:5432/kindo"
litellm:
connectionString: "postgresql://user:pass@host:5432/litellm"
ssoready:
connectionString: "postgresql://user:pass@host:5432/ssoready"
redis:
connectionString: "redis://host:6379"
rabbitmq:
connectionString: "amqp://user:pass@host:5672"
storage:
accessKey: "your-access-key"
secretKey: "your-secret-key"
bucketName: "your-bucket"
region: "us-east-1"

3. Configure Environment

Edit environments/default.yaml to set the app version and enable/disable services:

appVersion: "2025.10.1-rc.1"
storageClass: "" # Leave empty for cluster default
api:
enabled: true
next:
enabled: true
litellm:
enabled: true
llama-indexer:
enabled: true
credits:
enabled: true
external-sync:
enabled: true
external-poller:
enabled: true
audit-log-exporter:
enabled: true
cerbos:
enabled: true
ssoready:
enabled: true
prisma-migrations:
enabled: true

4. Setup Helm and Registry

Terminal window
make setup-repos
helm registry login registry.kindo.ai
./scripts/setup-registry-credentials.sh registry.kindo.ai \
'robot$your_user' 'your-password'

5. Deploy

  1. Deploy peripheries (Unleash, Qdrant, Presidio, Speaches):

    Terminal window
    make peripheries
  2. Import Unleash feature flags — Port-forward Unleash and create a Personal Access Token:

    Terminal window
    kubectl port-forward svc/unleash 4242:4242 -n unleash

    Open http://localhost:4242, log in, create a Personal API token from your profile settings, then import:

    Terminal window
    make import-flags TOKEN='user:your-token-here'
  3. Deploy secrets and applications:

    Terminal window
    make secrets
    make applications

To deploy everything at once (if feature flags are already imported):

Terminal window
make all

Deploy a single application:

Terminal window
make applications APP=api

Preview changes before deploying:

Terminal window
make diff
make diff APP=api

6. Operations

Terminal window
# Rollout restart all application deployments
make restart
# Restart a single app
make restart APP=api
# Check deployment status
make status
# Uninstall everything
make uninstall

How It Works

Helmfile Orchestration

Helmfile (helmfile.yaml.gotmpl) is the orchestration layer on top of Helm. It defines which charts to deploy, where (namespace), and in what order via needs dependencies.

# Example release definition
- name: api
chart: oci://registry.kindo.ai/kindo-helm/api
version: "{{ .Values.appVersion }}"
namespace: api
labels:
group: applications
condition: api.enabled
needs:
- kindo-system/kindo-secrets
values:
- values/api.yaml.gotmpl

Values Files

  • Plain YAML (.yaml) — Static configuration
  • Go Template (.yaml.gotmpl) — Dynamic configuration that reads from secrets.yaml

The .gotmpl extension tells Helmfile to process the file as a Go template before passing to Helm.

Secrets Flow

generate-secrets.sh → values/secrets.yaml → .gotmpl files + kindo-secrets chart
  1. .gotmpl values files read secrets for peripheries (Unleash credentials, etc.)
  2. The kindo-secrets chart reads secrets.yaml and creates Kubernetes Secrets in each app namespace

Deployment Order

Helmfile ensures correct ordering via needs:

  1. Peripheries (no dependencies) — Unleash, Qdrant, Presidio, Speaches
  2. kindo-secrets (needs peripheries) — Creates secrets in all app namespaces
  3. Applications (needs kindo-secrets) — API, Next, LiteLLM, and all other services

Directory Structure

kindo-e2e/
├── Makefile # CLI entry point
├── helmfile.yaml.gotmpl # Helmfile orchestration
├── generate-secrets.sh # Secret generator
├── charts/
│ ├── kindo-secrets/ # Creates K8s Secrets for all apps
│ ├── presidio/
│ ├── speaches/
│ └── feature_flags.json # Unleash bootstrap
├── environments/
│ └── default.yaml # App versions & enable/disable
├── scripts/
│ └── setup-registry-credentials.sh
└── values/
├── secrets.yaml # Your config (edit this!)
├── secrets.yaml.template
├── unleash.yaml.gotmpl # Periphery values
├── api.yaml.gotmpl # Application values
├── next.yaml
└── ... # One file per service

Make Commands

CommandDescription
make helpShow help and available commands
make generate-secretsGenerate secrets file from template
make check-prereqsVerify prerequisites are installed
make setup-reposAdd Helm repositories
make peripheriesDeploy peripheral services
make import-flags TOKEN='...'Import Unleash feature flags
make secretsDeploy secrets only
make applicationsDeploy all applications
make applications APP=<name>Deploy single application
make allDeploy everything
make diffPreview changes before deploying
make restartRollout restart all deployments
make restart APP=<name>Rollout restart single app
make statusShow deployment status
make templateRender templates locally (debug)
make uninstallUninstall everything

Common Workflows

Adding a new environment variable to an app:

charts/kindo-secrets/templates/secret-api.yaml
# Option 1: Edit the secret template
stringData:
MY_NEW_VAR: {{ .Values.mySection.myValue | quote }}
# Option 2: Use serviceOverrides in secrets.yaml
serviceOverrides:
api:
MY_NEW_VAR: "my-value"

Changing app version:

environments/default.yaml
appVersion: "2025.10.2"

Disabling an app:

environments/default.yaml
prisma-migrations:
enabled: false

Namespace Reference

ServiceNamespace
Unleash + Edgeunleash
Qdrantqdrant
Presidiopresidio
Speachesspeaches
APIapi
Next.jsnext
LiteLLMlitellm
Llama Indexerllama-indexer
Creditscredits
External Syncexternal-sync
External Pollerexternal-poller
Audit Log Exporteraudit-log-exporter
Cerboscerbos
SSOReadyssoready
Prisma Migrationsprisma-migrations
Secrets Chartkindo-system

Troubleshooting

Check Status

Terminal window
make status
kubectl get pods -A
kubectl get pods -n api

View Logs

Terminal window
kubectl logs -l app.kubernetes.io/name=api -n api
kubectl logs -l app.kubernetes.io/name=litellm -n litellm
kubectl logs -n unleash -l app.kubernetes.io/name=unleash

Verify Secrets

Terminal window
kubectl get secrets -A | grep "\-env"
kubectl get secret api-env -n api -o jsonpath='{.data}' | jq 'keys'
kubectl get secret api-env -n api -o jsonpath='{.data.DATABASE_URL}' | base64 -d

Common Issues

Secrets not found:

Terminal window
make secrets
kubectl get secret api-env -n api

Pods stuck in ImagePullBackOff:

Terminal window
kubectl get secret registry-credentials -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
./scripts/setup-registry-credentials.sh registry.kindo.ai 'robot$user' 'pass'

Pod CrashLoopBackOff:

Terminal window
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Limits:"

Healthcheck failures (pod restarts after ~5 min):

Terminal window
kubectl describe deployment <name> -n <namespace> | grep -A5 "Liveness:"

Debug Helm/Helmfile

Terminal window
helmfile template -l name=api
helm template kindo-secrets ./charts/kindo-secrets -f values/secrets.yaml
helmfile --debug sync