Skip to content

Terraform

Document ID: DEP-005
File Path: docs/12-deployment/terraform.md
Version: 1.2.0
Status: Draft — spec-only, zero artifacts, deliberately (see the decision note below). No .tf files exist in this repository yet, and this document describes the long-term, aspirational multi-service cloud topology (a Kubernetes cluster + managed Postgres/Redis/Qdrant/NATS + object storage), which mirrors the equally aspirational kubernetes.md/helm.md topology, not what deployment/helm/wovyr/ or deployment/docker-compose.yml actually deploy today (single binary + optional Postgres + optional Qdrant, no Redis, no NATS). Provision the real v1.0 topology’s infrastructure by hand or with generic Postgres/Kubernetes Terraform modules until this document has real artifacts behind it. Owner: Platform Operations Team
Last Updated: 2026-07-18

Decision (RM-AIM-P3 DEP-302, 2026-07-18): first-party Terraform artifacts are scoped out for the current single-node topology. What ships today — one binary on a PVC/host directory plus optional stock Postgres/Qdrant — is exactly what generic, battle-tested modules (a managed-Postgres module, a cluster module, or plain helm_release) already provision; a first-party module would wrap those with no Wovyr-specific logic and immediately go stale against the aspirational topology below. Revisit when the multi-service split (§2) actually exists to encode. Until then: provision infrastructure with your cloud’s standard modules and deploy via deployment/helm/wovyr/, compose, or systemd; the operator upgrade path is covered by upgrade-and-migration.md.


This document describes provisioning the cloud infrastructure for the Wovyr AI Platform with Terraform — the Kubernetes cluster, managed datastores, networking, and secrets that the Helm release runs on.


Terraform provisions the infrastructure; Helm deploys the application. The boundary:

Terraform Helm
───────── ────
K8s cluster + node pools Wovyr services
Managed PostgreSQL (consumes DB URL)
Managed Redis (consumes Redis URL)
Qdrant (managed/self-hosted) Memory Engine config
NATS / managed messaging Event bus config
Object storage bucket Artifacts/archives
DNS, TLS certs, ingress LB Ingress
Secrets manager + IAM Secret references

infra/
├── main.tf
├── variables.tf
├── outputs.tf
└── modules/
├── network/ # VPC, subnets, security groups
├── kubernetes/ # cluster + node pools (incl. untrusted pool)
├── postgres/ # managed PostgreSQL (primary + replica)
├── redis/ # managed Redis
├── qdrant/ # Qdrant cluster
├── messaging/ # NATS / managed equivalent
├── objectstore/ # S3-compatible bucket
└── secrets/ # secrets manager + IAM bindings

The provider is cloud-agnostic in shape; concrete modules target a specific cloud (AWS/GCP/Azure).


The cluster module provisions separate pools matching the tool-worker isolation model:

PoolPurposeNotes
systemControl-plane servicesGeneral compute
servicesStateless platform servicesAutoscaled
untrustedTool Runtime untrusted workersTainted; gVisor/Kata; isolated
gpu (optional)ML/heavy toolsGPU nodes

module "kubernetes" {
source = "./modules/kubernetes"
cluster_name = "wovyr-prod"
node_pools = {
services = { min = 3, max = 30, machine = "standard-4" }
untrusted = { min = 1, max = 30, machine = "standard-4", taint = "wovyr.io/untrusted", runtime = "gvisor" }
}
}
module "postgres" {
source = "./modules/postgres"
ha = true
storage_gb = 200
}
output "db_url" { value = module.postgres.connection_url, sensitive = true }
output "bucket" { value = module.objectstore.name }

Sensitive outputs (DB URL, keys) are written to the secrets manager and surfaced to Helm as secret references, never as plaintext values.


Terminal window
terraform init # remote backend (versioned, locked state)
terraform plan -var-file=prod.tfvars
terraform apply -var-file=prod.tfvars
  • Use a remote, locked backend for state.
  • Maintain per-environment var files (dev.tfvars, prod.tfvars).
  • Drive via CI with plan review before apply.

  • A secrets manager (cloud-native or Vault) stores DB credentials, provider keys, and signing keys.
  • Workloads receive scoped IAM identities (e.g. IRSA/workload identity) to read only their secrets and object-store prefixes — least privilege.

  • Managed PostgreSQL: automated backups + PITR; cross-region replica for DR.
  • Object storage: versioning + lifecycle rules.
  • Qdrant/Redis are rebuildable (Memory storage §9), reducing DR scope to the system of record.

After apply, Terraform outputs feed the Helm values (cluster credentials, backend URLs as secret refs, bucket name), completing infra → application deployment.



VersionDateDescription
1.2.02026-07-18RM-AIM-P3 DEP-302: recorded the explicit decision to scope out first-party Terraform artifacts for the single-node topology (generic modules + Helm/compose/systemd suffice; revisit at the multi-service split)
1.1.02026-07-07RM-GA-P3 DOC-A2: marked as spec-only/zero-artifacts and the described topology as long-term aspirational, distinct from what deployment/helm/wovyr//deployment/docker-compose.yml actually deploy today
1.0.02026-06-27Initial Terraform deployment guide