Per-tenant loops

One block, N tenants. Drive a list of deployments from a JSON values file.

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

// values/tenants.json
{
  "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

# vars.kdef
variable "tenants" {
  type    = "any"
  default = []
}

The loop

# booking.kdef
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

kdef render --dir k8s/ --values values/tenants.json

Output: three full app stacks, each with its own Deployment, Service, Ingress, Certificate, named booking-acme, booking-demo, booking-beta.

Adding a tenant

Edit values/tenants.json, add an entry, run kdef diff: only the new tenant's resources show up in the diff.

Tips

  • Keep values/ files in git. They're not secrets.
  • A for body holds deployment, daemonset, statefulset, cronjob, configmap and ingress blocks, but no if blocks. To vary what a tenant gets, use ternaries on attributes as above; for resources only some tenants need, keep those tenants in a separate list in the values file and give it its own for block.
  • For many tenants (dozens+), render with kdef render > out.yaml once and inspect to make sure the output is what you expect before applying.