Demo · Kubernetes stacks

One turf up. The whole stack converges.

A kind cluster, a CustomResourceDefinition, and an instance of it — three resources that each depend on the previous one existing. Terraform makes you apply these in awkward stages. Turf converges all three in a single, governed run.

turf up — cluster → CRD → custom resource, converged in one run.

One config. Three phases.

The whole demo is a single Terraform file. Each resource can only be created once the one above it exists — so Turf converges it in three planned, approved phases, configuring the kubernetes provider in Phase 2 once the cluster's endpoint is known. The phase labels and effects below are exactly what turf up computes; nothing is edited or staged by hand.

main.tf + create · each phase planned & approved
Phase 1 · create + kind_cluster.demo
# A local Kubernetes cluster running as Docker containers via kind.
resource "kind_cluster" "demo" {
  name           = var.cluster_name
  node_image     = var.node_image
  wait_for_ready = true
}
Phase 2 · create + kubernetes_manifest.crd
# The kubernetes provider binds to the cluster's computed endpoint — unknown
# until Phase 1 applied. Turf configures it here, then reloads it so the new
# CRD's API is discoverable.
provider "kubernetes" {
  host                   = kind_cluster.demo.endpoint
  client_certificate     = kind_cluster.demo.client_certificate
  client_key             = kind_cluster.demo.client_key
  cluster_ca_certificate = kind_cluster.demo.cluster_ca_certificate
}

# Registers a new API kind, demo.local/v1 "Turf".
resource "kubernetes_manifest" "crd" {
  manifest = { # … CustomResourceDefinition for turfs.demo.local (elided) … }
}
Phase 3 · create + kubernetes_manifest.instance
# The "Turf" kind does not exist until the CRD applies, so this cannot be
# planned until Phase 2 is live. depends_on orders it; Turf defers it here.
resource "kubernetes_manifest" "instance" {
  depends_on = [kubernetes_manifest.crd]
  manifest   = {
    apiVersion = "demo.local/v1"
    kind       = "Turf"
    metadata   = { name = "example-turf" }
    spec       = { message = var.cr_message }
  }
}

No -target, no staged applies, no edits to your .tf — the deferral loop converges the file as-is. Browse the full configuration on GitHub.

Run it yourself → Install Turf → Scalr demo →

turf destroy — reverse-dependency teardown: custom resource → CRD → cluster.

Tear it all down the same way it came up — planned and approved, in reverse dependency order. No cloud account or credentials required: kind runs the cluster as local Docker containers, so the whole demo is free to run yourself.