Kustomize: Template-Free Configuration Hydration
Kustomize is a declarative configuration management tool that allows you to manage environment-specific customizations without templating (e.g., Helm's Go templates). It utilizes a Base + Overlay pattern to "hydrate" raw YAML into environment-ready manifests.
1. ARCHITECTURAL CORE CONCEPTS
Kustomize operates on the principle of Inheritance via the Filesystem.
1.1 The Base
The "Source of Truth." It contains the common, raw Kubernetes manifests (Deployments, Services, ConfigMaps) that represent the generic application state.
1.2 The Overlay
A specialized directory that references a Base. It contains Patches and Transformers that modify the base resources for a specific environment (Dev, Staging, Prod).
1.3 Hydration vs. Templating
- Helm (Templating): Uses placeholders (
{{ .Values.name }}) and generates YAML via string replacement. - Kustomize (Hydration): Starts with valid YAML, merges changes, and outputs valid YAML.
- Architectural Benefit: You can always
kubectl applya Base directly; you cannot do that with an unrendered Helm chart.
- Architectural Benefit: You can always
2. THE KUSTOMIZATION SCHEMA
The engine is controlled by kustomization.yaml. Strict Naming Rule: The file must be lowercase kustomization.yaml. Kustomization.yml or capitalized variants will be ignored by kubectl.
2.1 Recommended Production Directory Structure
deploy/
├── base/ # Generic application logic
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/ # Environment-specific logic
├── dev/
│ ├── kustomization.yaml
│ └── patches.yaml
└── prod/
├── kustomization.yaml
└── replicas-patch.yaml
3. TRANSFORMERS: GLOBAL MODIFICATIONS
Transformers are high-level mechanisms to apply changes across all resources in a kustomization set.
| Transformer | Description | Internal Impact |
|---|---|---|
namespace | Sets the namespace for all resources. | Updates metadata.namespace and cross-references (ServiceAccount bindings). |
namePrefix | Prepends a string to all resource names. | Updates names and all selectors/references. |
commonLabels | Injects labels into all resources. | Updates metadata and selectors (if includeSelectors: true). |
images | Overrides container image tags/registries. | Replaces image: tag without manual spec edits. |
Example: Production Overlay Transformer
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: prod-namespace
namePrefix: enterprise-
images:
- name: my-api-image
newName: 123456789.dkr.ecr.us-east-1.amazonaws.com/api
newTag: v2.4.5
replicas:
- name: enterprise-my-deployment
count: 10
4. GENERATORS: IMMUTABLE CONFIG PATTERN
Kustomize can generate ConfigMaps and Secrets. Crucially, it appends a Content Hash to the name (e.g., my-config-h9k2b5).
4.1 The Rollout Trigger
When you change the content of a file in a configMapGenerator, the hash changes. This creates a New ConfigMap. Kubernetes sees the Deployment's reference has changed and triggers a Rolling Update.
- Bible Usage: This is the gold standard for ensuring Pods always have the latest config without manually managing
recreatestrategies.
configMapGenerator:
- name: app-settings
files:
- configs/ui.properties
literals:
- API_TIMEOUT=30s
5. PATCHES: SURGICAL YAML MODIFICATION
For deep modifications (probes, affinity, env vars) that Transformers cannot reach, use Patches.
5.1 Strategic Merge Patch (YAML-style)
Updates the resource by providing a partial YAML snippet. Kustomize merges it into the base.
5.2 JSON Patch (RFC 6902)
Standardized, precise operations (add, replace, remove).
Bible-Grade Patch Example (In-line v5+ Syntax):
patches:
- target:
group: apps
version: v1
kind: Deployment
name: my-app
patch: |-
# 1. Add Environment Variables
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: NODE_ENV
value: production
# 2. Modify Resource Limits
- op: replace
path: /spec/template/spec/containers/0/resources
value:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "100m"
memory: "512Mi"
# 3. Inject Liveness Probe (if missing)
- op: add
path: /spec/template/spec/containers/0/livenessProbe
value:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
6. REPLACEMENTS (The Modern "Vars")
The legacy vars system is deprecated. The modern way to share data between resources (e.g., injecting a Service name into an Ingress) is replacements.
replacements:
- source:
kind: Service
name: my-backend
fieldPath: metadata.name
targets:
- select:
kind: Ingress
fieldPaths:
- spec.rules.0.http.paths.0.backend.service.name
7. PRODUCTION CLI WORKFLOW
7.1 Hydration Verification (The Dry Run)
Always inspect the hydrated output before applying.
# Render the final YAML to stdout
kubectl kustomize overlays/prod
# Use a linter on the rendered output
kubectl kustomize overlays/prod | kube-linter lint
7.2 Deployment
The -k flag tells kubectl to look for a kustomization.yaml and run the hydration engine before sending to the API.
kubectl apply -k overlays/prod
7.3 Debugging the "Edit Fix"
If you are moving from old Kustomize versions (v3/v4) to v5+, your patchesJson6902 will be deprecated. Use the fixer:
kustomize edit fix
8. ARCHITECT'S COMPARISON SUMMARY
| Feature | Kustomize | Helm |
|---|---|---|
| Logic | None (Declarative) | High (Go Templating, Loops, If/Else) |
| Deployment | kubectl apply -k | helm install |
| Immutability | Very High (Base stays valid) | Medium (Charts are brittle) |
| State | None (Cluster is Truth) | Secret-based releases (helm list) |
| Learning Curve | Low (Pure YAML) | High (Template debugging) |
9. PRODUCTION PITFALLS & WARNINGS
- SubPath Update Failure: If you patch a file inside a ConfigMap that is mounted via
subPath, Kustomize's hash rotation will create a new ConfigMap, but the Pod'ssubPathmount will not update.- Solution: Always mount the whole directory or restart the Pod.
- Naming Collisions:
namePrefixcan cause issues if you have multiple resources that end up with the same name after prefixing. - Cross-Namespace References:
namespacetransformer is powerful but can breakClusterRoleBindingsif you aren't careful with thesubjectsnamespace field. - Implicit Ordering: Kustomize processes resources in the order they appear in
resources:. Place dependencies (like Namespaces) at the top.