Deploy on Kubernetes

Terrantula deploys to Kubernetes via a Helm chart (infra/k8s/). The API and Worker run as long-running Bun processes; pg-boss (Postgres-native) is the job queue. The bundled Bitnami PostgreSQL chart provides both the database and the queue — no additional infrastructure is required.

Architecture

┌─────────────────────────────────────────────────────────────────┐ │ Ingress (nginx) │ └────────────────────────────┬────────────────────────────────────┘ │ ┌──────────────▼──────────────┐ │ API (Bun) │ │ Hono + Drizzle + Zod │ │ │ │ ┌─────────────────────┐ │ │ │ Business Logic │ │ │ │ - apply │ │ │ │ - constraints │ │ │ │ - recommendations │ │ │ │ - interpolation │ │ │ └─────────────────────┘ │ └──────┬───────────┬──────────┘ │ │ ┌──────────▼───────────▼──────────┐ │ PostgreSQL │ │ (data + pg-boss job queue) │ └─────────────────────────────────┘ │ ┌───────▼─────────────────┐ │ Worker (Bun) │ │ pg-boss long-poll │ │ - resolve + decrypt │ │ secrets │ │ - interpolate payload │ │ - fire webhook or PR │ │ - update ActionRun │ └──────────────────────────┘

Prerequisites

  • Kubernetes 1.25+
  • helm 3.x
  • kubectl configured for the target cluster

1. Pull chart dependencies

helm dependency update infra/k8s

This downloads the bitnami/postgresql subchart.

2. Install

helm install terrantula infra/k8s

The chart deploys PostgreSQL, the API, and the Worker. DATABASE_URL is constructed automatically from the bundled PostgreSQL credentials — no manual secret management needed for a default install.

3. Run migrations

Migrations are not run automatically on Kubernetes. Run them as a one-off pod after install or upgrade:

kubectl run terrantula-migrate \
  --image=ghcr.io/terrantula-io/terrantula-api:latest \
  --restart=Never \
  --env="DATABASE_URL=$(kubectl get secret terrantula-secrets -o jsonpath='{.data.DATABASE_URL}' | base64 -d)" \
  -- bun run src/db/migrate.ts

Configuration

All values can be overridden with --set or a values override file (-f my-values.yaml).

PostgreSQL

ValueDefaultDescription
postgresql.enabledtrueDeploy bundled PostgreSQL. Set to false to use an external database.
postgresql.auth.usernameterrantulaDatabase username
postgresql.auth.passwordterrantulaDatabase password — change this in production
postgresql.auth.databaseterrantulaDatabase name
postgresql.primary.persistence.size8GiPVC size for PostgreSQL data

API

ValueDefaultDescription
api.replicaCount2Number of API pod replicas
api.port3000Container port
image.api.repositoryghcr.io/terrantula-io/terrantula-apiAPI image repository
image.api.taglatestAPI image tag

Worker

ValueDefaultDescription
worker.replicaCount1Number of Worker pod replicas
image.worker.repositoryghcr.io/terrantula-io/terrantula-workerWorker image repository
image.worker.taglatestWorker image tag

Ingress

ValueDefaultDescription
ingress.enabledtrueDeploy an Ingress resource
ingress.classNamenginxIngress class
ingress.hostterrantula.example.comHostname
ingress.tls[]TLS configuration

Common scenarios

External database

Disable the bundled PostgreSQL and supply a connection string:

helm install terrantula infra/k8s \
  --set postgresql.enabled=false \
  --set secrets.databaseUrl="postgresql://user:pass@your-db-host:5432/terrantula"

Production credentials

Use a values override file to avoid passing secrets on the command line:

# my-values.yaml
postgresql:
  auth:
    password: "a-strong-random-password"

ingress:
  host: terrantula.your-domain.com
  tls:
    - hosts:
        - terrantula.your-domain.com
      secretName: terrantula-tls
helm install terrantula infra/k8s -f my-values.yaml

Upgrade

helm upgrade terrantula infra/k8s

Building images

If you're self-building rather than using published images, build from the workspace root (required for monorepo dependency resolution):

docker build -f packages/api/Dockerfile    -t ghcr.io/your-org/terrantula-api:latest .
docker build -f packages/worker/Dockerfile -t ghcr.io/your-org/terrantula-worker:latest .
docker push ghcr.io/your-org/terrantula-api:latest
docker push ghcr.io/your-org/terrantula-worker:latest

Then reference your images at install time:

helm install terrantula infra/k8s \
  --set image.api.repository=ghcr.io/your-org/terrantula-api \
  --set image.worker.repository=ghcr.io/your-org/terrantula-worker