Stage 5 · Platform
Release Packaging with Helm & Kustomize
Package Testing
helm lint, chart-testing, kubeconform, conftest, and server-side dry runs.
Lint and Validate
Package testing catches issues before deployment. Layers: linting (syntax and style), validation (schema compliance), policy (security rules), and integration (cluster testing). Run these in CI to prevent broken deployments.
- helm lint — Check chart syntax and structure
- kubeconform — Validate rendered manifests against schemas
- conftest — Test policies with OPA/Rego
- chart-testing — Test chart installation in a real cluster
- helm template + kubeconform — Validate without a cluster
Helm Lint
helm lint checks charts for common issues: missing required values, template errors, and structural problems. Use --strict for additional checks. Add helm lint to CI pipelines.
# Basic lint
helm lint ./my-chart
# Strict mode (additional checks)
helm lint ./my-chart --strict
# Lint with values file
helm lint ./my-chart -f values-prod.yaml
# Lint OCI chart
helm lint oci://ghcr.io/my-org/charts/my-chart --version 1.0.0helm lint catches: missing templates, invalid YAML, unused values, and dependency issues. --strict adds warnings for potential issues. Always lint before packaging and publishing.
Chart Testing (ct)
Chart Testing (ct) installs charts in a real cluster and runs tests. It creates namespaces, installs the chart, waits for readiness, runs tests, and cleans up. This catches integration issues that linting cannot.
# Install ct
brew install chart-testing
# Lint changed charts
ct lint --all
# Install and test changed charts
ct install --all
# Test with specific Kubernetes version
ct install --k8s-version 1.29.0
# Test in specific namespace
ct install --namespace testingct lint runs helm lint and kubeconform validation. ct install creates a temporary namespace, installs the chart, runs helm test, and cleans up. It only tests charts that have changed since the last commit.
Kubeconform
Kubeconform validates Kubernetes manifests against official schemas. It catches schema errors that kubectl apply --dry-run might miss. Supports CRDs with custom schemas.
# Validate rendered Helm templates
helm template my-release ./my-chart | kubeconform -strict
# Validate with CRD schemas
helm template my-release ./my-chart | kubeconform \
-schema-location default \
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
# Output summary
helm template my-release ./my-chart | kubeconform -summary
# Ignore specific resources
helm template my-release ./my-chart | kubeconform \
-ignore-missing-schemas \
-summarykubeconform validates against JSON schemas. -strict treats warnings as errors. -schema-location supports custom CRD schemas. -ignore-missing-schemas skips unknown resources. -summary shows pass/fail counts.
Conftest (OPA)
Conftest tests Kubernetes manifests against OPA/Rego policies. Write custom policies for your organization: require labels, restrict images, enforce resource limits. This is policy-as-code for Kubernetes.
# policy/deployment.rego
package main
deny[msg] {
input.kind == "Deployment"
not input.spec.template.metadata.labels.team
msg := "Deployment must have a 'team' label"
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %s must have CPU limits", [container.name])
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
startswith(container.image, "docker.io/")
msg := sprintf("Container %s uses docker.io — use ghcr.io or gcr.io", [container.name])
}Rego policies define deny rules. conftest evaluates these against rendered manifests. Violations are reported with the deny message. Add conftest to CI to enforce organizational policies.
# Test rendered manifests
helm template my-release ./my-chart | conftest test -
# Test with multiple policy directories
helm template my-release ./my-chart | conftest test -p policies/ -
# Show all results (pass and fail)
helm template my-release ./my-chart | conftest test --all-namespaces -p policies/ -conftest test evaluates policies against input. The input can be YAML, JSON, or Terraform. Pipe rendered Helm templates to conftest for policy validation.
Server-Side Dry Run
Server-side dry run validates manifests against the actual API server without persisting. This catches issues that client-side validation misses: RBAC, quota limits, admission webhooks, and CRD validation.
# Validate against API server
helm template my-release ./my-chart | kubectl apply --dry-run=server -f -
# Validate with specific namespace
helm template my-release ./my-chart -n production | \
kubectl apply --dry-run=server -n production -f -Server-side dry run sends manifests to the API server for validation. The API server runs all admission controllers, RBAC checks, and schema validation without persisting. This is the most accurate validation.
Create a CI pipeline: helm lint -> kubeconform -> conftest -> ct lint -> ct install. Each step catches different issues. Run ct install on a real cluster (kind, k3d) for integration testing.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.