Warrior, now that you understand Helm, the next important Kubernetes configuration tool is Kustomize.
The key idea is very simple:
Kustomize lets you reuse normal Kubernetes YAML and customize it for different environments without creating completely separate YAML files.
Imagine you have a Node.js application.
In development:
replicas: 1
image: node-api:devStaging:
replicas: 2
image: node-api:stagingProduction:
replicas: 5
image: node-api:1.4.0Most of the Kubernetes configuration is identical.
Without Kustomize, you might create:
deployment-dev.yaml
deployment-staging.yaml
deployment-prod.yamlThis causes duplication.
deployment-dev.yaml
โ
deployment-staging.yaml
โ
deployment-prod.yamlEventually someone changes one file but forgets another.
Kustomize solves this using:
Base
โ
โโโโโโโโโผโโโโโโโโ
โ โ โ
Dev Staging ProdKustomize is a Kubernetes-native configuration customization tool.
It allows you to define:
Base Kubernetes YAML
+
Environment-specific changes
โ
Final Kubernetes YAMLUnlike Helm, Kustomize does not primarily use templates.
Instead, it works with existing Kubernetes YAML and applies modifications/patches.
This is very important.
You don't necessarily need a separate CLI.
You can use:
kubectl apply -k .Notice:
-fmeans normal YAML:
kubectl apply -f deployment.yamlwhile:
-kmeans Kustomize:
kubectl apply -k .Think:
kubectl apply -f
โ
regular YAML
kubectl apply -k
โ
Kustomize configurationA common structure is:
k8s/
โ
โโโ base/
โ โโโ deployment.yaml
โ โโโ service.yaml
โ โโโ kustomization.yaml
โ
โโโ overlays/
โ
โโโ dev/
โ โโโ kustomization.yaml
โ โโโ patch.yaml
โ
โโโ staging/
โ โโโ kustomization.yaml
โ โโโ patch.yaml
โ
โโโ production/
โโโ kustomization.yaml
โโโ patch.yamlMental model:
BASE
โ
โโโโโโโโโโโโผโโโโโโโโโโโ
โ โ โ
DEV STAGING PROD
โ โ โ
โ โ โ
customized customized customized
Kubernetes Kubernetes Kubernetes
resources resources resourcesA base contains configuration common to all environments.
For example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 2
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: myregistry/node-api:latest
ports:
- containerPort: 3000This is our base.
kustomization.yaml#Kustomize needs a file called:
kustomization.yamlExample:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yamlThis tells Kustomize:
"These Kubernetes resources belong together."
Let's build a Node.js API.
Directory:
k8s/
โโโ base/
โโโ deployment.yaml
โโโ service.yaml
โโโ kustomization.yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 2
selector:
matchLabels:
app: node-api
template:
metadata:
labels:
app: node-api
spec:
containers:
- name: node-api
image: myregistry/node-api:1.0.0
ports:
- containerPort: 3000
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"apiVersion: v1
kind: Service
metadata:
name: node-api
spec:
selector:
app: node-api
ports:
- port: 80
targetPort: 3000apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yamlNow we have our base.
Directory:
k8s/
โ
โโโ base/
โ โโโ deployment.yaml
โ โโโ service.yaml
โ โโโ kustomization.yaml
โ
โโโ overlays/
โโโ dev/
โโโ kustomization.yaml
โโโ patch.yamlWe want development to have:
replicas = 1
image = node-api:devWe don't want to duplicate the entire Deployment.
Instead, we patch it.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch.yamlNotice:
resources:
- ../../baseWe're saying:
Use the base configuration.
Then:
patches:
- path: patch.yamlmeans:
Apply these changes on top of the base.
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 1
template:
spec:
containers:
- name: node-api
image: myregistry/node-api:devThe final result becomes approximately:
Deployment:
name: node-api
replicas: 1
image: myregistry/node-api:dev
resources:
requests:
cpu: 250m
memory: 256MiThe resources from the base remain.
Only the required values changed.
This is one of the most useful commands:
kubectl kustomize overlays/devIt doesn't deploy anything.
It generates the final Kubernetes YAML.
Think:
Base
+
Patch
โ
kubectl kustomize
โ
Final YAMLYou can inspect it before deployment.
Development:
kubectl apply -k overlays/devStaging:
kubectl apply -k overlays/stagingProduction:
kubectl apply -k overlays/productionThis is extremely convenient for CI/CD.
Our structure:
k8s/
โ
โโโ base/
โ โโโ deployment.yaml
โ โโโ service.yaml
โ โโโ kustomization.yaml
โ
โโโ overlays/
โโโ dev/
โ โโโ kustomization.yaml
โ โโโ patch.yaml
โ
โโโ staging/
โ โโโ kustomization.yaml
โ โโโ patch.yaml
โ
โโโ production/
โโโ kustomization.yaml
โโโ patch.yamlProduction kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: patch.yamlProduction patch:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-api
spec:
replicas: 5
template:
spec:
containers:
- name: node-api
image: myregistry/node-api:1.4.0So:
BASE
replicas: 2
image: node-api:1.0.0
โ
PRODUCTION OVERLAY
replicas: 5
image: node-api:1.4.0Kustomize provides a convenient images field.
Instead of patching the image:
images:
- name: myregistry/node-api
newTag: "1.4.0"Example:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
images:
- name: myregistry/node-api
newTag: "1.4.0"Base:
image: myregistry/node-api:1.0.0Final:
image: myregistry/node-api:1.4.0This is very useful in CI/CD.
You can also change the repository:
images:
- name: myregistry/node-api
newName: 123456789.dkr.ecr.ap-south-1.amazonaws.com/node-api
newTag: "1.4.0"So development could use:
myregistry/node-apiwhile production uses:
AWS ECRKustomize can generate ConfigMaps.
Example:
configMapGenerator:
- name: node-api-config
literals:
- NODE_ENV=production
- LOG_LEVEL=info
- PORT=3000Complete:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
configMapGenerator:
- name: node-api-config
literals:
- NODE_ENV=production
- LOG_LEVEL=info
- PORT=3000Kustomize generates a ConfigMap.
An important feature is that generated ConfigMaps can receive a content-based suffix/hash, which helps trigger Pod rollouts when configuration changes.
For example, conceptually:
node-api-config-8g7f6ginstead of simply:
node-api-configThis helps prevent stale configuration when referenced appropriately.
Suppose:
app.envcontains:
NODE_ENV=production
LOG_LEVEL=info
PORT=3000You can use:
configMapGenerator:
- name: node-api-config
envs:
- app.envKustomize generates the ConfigMap.
Kustomize can also generate Secrets.
For example:
secretGenerator:
- name: database-secret
literals:
- DB_USER=admin
- DB_PASSWORD=supersecretHowever:
โ ๏ธ Don't put real production secrets directly into Git just because Kustomize supports secretGenerator.
Remember:
Base64 โ encryptionFor production, consider:
AWS Secrets Manager
GCP Secret Manager
Azure Key Vault
Vault
External Secrets OperatorYou can specify a namespace:
namespace: developmentFor example:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: development
resources:
- ../../baseKustomize will apply the namespace to namespace-scoped resources.
You can add common labels:
commonLabels:
team: platform
environment: productionDepending on your Kustomize version/features, newer recommended fields may include labels; the exact transformation behavior should be tested with your manifests.
Example concept:
Deployment
Service
ConfigMapall receive:
environment=productionThis is useful for:
Kustomize can modify resource names.
namePrefix: prod-If base contains:
metadata:
name: node-apithe generated name becomes:
prod-node-apiSimilarly:
nameSuffix: -v1could produce:
node-api-v1Be careful with names because references between resources must remain correctly transformed.
One of the most important Kustomize concepts is patching.
Suppose base has:
replicas: 2Production needs:
replicas: 5Instead of copying the Deployment:
replicas: 5you patch the existing resource.
Think:
Original YAML
โ
+ Patch
โ
Modified YAMLKustomize also supports JSON 6902 patches.
Example:
patches:
- target:
group: apps
version: v1
kind: Deployment
name: node-api
patch: |-
- op: replace
path: /spec/replicas
value: 5This explicitly says:
Find Deployment/node-api
Replace:
/spec/replicas
With:
5This is powerful for precise changes.
You'll encounter different patch mechanisms.
Easy for common Kubernetes resource modifications.
Example:
spec:
replicas: 5More explicit:
- op: replace
path: /spec/replicas
value: 5Think:
Strategic/structured patch
โ
"Change this Kubernetes field"
JSON 6902
โ
"Perform this exact operation at this exact path"For many modern Kustomize configurations, the unified patches field can be used for both styles.
Let's make this realistic.
Imagine your architecture:
Internet
โ
โ
Ingress
โ
โโโโโโโโโดโโโโโโโโ
โ โ
Next.js Service Node.js Service
โ โ
Next.js Pods Node Pods
โ
โโโโโโโโดโโโโโโโ
โ โ
Redis PostgreSQLYou could maintain:
k8s/
โ
โโโ base/
โ โโโ frontend-deployment.yaml
โ โโโ frontend-service.yaml
โ โโโ backend-deployment.yaml
โ โโโ backend-service.yaml
โ โโโ ingress.yaml
โ โโโ kustomization.yaml
โ
โโโ overlays/
โโโ dev/
โโโ staging/
โโโ production/The base contains architecture.
The overlays contain environment differences.
For example:
Frontend replicas: 1
Backend replicas: 1
Backend image:
node-api:dev
Database:
development DB
Log level:
debugFrontend replicas: 2
Backend replicas: 2
Backend image:
node-api:staging
Log level:
infoFrontend replicas: 5
Backend replicas: 5
Backend image:
node-api:1.4.0
Log level:
warn
Resources:
higherNotice something important:
The architecture remains the same.
Only configuration changes.
This is a very common interview question.
Templates
+
values.yaml
+
Helm engine
โ
Kubernetes YAMLExample:
replicas: {{ .Values.replicaCount }}Values:
replicaCount: 5Base YAML
+
Overlay/Patches
โ
Kubernetes YAMLNo traditional template language is required.
| Feature | Helm | Kustomize |
|---|---|---|
| Templates | Yes | No traditional templates |
| Values | Yes | Overlays/patches |
| Packaging | Strong | Not its primary goal |
| Releases | Yes | No Helm-style release |
| Rollbacks | Helm release history | Usually Git/Kubernetes rollout mechanisms |
| Kubernetes-native | External tool | Integrated with kubectl |
| Reuse | Templates | Bases/overlays |
| Complexity | Can become template-heavy | Often straightforward |
| Dependencies | Strong chart dependency system | More composition-oriented |
| Good for | Reusable packages/platforms | Environment customization |
Remember:
Chart
โ
โโโ templates/
โโโ values.yaml
โ
โ
Helm
โ
โ
Rendered Kubernetes YAMLBase YAML
โ
โโโโโโโโโโโโโโโ
โ โ
Dev patch Prod patch
โ โ
โ โ
Dev YAML Prod YAMLThis distinction is extremely important.
Yes.
You don't necessarily have to choose only one.
For example:
Helm
โ
Generate Kubernetes resources
โ
Kustomize
โ
Environment-specific customizationThere are multiple possible architectures, but don't add both just because you can.
More tools can mean more complexity.
Kustomize is particularly attractive when:
deployment.yaml
service.yaml
ingress.yamland simply need:
dev
staging
productioncustomizations.
Your YAML remains recognizable Kubernetes YAML.
If you're not distributing a reusable application package, Helm's packaging/release features may be unnecessary.
Helm is particularly useful when:
You want to package an applicationor:
You want configurable reusable chartsor:
You want to install third-party Kubernetes applicationsExamples include charts for common infrastructure components.
A realistic Git repository might look like:
my-platform/
โ
โโโ application/
โ โโโ frontend/
โ โโโ backend/
โ
โโโ docker/
โ
โโโ k8s/
โ
โโโ base/
โ โโโ frontend/
โ โโโ backend/
โ โโโ redis/
โ โโโ ingress/
โ
โโโ overlays/
โ
โโโ dev/
โ
โโโ staging/
โ
โโโ production/Then CI/CD can do:
kubectl apply -k k8s/overlays/productionor render it first:
kubectl kustomize k8s/overlays/productionSuppose GitHub Actions builds:
node-api:1.5.0Then CI updates:
images:
- name: myregistry/node-api
newTag: "1.5.0"Then deployment:
kubectl apply -k k8s/overlays/productionFlow:
Developer
โ
โ
Git Push
โ
โ
CI
โ
โโโ Test
โโโ Build
โโโ Docker Image
โโโ Push Registry
โ
โ
node-api:1.5.0
โ
โ
Kustomize
โ
โ
Production manifests
โ
โ
Kubernetes
โ
โ
Deployment
โ
โ
Rolling UpdateNow you're connecting the concepts you've already learned.
Kustomize's primary job is:
Generate/customize Kubernetes manifestsKubernetes does the actual deployment.
For example:
kubectl kustomize overlays/prodjust renders YAML.
Whereas:
kubectl apply -k overlays/prodrenders and applies it through Kubernetes.
kubectl kustomize overlays/devkubectl apply -k overlays/devkubectl delete -k overlays/devkubectl diff -k overlays/devThis is extremely useful before applying changes.
Create:
k8s/
โ
โโโ base/
โ โโโ deployment.yaml
โ โโโ service.yaml
โ โโโ kustomization.yaml
โ
โโโ overlays/
โโโ dev/
โ โโโ kustomization.yaml
โ โโโ patch.yaml
โ
โโโ production/
โโโ kustomization.yaml
โโโ patch.yamlBase:
replicas = 2
image = node-api:1.0.0Dev:
replicas = 1
image = node-api:devProduction:
replicas = 5
image = node-api:1.0.0Then test:
kubectl kustomize overlays/devand:
kubectl kustomize overlays/productionCompare the output.
Kustomize is a Kubernetes configuration customization tool that lets us maintain reusable base manifests and environment-specific overlays without relying on traditional templates.
No.
Kustomize โ prepares/customizes manifests
Kubernetes โ runs/manages workloadsA base contains common Kubernetes resources shared across environments.
An overlay customizes a base for a particular environment or use case.
Example:
base
โ
production overlaykubectl apply -k mean?#It tells kubectl to process a Kustomize directory and apply the generated resources.
A strong interview answer:
Helm is a templating and package/release-management tool for Kubernetes, while Kustomize customizes existing Kubernetes manifests using bases, overlays, and patches. Helm is particularly useful for reusable packages and configurable charts, while Kustomize is useful when you want to keep native YAML and apply environment-specific changes.
You've now learned:
Kubernetes
โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโ
โ โ โ
Workloads Networking Config
โ โ โ
Deployment Service ConfigMap
Pod Ingress Secret
โ
โ
Scaling
โ
HPA / CAAnd now:
Kubernetes YAML
โ
โโโโโโโโโโดโโโโโโโโโ
โ โ
Helm Kustomize
โ โ
Templates + Base + Overlays
Values + Patches
โ โ
โโโโโโโโโโฌโโโโโโโโโ
โ
Kubernetes API
โ
ClusterKustomize
โ
Customize Kubernetes YAML
Base
โ
Common configuration
Overlay
โ
Environment-specific configuration
kustomization.yaml
โ
Defines resources/customizations
kubectl kustomize
โ
Render manifests
kubectl apply -k
โ
Apply Kustomize configuration
kubectl diff -k
โ
Preview changes
Helm
โ
Templates + values + packages/releases
Kustomize
โ
Base + overlays + patchesHelm generates Kubernetes configuration from templates; Kustomize modifies existing Kubernetes configuration using bases and overlays.
We'll move from theory into actually running Kubernetes on your PC.
We'll cover:
kubectlMark it as complete to track your mastery.