Kustomize¶
Kustomize customizes Kubernetes manifests without templates. Instead of sprinkling {{ .Values.replicas }} through your YAML, you keep complete, valid base manifests and declare patches that transform them per environment. It is built into kubectl (kubectl apply -k), which also makes it CKA exam material.
The philosophy difference from Helm matters more than the syntax: a Helm chart is a program that generates YAML; a Kustomize overlay is a diff against YAML that already exists. Diffs are easier to review and reason about; programs are more powerful for packaging and distribution. Most platforms end up using both.
The base/overlay model¶
app/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml # complete, valid manifests
│ └── service.yaml
└── overlays/
├── staging/
│ ├── kustomization.yaml # references ../../base + patches
│ └── replica-patch.yaml
└── production/
├── kustomization.yaml
├── replica-patch.yaml
└── resources-patch.yaml
flowchart LR
BASE[base/\ncomplete manifests] --> S[overlay: staging\n+ 1 replica, debug logging]
BASE --> P[overlay: production\n+ 10 replicas, resources,\nprod image tag]
S --> OUT1[rendered staging YAML]
P --> OUT2[rendered production YAML]
The base is deployable on its own. Overlays never copy it -- they reference and transform it, so a fix to the base propagates to every environment on the next apply.
Base kustomization.yaml¶
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
labels:
- pairs:
app.kubernetes.io/name: web
includeSelectors: true
Production overlay¶
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: production
namePrefix: prod-
images:
- name: ghcr.io/example/web
newTag: v2.4.1 # pin the image per environment, no template needed
replicas:
- name: web
count: 10
patches:
- path: resources-patch.yaml
Built-in transformers (namespace, namePrefix, images, replicas, labels) cover the majority of per-environment changes without writing a patch file at all.
Patches: two flavors¶
Strategic merge patch -- a partial manifest; anything you include is merged over the base:
# resources-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
template:
spec:
containers:
- name: web # matched by name, not position
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
memory: 1Gi
JSON6902 patch -- surgical operations at exact paths, for cases merge semantics can't express (removing a field, editing a list element by index):
patches:
- target:
kind: Deployment
name: web
patch: |-
- op: remove
path: /spec/template/spec/containers/0/livenessProbe
- op: replace
path: /spec/strategy/rollingUpdate/maxUnavailable
value: 0
Rule of thumb: strategic merge for "set these fields," JSON6902 for "remove this" or list-index surgery.
Generators: the killer feature¶
configMapGenerator and secretGenerator create ConfigMaps/Secrets with a content-hash suffix, and rewrite every reference to match:
This produces app-config-7b2f8c9k4d, and the Deployment that mounts app-config is automatically updated to reference the hashed name. Change app.properties, and the hash changes -- which changes the pod template -- which triggers a normal rolling update.
This is the clean solution to the problem described in ConfigMaps and Secrets: editing a ConfigMap in place never restarts pods, and subPath mounts never update at all. Generated, hash-named config makes every config change a versioned, rollback-able rollout instead of a silent in-place mutation. If you adopt one Kustomize feature, adopt this one.
(Use generatorOptions: {disableNameSuffixHash: true} only when something outside Kustomize references the ConfigMap by fixed name.)
Using it¶
Kustomize is built into kubectl:
kubectl kustomize overlays/production # render, review
kubectl apply -k overlays/production # render + apply
kubectl diff -k overlays/production # what would change
kubectl delete -k overlays/production
The standalone kustomize binary tracks newer features (and is what Argo CD and Flux embed); kubectl's built-in version lags it slightly. For CI, render with kustomize build and pipe through policy checks before applying.
Composing with Helm and GitOps¶
- Argo CD and Flux speak Kustomize natively -- point an Application at an overlay directory and you have per-environment GitOps with zero templating.
- The common hybrid: Helm for third-party software (you consume someone's chart), Kustomize for your own apps (you own the YAML). Kustomize can even post-process rendered charts via
helmCharts:when you need to patch a chart the maintainer won't parameterize. - Because overlays are plain YAML in Git,
git diffon a PR shows exactly what changes in production -- the review experience is Kustomize's quiet superpower.
Kustomize vs Helm¶
| Kustomize | Helm | |
|---|---|---|
| Model | patch existing YAML | render templates |
| Learning curve | low | medium (Go templates, Sprig) |
| Environment variants | overlays | values files |
| Packaging/distribution | none (it's just Git) | charts, registries, versioning |
| Rollback tooling | via Git / GitOps | helm rollback release history |
| Config-change rollouts | hash-suffixed generators | checksum annotations (manual pattern) |
| Built into kubectl | yes (-k) |
no |
Choose Kustomize when you own the manifests and want reviewable, template-free environment variants. Choose Helm when you're distributing software to others or consuming third-party packages. They compose rather than compete.
Common mistakes¶
- Copying the base into each overlay -- the entire point is single-source transformation; copies rot immediately.
- Deep overlay chains (overlay-on-overlay-on-overlay): after two levels, nobody can predict the output. Keep it to base + one overlay per environment and verify with
kubectl kustomize. - Patching what a transformer already handles -- use
images:andreplicas:fields instead of hand-written patches for those. - Disabling the hash suffix out of habit -- you're throwing away automatic config rollouts.
Certification notes¶
- The current CKA curriculum explicitly includes Kustomize (alongside Helm) under cluster and workload configuration. Know
kubectl apply -k, the kustomization.yaml structure, and how overlays reference bases. kubectl kustomize <dir>(render without applying) is the fast way to verify your answer in the exam.
Related Concepts¶
- Helm -- the complementary packaging approach
- ConfigMaps and Secrets -- the update problem generators solve
- Argo CD -- GitOps delivery for overlays
- CKA Exam Guide