Kubernetes deployment
Deploy ai-agents-observability on Kubernetes using the Helm chart.
When to use this path
- Your org standardizes on Kubernetes and cannot run Docker Compose in production.
- You need integration with K8s-native supply-chain tooling (Sigstore policy controller, OPA/Gatekeeper, External Secrets Operator).
- You want managed database/storage via K8s operators or cloud services.
Prerequisites
- Kubernetes 1.28+
- Helm 3.12+
- A namespace for the deployment
- (Optional) An ingress controller (nginx-ingress, Traefik, etc.)
- (Optional) A storage class for persistent volumes
Quick start (bundled everything)
# Clone and checkout a tagged releasegit clone https://github.com/yorch/ai-agents-observability.gitcd ai-agents-observabilitygit checkout v1.0.0
# Create namespacekubectl create namespace ai-agents-observability
# Generate JWT keysbun run gen:keys # writes to .env; copy the values into your values.yaml
# Create your values filecp deploy/helm/ai-agents-observability/values.yaml my-values.yaml# Edit my-values.yaml: set secrets.jwtPrivateKey, secrets.jwtPublicKey,# secrets.githubOAuthClientId, secrets.githubOAuthClientSecret, etc.
# Installhelm install ai-agents-observability deploy/helm/ai-agents-observability/ \ -n ai-agents-observability \ -f my-values.yamlThe chart deploys:
- TimescaleDB StatefulSet (or uses your external DB)
- MinIO StatefulSet (or uses your external S3)
- Migrations Job (Helm pre-install hook)
- Web Deployment + Service
- Ingest Deployment + Service
- GitHub App Deployment + Service (optional)
Using an internal registry
For governance-compliant deployments, push images to your internal registry and point the chart at it:
image: registry: harbor.internal.corp.com/ai-agents-observability pullPolicy: Always pullSecrets: - name: my-registry-pull-secretSee docs/deploy/README.md for how to get images into your internal registry (build from source, registry sync, or air-gapped import).
Using external database and S3
For production, prefer managed backends:
timescaledb: enabled: false
externalDatabase: url: postgresql://user:pass@managed-postgres.internal:5432/ai_agents_observability
minio: enabled: false
externalS3: endpoint: https://s3.us-east-1.amazonaws.com accessKeyId: AKIA... secretAccessKey: ... bucket: my-org-transcripts region: us-east-1 forcePathStyle: falseWhen timescaledb.enabled is false, the chart skips the TimescaleDB StatefulSet and uses externalDatabase.url for all services. Same for MinIO/external S3.
Ingress
Enable ingress for the web UI and (optionally) the GitHub App webhook receiver:
ingress: enabled: true className: nginx # or traefik, etc. annotations: cert-manager.io/cluster-issuer: letsencrypt-prod hosts: - host: observability.example.com paths: - path: / pathType: Prefix tls: - secretName: observability-tls hosts: - observability.example.com
githubAppIngress: enabled: true className: nginx hosts: - host: github-webhook.example.com paths: - path: / pathType: PrefixSecrets management
For production, don’t put secrets in values.yaml. Use External Secrets Operator or sealed-secrets:
secrets: useExistingSecret: true secretName: my-external-secretCreate the secret via External Secrets Operator pointing at Vault, AWS Secrets Manager, etc. The chart reads all secrets from the named Kubernetes Secret.
Air-gapped Kubernetes
-
Load images onto all cluster nodes (or a local registry):
Terminal window # On each node (or use a local registry):docker load -i web-v1.0.0.tardocker load -i ingest-v1.0.0.tardocker load -i github-app-v1.0.0.tardocker load -i migrations-runner-v1.0.0.tar -
Set
pullPolicy: IfNotPresentand point at the loaded image names:image:registry: ghcr.io/yorch/ai-agents-observability # matches the loaded image namespullPolicy: IfNotPresent -
Install the chart — no outbound image pulls happen.
Disabling the GitHub App service
If you don’t use PR enrichment:
githubApp: enabled: falseThe chart skips the Deployment, Service, and Ingress for the GitHub App.
Manual migration management
If you prefer to run migrations outside Helm:
migrations: enabled: falseThen run migrations manually:
kubectl exec -n ai-agents-observability deploy/ai-agents-observability-web -- \ bun run db:deployUpgrading
# Update your values if needed, then:helm upgrade ai-agents-observability deploy/helm/ai-agents-observability/ \ -n ai-agents-observability \ -f my-values.yamlThe migration Job runs as a pre-upgrade hook. If it fails, the release is in a half-upgraded state:
helm rollback ai-agents-observability -n ai-agents-observabilitykubectl logs job/ai-agents-observability-migrations -n ai-agents-observabilityVerification
# Check all pods are runningkubectl get pods -n ai-agents-observability
# Check web healthkubectl exec -n ai-agents-observability deploy/ai-agents-observability-web -- \ wget -qO- http://localhost:3000/health
# Port-forward to access the UIkubectl port-forward -n ai-agents-observability svc/ai-agents-observability-web 3000:3000Production considerations
- TimescaleDB: the bundled StatefulSet is a starting point. For production, use a managed Postgres with TimescaleDB extension, or the CloudNativePG operator with the TimescaleDB extension. The bundled StatefulSet has no HA, no automated backups, and no WAL archiving.
- MinIO: same — the bundled StatefulSet is single-node. For production, use external S3 or the MinIO Operator for distributed MinIO.
- Resource limits: the defaults in
values.yamlare conservative. Adjust based on your load. - Replicas:
webandingestcan be scaled horizontally (they’re stateless).github-appcan too. TimescaleDB and MinIO are single-replica by default. - Backups: PVC snapshots for TimescaleDB and MinIO data. Configure according to your cluster’s backup strategy (Velero, etc.).