19 min to read
What is Kustomize? A Configuration Management Tool for Kubernetes
A comprehensive guide to Kustomize usage and implementation

Overview
This post explores Kustomize, a powerful tool for customizing Kubernetes manifests.
What is Kustomize?
It lets you customize raw, template-free YAML files for multiple environments, leaving the original files untouched and usable as-is.
Key Features of Kustomize
✅ No Templates: Uses plain YAML files without templating languages
✅ Overlay-Based: Generates variants from a common base
✅ Declarative: Describes the desired state, not how to achieve it
✅ Native Integration: Built into kubectl since v1.14
✅ GitOps Friendly: Perfect for source-controlled configuration
✅ No Duplication: Reuses common configurations with minimal changes
Why Kustomize?
The Configuration Challenge
Managing Kubernetes YAML manifests across multiple environments presents several challenges:
- Duplication: Copy-pasting configurations for different environments leads to maintenance issues
- Environment Differences: Managing variations between dev, staging, and production
- Configuration Drift: Ensuring consistency across environments
- Change Management: Applying changes systematically across all environments
- Copy & Paste: Duplicate files for each environment (error-prone, hard to maintain)
- Templates: Use templating engines like Helm (adds complexity with templating language)
- Overlays: Apply patches to base configurations (Kustomize's approach)
Kustomize vs Helm
Feature | Kustomize | Helm |
---|---|---|
Approach | Overlay-based patching | Template-based generation |
Syntax | Native Kubernetes YAML | Go templates syntax |
Learning Curve | Lower (if familiar with Kubernetes YAML) | Higher (requires learning template syntax) |
Package Management | No central repository | Charts repository system |
Versioning | Git-based versioning | Chart versioning |
Integration | Native in kubectl | Separate CLI tool |
Best For | Environment-specific variations with same resources | Distributing/reusing complete applications |
Installation
Installing Kustomize CLI
# Method 1: Direct download and install
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
# Method 2: Using Homebrew (macOS)
brew install kustomize
# Method 3: Using Chocolatey (Windows)
choco install kustomize
Verifying Installation
kustomize version
Using Built-in kubectl Support
Since Kubernetes v1.14, Kustomize functionality is built into kubectl:
# Using kubectl with Kustomize
kubectl apply -k <directory>
kubectl diff -k <directory>
kubectl delete -k <directory>
Core Concepts
1. Base and Overlays
Kustomize follows a “base + overlay” model:
- Base: Common YAML manifests shared across all environments
- Overlays: Environment-specific customizations applied on top of the base
- Variants: The resulting manifests for each environment
Typical Project Structure:
├── base
│ ├── kustomization.yaml # Defines base resources
│ ├── deployment.yaml # Common deployment configuration
│ ├── service.yaml # Common service configuration
│ └── configmap.yaml # Common configmap
└── overlays
├── dev
│ ├── kustomization.yaml # References base + dev patches
│ └── patch-replicas.yaml # Dev-specific patches
├── staging
│ ├── kustomization.yaml # References base + staging patches
│ └── patch-replicas.yaml # Staging-specific patches
└── production
├── kustomization.yaml # References base + production patches
├── patch-replicas.yaml # Production-specific patches
└── patch-resources.yaml # Additional production patches
2. Kustomization File
The kustomization.yaml
is the configuration file that tells Kustomize what resources to include and how to transform them.
Base Kustomization
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: my-application
Overlay Kustomization
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: dev-
namespace: dev
commonLabels:
environment: dev
variant: development
patches:
- path: deployment-patch.yaml
# overlays/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-application
spec:
replicas: 2
Kustomize Transformers
Kustomize uses various transformers to modify resources. These are the key transformers available:
1. Name Transformers
# Add prefix to all resource names
namePrefix: dev-
# Add suffix to all resource names
nameSuffix: -v1
# Replace names
replacements:
- source:
kind: ConfigMap
name: source-name
targets:
- select:
kind: Deployment
fieldPaths:
- spec.template.spec.volumes[0].configMap.name
2. Label Transformers
# Add labels to all resources
commonLabels:
environment: dev
app: my-application
# Add annotations to all resources
commonAnnotations:
note: "This is a dev environment"
version: "v1.0.0"
3. Patches
Strategic Merge Patches
Strategic merge patches use the Kubernetes resource structure to intelligently merge changes:
# kustomization.yaml
patches:
- path: patch-deployment.yaml
target:
kind: Deployment
# patch-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3 # Will override the replicas in base
template:
spec:
containers:
- name: nginx
resources: # Will be merged with existing resources
limits:
memory: "512Mi"
JSON 6902 Patches
For more precise changes, JSON 6902 patches can be used:
# kustomization.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: my-deployment
path: deployment-patch.yaml
# deployment-patch.yaml
- op: replace
path: /spec/replicas
value: 5
- op: add
path: /metadata/annotations/monitoring
value: "true"
4. ConfigMap and Secret Generators
# Generate ConfigMaps from files and literals
configMapGenerator:
- name: app-config
files:
- application.properties
- settings.json
literals:
- ENVIRONMENT=dev
- DEBUG=true
# Generate Secrets from files and literals
secretGenerator:
- name: app-secrets
files:
- secret.properties
literals:
- API_KEY=secret-value
type: Opaque
Practical Implementation Guide
Let’s build a complete example of a microservice deployment with Kustomize.
Step 1: Create Base Structure
Create basic directory structure and files:
mkdir -p kustomize-demo/{base,overlays/{dev,staging,production}}
Step 2: Define Base Resources
Deployment
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
selector:
matchLabels:
app: web-app
replicas: 1
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: nginx:1.19
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: web-app-config
Service
# base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 80
type: ClusterIP
ConfigMap
# base/nginx-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-app-config
data:
default.conf: |
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Base Kustomization
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- nginx-config.yaml
commonLabels:
app: web-app
Step 3: Create Overlays
Dev Environment
# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: dev-
namespace: dev
commonLabels:
environment: dev
variant: development
patches:
- path: deployment-patch.yaml
# overlays/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
Staging Environment
# overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: staging-
namespace: staging
commonLabels:
environment: staging
variant: pre-production
patches:
- path: deployment-patch.yaml
# overlays/staging/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
template:
spec:
containers:
- name: web-app
resources:
limits:
memory: "256Mi"
cpu: "300m"
Production Environment
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namePrefix: prod-
namespace: production
commonLabels:
environment: production
variant: stable
patches:
- path: deployment-patch.yaml
- path: service-patch.yaml
# overlays/production/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 5
template:
spec:
containers:
- name: web-app
image: nginx:1.19-alpine
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
# overlays/production/service-patch.yaml
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
type: LoadBalancer
Step 4: Building and Applying
Build Manifests
# Generate manifests for different environments
kustomize build overlays/dev > dev-manifests.yaml
kustomize build overlays/staging > staging-manifests.yaml
kustomize build overlays/production > production-manifests.yaml
Apply to Cluster
# Using kustomize directly
kustomize build overlays/dev | kubectl apply -f -
# Using kubectl's built-in support
kubectl apply -k overlays/dev/
Advanced Features and Techniques
Component Reuse
Components are reusable pieces of kustomization that can be included in different bases or overlays:
# components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- prometheus.yaml
- grafana.yaml
# To use the component:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/monitoring
Composition and Inheritance
Kustomize supports multiple levels of composition:
# platform-base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- network-policy.yaml
# service-base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../platform-base
- deployment.yaml
- service.yaml
Custom Resource Transformers
Advanced transformations can be achieved with custom transformers:
transformers:
- mytransformer.yaml
# mytransformer.yaml
apiVersion: builtin
kind: PatchTransformer
metadata:
name: custom-transformer
patch: |
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: CUSTOM_ENV
value: custom-value
target:
kind: Deployment
Integrating Kustomize with CI/CD
GitOps Workflow
A GitOps approach to Kustomize typically involves:
- Source Control: Maintain base and overlays in Git
- Automated Builds: CI pipeline generates environment-specific manifests
- Deployment: CD system applies manifests to clusters
Example: GitLab CI Pipeline
# .gitlab-ci.yml
stages:
- validate
- build
- deploy
validate:
stage: validate
script:
- kustomize build overlays/dev | kubeval --strict
- kustomize build overlays/staging | kubeval --strict
- kustomize build overlays/production | kubeval --strict
build-manifests:
stage: build
script:
- kustomize build overlays/dev > build/dev-manifests.yaml
- kustomize build overlays/staging > build/staging-manifests.yaml
- kustomize build overlays/production > build/production-manifests.yaml
artifacts:
paths:
- build/
deploy-dev:
stage: deploy
environment: dev
script:
- kubectl apply -f build/dev-manifests.yaml
only:
- develop
deploy-staging:
stage: deploy
environment: staging
script:
- kubectl apply -f build/staging-manifests.yaml
only:
- main
deploy-production:
stage: deploy
environment: production
script:
- kubectl apply -f build/production-manifests.yaml
only:
- tags
when: manual
Example: ArgoCD Integration
ArgoCD can directly use Kustomize to deploy applications:
# Application CRD for ArgoCD
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-application-dev
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/my-kustomize-repo.git
targetRevision: HEAD
path: overlays/dev
destination:
server: https://kubernetes.default.svc
namespace: dev
syncPolicy:
automated:
prune: true
selfHeal: true
Common Patterns and Best Practices
- Directory Structure
- Keep base configurations minimal and environment-agnostic
- Use meaningful names for overlay directories
- Group related components together
- Consider using components for cross-cutting concerns
- Version Control
- Commit base configurations and overlays together
- Document environment-specific requirements
- Use tags for stable versions
- Consider feature branches for major changes
- Resource Management
- Use namePrefix or nameSuffix to avoid naming conflicts
- Implement proper namespace management
- Use commonLabels for resource tracking
- Generate configmaps and secrets instead of hardcoding
- Security Considerations
- Never commit sensitive data in base configurations
- Use secretGenerator for sensitive information
- Consider using Sealed Secrets or external secret management
- Implement proper RBAC configurations
Real-World Example: Multi-Environment Microservice Deployment
An e-commerce company uses Kustomize to manage their 20+ microservices across development, staging, and production environments.
Implementation:
- Platform base with common policies, RBAC, and network rules
- Service-specific bases with standard configurations
- Environment overlays customizing resources and replica counts
- Region-specific overlays for global deployment
- ArgoCD integration for GitOps-based continuous delivery
Benefits:
- 90% reduction in duplicate configuration
- Consistent environments with environment-specific tuning
- Faster onboarding of new developers
- Audit trail of all configuration changes
- Reliable continuous deployment
Troubleshooting
Common Issues and Solutions
1. Resource Not Found
# Verify the resource exists in base
kubectl kustomize base
# Check overlay configuration
kubectl kustomize overlays/dev
Solution: Ensure file paths in resources sections are correct and verify file existence.
2. Patch Not Applied
# Debug patch application
kustomize build --load-restrictor LoadRestrictionsNone overlays/dev
# Verify patch syntax
kustomize build overlays/dev --enable-alpha-plugins
Solution: Check that target selectors match resource names exactly, including any name prefixes/suffixes.
3. Namespace Issues
# Verify namespace configuration
kubectl config get-contexts
kubectl config set-context --current --namespace=target-namespace
Solution: Ensure namespace is defined in kustomization.yaml if needed.
4. Version Compatibility
# Check Kustomize version
kustomize version
# Check kubectl version
kubectl version
Solution: Update Kustomize or kubectl to compatible versions.
Advanced Features
1. Strategic Merge Patches vs JSON Patches
# Strategic Merge Patch (understands Kubernetes semantics)
patchesStrategicMerge:
- |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
template:
spec:
containers:
- name: nginx
resources:
limits:
memory: 512Mi
# JSON 6902 Patch (more precise control)
patchesJson6902:
- target:
version: v1
kind: Deployment
name: my-deployment
path: patch.yaml
2. Cross-Cutting Fields with Transformers
# Transformer to add fields to all resources
apiVersion: builtin
kind: PatchTransformer
metadata:
name: global-settings
patch: |-
- op: add
path: /metadata/labels/release-id
value: v2023-01
target:
labelSelector: app
3. Composition with Components
# Component for monitoring
components:
- ../../components/monitoring
- ../../components/logging
Conclusion and Takeaways
Key Benefits of Kustomize
- Simplicity: Uses native Kubernetes YAML without templating language
- Reusability: Promotes sharing common configurations
- Modularity: Enables compositional, layer-based approach
- GitOps-Friendly: Works well with Git workflows and CI/CD systems
- Kubernetes-Native: Integrated directly into kubectl
When to Choose Kustomize
- Managing multiple environments with similar configurations
- Need to maintain original manifests in readable form
- GitOps-based workflows
- Environments with predictable variations
- Teams already familiar with Kubernetes YAML
Comments