Kustomize#
Helm solves packaging with templates and values. Kustomize refuses templates entirely: keep your plain YAML as the base, and build overlays that patch in environment differences. Since v1.27 kubectl ships with it built in - no extra binary:
kubectl apply -k ./my-appThe Mental Model#
k8s-manifests/
├── base/
│ ├── api-deployment.yaml
│ ├── api-configmap.yaml
│ ├── web-deployment.yaml
│ └── kustomization.yaml # lists resources
├── overlays/
│ ├── dev/
│ │ └── kustomization.yaml # patches: replicas: 1
│ └── prod/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml- base = the truth of the application (works as-is on any cluster)
- overlay = a set of patches on top of the base (environment-specific deltas)
The rule that makes it work: overlays only touch fields they declare. Everything else passes through unchanged.
Patches: Strategic Merge vs JSON6902#
Two patch flavors, and picking the right one matters:
Strategic merge (the default when you give a plain YAML patch) - merges by field name, YAML-style:
# patch-replicas.yaml - strategic merge
apiVersion: apps/v1
kind: Deployment
metadata:
name: synergychat-api
spec:
replicas: 3Strategic merge has one hard limitation: it can’t remove list items cleanly, because lists have no “key”. If you need to replace an element of a list (say, one container’s env entry), strategic merge will merge it weirdly or duplicate it.
JSON6902 (explicit patch type) - RFC 6902 operations, surgical and precise:
# kustomization.yaml
patches:
- target:
kind: Deployment
name: synergychat-api
patch: |-
- op: replace
path: /spec/replicas
value: 3
- op: remove
path: /spec/template/spec/containers/0/resourcesUse strategic merge for “set these fields”, JSON6902 when you need remove, replace on list elements, or to target by something other than name/kind.
The Transforms That Scale#
namePrefix/nameSuffix: prefix every resource (great for a “team” prefix without editing files)namespace: stamp every resource into a namespace (pairs with the namespaces notes)labels(current) vscommonLabels(deprecated): adds labels to every resource including selectors
Deprecation trap: older tutorials use
commonLabels. On current kustomize it warns; the replacement is thelabels:field withincludeSelectors: true|false.includeSelectors: falseis safer when you don’t want the label change to trigger deployment updates.
configMapGenerator/secretGenerator: generate resources with content hashes (more below)--load-restrictor: kustomize refuses to read files outside the kustomization directory by default. That security restriction exists because remote/../bases can pull arbitrary content;--load-restrictor LoadRestrictionsNoneis the “I know what I’m doing” escape hatch
Validate Before You Apply#
kubectl kustomize overlays/prod # render to stdout
kubectl apply -k overlays/prod --dry-run=clientAnd for schema-level validation, pipe into kubeconform:
kubectl kustomize overlays/prod | kubeconform -strict -summaryconfigMapGenerator: The Hash Trick#
configMapGenerator:
- name: api-config
files:
- config.envThe generated ConfigMap is named api-config-hg8b7fcfd2. Change config.env, re-apply, and the hash changes. If your Deployment references the ConfigMap (via envFrom), kustomize rewrites the reference - so the pod template changes and pods roll automatically.
This closes a silent failure mode from the v1 notes: with a hand-written ConfigMap,
kubectl applyof a changed ConfigMap does nothing to already-running pods. The container keeps its old env until it restarts for some other reason. With generated ConfigMaps, a config change is a rollout - visible, verifiable, and no stale-config mystery.
Helm mi Kustomize mı?#
| Helm | Kustomize | |
|---|---|---|
| Yaklaşım | Go template’leri + values | Saf YAML + patches |
| Ne için | 3. parti uygulamaları paketten kurmak | Kendi manifest’lerini ortam bazlı yönetmek |
| Release/rollback | Helm’in kendi state’i (revision) | Git’te versiyonlarsan git revert |
| Öğrenme eğrisi | Template dili + chart yapısı | Neredeyse yok |
Benim pratik kuralım: başkasının yazdığı karmaşık uygulamayı (Prometheus, ArgoCD, cert-manager) kuracaksam Helm; kendi deployment’larımı ortamlara göre yönetiyorsam Kustomize. İkisi bir arada da yaygın - ve ArgoCD ikisini de source olarak destekler.
How to Structure a Base and Overlays#
Move your SynergyChat manifests from v1 into the structure shown above, and write
base/kustomization.yamllisting every resource.The base must be independently applyable - test it first:
kubectl apply -k base
kubectl get podsIf the base alone doesn’t work, the overlays never will. Fix base errors here, where nothing environmental can mask them.
- Create
overlays/dev/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- target:
kind: Deployment
name: synergychat-api
patch: |-
- op: replace
path: /spec/replicas
value: 1- Preview the difference, then apply:
kubectl kustomize overlays/dev | grep -B2 -A2 "replicas"
kubectl apply -k overlays/devHow to Promote a Change from dev to prod#
The whole point of overlays: promotion is another overlay, not a copy-paste of files.
- Create
overlays/prod/kustomization.yamlwith a higher replica patch plus an image pin:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch-replicas.yaml
images:
- name: bootdotdev/synergychat-api
newTag: v1.4.2- Render and compare dev vs prod before applying - the diff is your promotion review:
diff <(kubectl kustomize overlays/dev) <(kubectl kustomize overlays/prod)- Apply and verify what actually landed:
kubectl apply -k overlays/prod
kubectl get deploy synergychat-api -o jsonpath='{.spec.replicas} {.spec.template.spec.containers[0].image}{"\n"}'How to Auto-Roll Pods on Config Change#
- Delete the hand-written
api-configmap.yamlfrom the base’sresources:list, put its content inbase/config.env, and add tobase/kustomization.yaml:
configMapGenerator:
- name: api-config
files:
- config.env- Update the deployment’s
envFromto reference the unhashed name (kustomize rewrites it at build time):
envFrom:
- configMapRef:
name: api-config- Verify the hash rewriting:
kubectl kustomize base | grep -A2 "name: api-config"- Change a value in
config.env, re-apply, and watch the rollout happen by itself:
kubectl apply -k overlays/dev
kubectl get pods --watchIf the ConfigMap is referenced via
envFromthe roll happens because the pod template changes. If some pod reads the ConfigMap via a mounted volume at runtime, the file updates on disk but pods still won’t restart automatically unless the hash trick applies - that’s exactly whyenvFrom+ generator is the sanest pattern here.
for more cluster-extensions