Kustomize â Native Kubernetes Configuration Management Guide
In this tutorial, you'll learn about Kustomize. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Kustomize is a Kubernetes Configuration Management tool that lets you customize raw YAML files using overlays, patches, and generators â without templates or domain-specific languages.
What You'll Learn
Why It Matters
Managing environment-specific Kubernetes YAML by copying and modifying files leads to massive duplication and configuration drift. Kustomize uses a base-plus-overlay pattern: you maintain one set of base manifests and layer environment-specific changes on top. DodaTech uses Kustomize across 60+ Microservices, reducing YAML duplication by 80% and making environment-specific changes explicit and reviewable.
Real-World Use
DodaZIP's deployment repository has a base k8s/base/ directory with canonical manifests for each service. Environment overlays (k8s/overlays/dev/, k8s/overlays/production/) add only the differences â different replica counts, resource limits, ConfigMap values, and Ingress hosts.
flowchart TD
A[k8s/base] --> B[deployment.yaml]
A --> C[service.yaml]
A --> D[configmap.yaml]
B --> E[k8s/overlays/production]
C --> E
D --> E
E --> F[replicas-patch.yaml]
E --> G[resources-patch.yaml]
E --> H[ingress.yaml]
E --> I[kustomization.yaml]
I --> J[kubectl apply -k]
J --> K[Merged Production YAML]
style E fill:#326CE5,color:#fff
style J fill:#326CE5,color:#fff
Prerequisites: Basic Kubernetes knowledge and kubectl (v1.24+ includes Kustomize). Familiarity with YAML syntax.
Base Configuration
# k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/part-of: dodazip
namePrefix: dodazip-
configMapGenerator:
- name: app-config
literals:
- NODE_ENV=production
- LOG_LEVEL=info
- API_URL=https://api.dodatech.com
behavior: create
# k8s/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.dodatech.com/api:latest
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
resources:
requests:
cpu: 100m
memory: 128Mi
# k8s/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: api
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
Overlay Configuration
# k8s/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: replicas-patch.yaml
target:
kind: Deployment
name: api
- path: resources-patch.yaml
target:
kind: Deployment
name: api
- path: hpa.yaml
configMapGenerator:
- name: app-config
behavior: merge
literals:
- LOG_LEVEL=warn
- API_URL=https://api.dodatech.com
- REDIS_URL=redis://redis-cluster.production:6379
images:
- name: registry.dodatech.com/api
newTag: v2.5.0
replicas:
- name: api
count: 5
commonLabels:
environment: production
# k8s/overlays/production/replicas-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 5
# k8s/overlays/production/resources-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
template:
spec:
containers:
- name: api
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 1024Mi
# k8s/overlays/production/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Development Overlay
# k8s/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: replicas-patch.yaml
configMapGenerator:
- name: app-config
behavior: merge
literals:
- LOG_LEVEL=debug
- API_URL=http://localhost:8080
images:
- name: registry.dodatech.com/api
newTag: latest
replicas:
- name: api
count: 1
commonLabels:
environment: dev
namespace: dev
# k8s/overlays/dev/replicas-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
Strategic Merge and JSON Patches
# patches/ingress-patch.yaml â Strategic merge patch
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- api.dodatech.com
secretName: dodatech-tls
rules:
- host: api.dodatech.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 80
# patches/json-patch.yaml â JSON 6902 patch
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: NEW_RELIC_LICENSE_KEY
valueFrom:
secretKeyRef:
name: newrelic-keys
key: license_key
- op: replace
path: /spec/replicas
value: 10
- op: add
path: /metadata/annotations
value:
reloader.stakater.com/match: "true"
Using Kustomize
# Build the production overlay (dry run)
kubectl kustomize k8s/overlays/production
# Expected output:
# apiVersion: v1
# kind: ConfigMap
# metadata:
# name: dodazip-app-config-4k5m2h8g3f
# data:
# API_URL: https://api.dodatech.com
# LOG_LEVEL: warn
# NODE_ENV: production
# REDIS_URL: redis://redis-cluster.production:6379
# ---
# apiVersion: apps/v1
# kind: Deployment
# metadata:
# labels:
# app.kubernetes.io/managed-by: kustomize
# app.kubernetes.io/part-of: dodazip
# name: dodazip-api
# spec:
# replicas: 5
# ...
# Apply to cluster
kubectl apply -k k8s/overlays/production
# Expected output:
# configmap/dodazip-app-config-4k5m2h8g3f created
# deployment.apps/dodazip-api created
# service/dodazip-api created
# Diff between overlays
kubectl diff -k k8s/overlays/dev -k k8s/overlays/production
# Delete everything built from an overlay
kubectl delete -k k8s/overlays/production
Generators and Transformers
# kustomization.yaml with generators
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
secretGenerator:
- name: app-secrets
envs:
- .env.secret
type: Opaque
configMapGenerator:
- name: app-config
files:
- configs/app.properties
- configs/logback.xml
generatorOptions:
disableNameSuffixHash: false
labels:
type: generated
annotations:
note: generated-by-kustomize
patchesStrategicMerge:
- patches/tolerations.yaml
namespace: production
namePrefix: prod-
nameSuffix: -v2
commonAnnotations:
deployed-by: argo-cd
environment: production
Common Configuration Mistakes
Not using
namePrefixornameSuffixfor resource isolation: Without prefixes, the same base deployed to multiple namespaces produces name conflicts. UsenamePrefix: env-per overlay.Forgetting
behavior: mergeon ConfigMap/Secret generators: Without merge behavior, each overlay creates a separate ConfigMap instead of extending the base.Patching the wrong target: Patch targets must match
group,version,kind,name,namespace, andlabelSelector. Overly broad patches affect unintended resources.Using strategic merge when JSON patch is needed: Strategic merge patches can only modify existing fields. JSON 6902 patches add, remove, or replace arbitrary paths.
Not validating output before apply: Always run
kubectl kustomize overlay/ | kubectl apply --dry-run=client -f -to catch syntax errors before making cluster changes.
Practice Questions
How does Kustomize differ from Helm? Answer: Kustomize is template-free â it patches raw YAML using overlays. Helm uses Go templates. Kustomize is built into kubectl; Helm is a separate CLI with release management.
What is an overlay in Kustomize? Answer: An overlay is a directory with a
kustomization.yamlthat references a base and adds patches, generators, or configuration changes for a specific environment.What is the difference between strategic merge and JSON patches? Answer: Strategic merge patches modify Kubernetes objects by merging YAML. JSON patches (JSON 6902) perform specific operations (
add,remove,replace) on arbitrary paths.How do generators work in Kustomize? Answer: Generators create ConfigMaps and Secrets from literals, files, or .env entries. They automatically append content hashes to names, triggering pod rotation on change.
Challenge
Create a complete Kustomize setup for a microservice: write base manifests (Deployment, Service, ConfigMap, Ingress), create overlays for dev (1 replica, debug logging, local API URL), staging (3 replicas, warn logging, staging API), and production (5+ replicas with HPA, resource limits, TLS Ingress, production secrets). Use strategic merge patches for resource changes and JSON patches for adding environment variables. Deploy each overlay to its respective namespace.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro