Lesson 16 Chart Validation & Linting
Theme:

Lab Guide

Three exercises: lint and fix a broken chart, add JSON Schema validation, and validate with kubeconform.

Prerequisites: Helm 3.x installed (helm version). For Exercise 3, install kubeconform: brew install kubeconform (macOS) or download from GitHub releases.

Exercise 1 Lint and Fix a Broken Chart

In this exercise you will create a chart with intentional errors, use helm lint and helm template to find them, and fix each issue.

Step 1 — Create the chart scaffold

helm create lint-lab
cd lint-lab

Step 2 — Introduce errors

Open Chart.yaml and remove the version field entirely. Then open templates/deployment.yaml and introduce two errors:

# Error 1: wrong indentation on labels (remove 2 spaces)
metadata:
  name: {{ include "lint-lab.fullname" . }}
labels:                          # <-- should be indented under metadata
    {{- include "lint-lab.labels" . | nindent 4 }}

# Error 2: reference a non-existent value
spec:
  replicas: {{ .Values.scaling.replicas }}  # scaling doesn't exist

Step 3 — Run helm lint

helm lint . --strict

What to observe

Step 4 — Run helm template with debug

helm template test-release . --debug

The --debug flag will show the exact template and line number for the nil pointer error on .Values.scaling.replicas.

Step 5 — Fix all errors

  1. Add version: 0.1.0 back to Chart.yaml
  2. Fix the indentation of labels: in deployment.yaml
  3. Change .Values.scaling.replicas to .Values.replicaCount

Step 6 — Verify

helm lint . --strict
helm template test-release . > /dev/null && echo "Template OK"

Success: Both commands exit with code 0 and no warnings.

Exercise 2 Add values.schema.json Validation

You will write a JSON Schema for the default Helm chart and test it against valid and invalid values.

Step 1 — Create the schema file

In the chart root (where Chart.yaml lives), create values.schema.json:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["replicaCount", "image", "service"],
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10
    },
    "image": {
      "type": "object",
      "required": ["repository"],
      "properties": {
        "repository": {
          "type": "string",
          "minLength": 1
        },
        "pullPolicy": {
          "type": "string",
          "enum": ["Always", "IfNotPresent", "Never"]
        },
        "tag": {
          "type": "string"
        }
      }
    },
    "service": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": ["ClusterIP", "NodePort", "LoadBalancer"]
        },
        "port": {
          "type": "integer",
          "minimum": 1,
          "maximum": 65535
        }
      }
    }
  }
}

Step 2 — Test with valid values

# Should succeed (default values.yaml matches the schema)
helm lint .
helm template test-release .

Step 3 — Test with invalid values

Create a file called bad-values.yaml:

replicaCount: "five"
image:
  repository: ""
  pullPolicy: Sometimes
service:
  type: MeshService
  port: 99999
helm lint . -f bad-values.yaml

What to observe

Step 4 — Add a pattern constraint

Update the tag property in your schema to require semantic versioning:

"tag": {
  "type": "string",
  "pattern": "^v?[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9.]+)?$"
}

Test with tag: latest (should fail) and tag: v1.2.3 (should pass).

Success: Schema rejects all invalid values and accepts valid ones.

Exercise 3 Validate with kubeconform

You will render the chart, pipe the output to kubeconform, and fix any schema violations.

Step 1 — Render and validate

# Render the chart
helm template test-release . > rendered.yaml

# Validate against K8s 1.29
kubeconform -strict -kubernetes-version 1.29.0 -summary rendered.yaml

Expected output

All resources should be valid if you are using the default helm create templates.

Step 2 — Introduce a schema error

Open templates/deployment.yaml and add a misspelled field:

spec:
  template:
    spec:
      contianers:          # <-- typo: should be "containers"
        - name: {{ .Chart.Name }}
          ...
helm template test-release . | kubeconform -strict -kubernetes-version 1.29.0

What to observe

Step 3 — Fix and re-validate

Correct the typo back to containers and run kubeconform again to confirm a clean pass.

Step 4 — Build a validation script

Create a script called validate.sh that runs the full pipeline:

#!/usr/bin/env bash
set -euo pipefail

CHART_DIR="${1:-.}"

echo "==> Linting..."
helm lint "$CHART_DIR" --strict

echo "==> Rendering templates..."
helm template validate-test "$CHART_DIR" > /tmp/rendered.yaml

echo "==> Validating against K8s schema..."
kubeconform -strict -kubernetes-version 1.29.0 -summary /tmp/rendered.yaml

echo "All checks passed."
chmod +x validate.sh
./validate.sh .

Success: The script runs all three stages and exits cleanly. Any single failure stops the pipeline.

Bonus: Try adding helm install test-release . --dry-run=server --debug as a fourth stage in the script (requires a running cluster).