kform

kform is an HCL-based generator for Kubernetes manifests.

See an example View on GitLab

What is kform?

kform generates Kubernetes manifests from HCL — the configuration language behind Terraform. Instead of stitching YAML together as text the way Helm’s Go templates do, kform evaluates a real configuration language: resources are structured data with types, expressions, and control flow, and YAML is only what comes out at the end.

Resources are expressed directly in HCL, with locals blocks to deduplicate shared values, typed variable blocks for inputs, and conditional resources built on for_each — concepts borrowed directly from Terraform.

Why kform?

The main reason to reach for kform is maintainability.

Templating treats manifests as text with placeholders. That’s fragile: YAML is whitespace-sensitive, so a misplaced indent, or a template expression that emits one extra space or newline, can silently produce invalid or wrong output. kform doesn’t have this problem, because it isn’t templating — HCL has an actual grammar, so expressions, interpolation, and variables are parsed and evaluated properly instead of stitched together as text. Whitespace carries no meaning at all.

Inputs are typed: variable blocks declare the shape values must take, so a wrong type or a typo’d field is caught when the configuration is evaluated, not after a broken manifest reaches kubectl apply.

That’s on top of everything else kform inherits from HCL and Terraform — string interpolation, values files equivalent to Helm’s, and more. See the project README for the full feature list.

How do I use kform?

Install the CLI:

go install gitlab.com/fforster/kform/cmd/kform@latest

Here’s a config that declares a typed input variable, a locals block shared by two resources, and a HorizontalPodAutoscaler that’s only generated when var.app.replicas is greater than one:

variable "name" {
  type    = string
  default = "my-app"
}

variable "replicas" {
  type    = number
  default = 1
}

locals {
  selectorLabels = {
    "app.kubernetes.io/name" = var.name
  }
  labels = merge({
    "app.kubernetes.io/managed-by" = "kform"
  }, local.selectorLabels)
}

resource "Deployment" {
  apiVersion = "apps/v1"

  metadata = {
    name   = var.name
    labels = local.labels
  }

  spec = {
    replicas = var.replicas
    selector = {
      matchLabels = local.selectorLabels
    }
    template = {
      metadata = {
        labels = local.labels
      }
      spec = {
        containers = [
          {
            name  = var.name
            image = "nginx:latest"
          }
        ]
      }
    }
  }
}

# Only generated when replicas > 1, since for_each on an empty
# collection produces zero resources.
resource "HorizontalPodAutoscaler" {
  for_each = var.replicas > 1 ? { (var.name) = { replicas = var.replicas } } : {}

  apiVersion = "autoscaling/v2"

  metadata = {
    name   = each.key
    labels = local.labels
  }

  spec = {
    scaleTargetRef = {
      apiVersion = "apps/v1"
      kind       = "Deployment"
      name       = each.key
    }
    minReplicas = each.value.replicas
    maxReplicas = each.value.replicas * 3
  }
}

Without specifying any variables, kform template chart.hcl generates just the Deployment by default. The HorizontalPodAutoscaler is omitted.

By providing the --var 'replicas=3' command line argument, kform also generates the HorizontalPodAutoscaler, with minReplicas: 3 and maxReplicas: 9.

# Output of: kform template config.hcl --var 'replicas=3'
apiVersion: apps/v1
kind: Deployment
metadata:
    labels:
        app.kubernetes.io/managed-by: kform
        app.kubernetes.io/name: my-app
    name: my-app
spec:
    replicas: 3
    selector:
        matchLabels:
            app.kubernetes.io/name: my-app
    template:
        metadata:
            labels:
                app.kubernetes.io/managed-by: kform
                app.kubernetes.io/name: my-app
        spec:
            containers:
                - image: nginx:latest
                  name: my-app
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
    labels:
        app.kubernetes.io/managed-by: kform
        app.kubernetes.io/name: my-app
    name: my-app
spec:
    maxReplicas: 9
    minReplicas: 3
    scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: my-app

Contributing

kform is developed in the open on GitLab. Issues and merge requests are welcome.

gitlab.com/fforster/kform