Per-tenant loops
Multi-tenant SaaS, per-region deployments, per-customer demo instances — whenever you want the same shape repeated with different parameters, use a for block.
The values file
Section titled “The values file”{ "tenants": [ { "name": "acme", "domain": "acme.example.com", "plan": "enterprise" }, { "name": "demo", "domain": "demo.example.com", "plan": "starter" }, { "name": "beta", "domain": "beta.example.com", "plan": "starter" } ]}The variable declaration
Section titled “The variable declaration”variable "tenants" { type = "any" default = []}The loop
Section titled “The loop”for "tenant" "var.tenants" { deployment "booking" { name = "booking-${tenant.name}" namespace = "production"
container "booking" { image = image("booking") env { TENANT_ID = tenant.name TENANT_PLAN = tenant.plan }
resources { cpu = tenant.plan == "enterprise" ? "500m..2000m" : "100m..500m" memory = tenant.plan == "enterprise" ? "512Mi..2Gi" : "128Mi..512Mi" } }
scale { replicas = tenant.plan == "enterprise" ? 3 : 1 }
service { port "80" "http" {} }
ingress { host = tenant.domain tls = true } }}Render it
Section titled “Render it”kdef render --dir k8s/ --values values/tenants.jsonOutput: three full app stacks — each with its own Deployment, Service, Ingress, Certificate — named booking-acme, booking-demo, booking-beta.
Adding a tenant
Section titled “Adding a tenant”Edit values/tenants.json, add an entry, run kdef diff — only the new tenant’s resources show up in the diff.
- Keep
values/files in git. They’re not secrets. - Combine
forwithifblocks if some tenants need extra resources:for "tenant" "var.tenants" {if {condition = tenant.plan == "enterprise"cronjob "nightly-report-${tenant.name}" {schedule = "0 2 * * *"image = image("reporter")env { TENANT_ID = tenant.name }}}} - For many tenants (dozens+), render with
kdef render > out.yamlonce and inspect to make sure the output is what you expect before applying.