Kustomize Kubernetes Configuration Management
Kustomize is a Kubernetes-native configuration management tool that lets you customize YAML manifests without templating — using bases and overlays to manage environment-specific differences. Built into kubectl since 1.14, Kustomize is essential for managing Kubernetes configuration across development, staging, and production environments.
Prerequisites
kubectl1.14+ (Kustomize is built in)- Kubernetes cluster access
- Basic familiarity with Kubernetes YAML manifests
Install Kustomize
Kustomize is bundled with kubectl, but installing the standalone binary gives you the latest version:
# Install standalone Kustomize CLI (recommended for latest features)
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
# Verify installation
kustomize version
# Alternatively, use kubectl's built-in kustomize
kubectl kustomize --help
Understanding Bases and Overlays
Kustomize uses a layering approach:
k8s/
├── base/ # Common configuration shared across environments
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── overlays/ # Environment-specific customizations
├── development/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
├── staging/
│ ├── kustomization.yaml
│ └── resource-patch.yaml
└── production/
├── kustomization.yaml
└── hpa.yaml
- Base: vanilla Kubernetes manifests with sensible defaults
- Overlays: target a base and apply patches, new resources, or transformations
Creating a Base Configuration
# k8s/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 1
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: my-org/web-app:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
env:
- name: LOG_LEVEL
value: info
# k8s/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: web-app
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 8080
# k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
managed-by: kustomize
app.kubernetes.io/name: web-app
# Preview the base output
kustomize build k8s/base/
# Apply the base directly
kubectl apply -k k8s/base/
Environment Overlays
# k8s/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Reference the base
bases:
- ../../base
# Add namespace
namespace: production
# Override the image tag for this environment
images:
- name: my-org/web-app
newTag: v1.2.3
# Additional resources specific to production
resources:
- hpa.yaml
- ingress.yaml
# Apply patches
patches:
- path: replica-patch.yaml
target:
kind: Deployment
name: web-app
- path: resource-limits-patch.yaml
# Add production-specific labels
commonLabels:
environment: production
# k8s/overlays/production/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
# k8s/overlays/development/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
namespace: development
images:
- name: my-org/web-app
newTag: latest
# Add name prefix to avoid conflicts
namePrefix: dev-
commonLabels:
environment: development
# Preview production manifests
kustomize build k8s/overlays/production/
# Apply production overlay
kubectl apply -k k8s/overlays/production/
# Diff current cluster state vs kustomize output
kubectl diff -k k8s/overlays/production/
Patches and Transformers
Kustomize supports multiple patch formats:
Strategic Merge Patch (merge-based, uses Kubernetes merge strategy):
# resource-limits-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
template:
spec:
containers:
- name: web-app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
env:
- name: LOG_LEVEL
value: warn
JSON 6902 Patch (precise, operation-based):
# json-patch.yaml
- op: replace
path: /spec/replicas
value: 5
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: FEATURE_FLAG
value: "enabled"
- op: remove
path: /spec/template/spec/containers/0/livenessProbe
# Reference JSON patch in kustomization.yaml
patches:
- path: json-patch.yaml
target:
kind: Deployment
name: web-app
options:
allowNameChange: false
Inline patches (no separate file needed):
patches:
- target:
kind: Deployment
labelSelector: "app=web-app"
patch: |-
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: ENVIRONMENT
value: production
Generators for ConfigMaps and Secrets
Kustomize can generate ConfigMaps and Secrets from files or literals, and automatically adds a hash suffix to trigger rolling updates:
# kustomization.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- MAX_CONNECTIONS=100
files:
- config.properties
- name: nginx-config
files:
- nginx.conf
secretGenerator:
- name: app-secrets
literals:
- DB_PASSWORD=supersecret
- API_KEY=myapikey
options:
disableNameSuffixHash: false # Keep hash for auto-rolling updates
- name: tls-secret
files:
- tls.crt
- tls.key
type: kubernetes.io/tls
# Verify the generated ConfigMap
kustomize build . | grep -A 20 "kind: ConfigMap"
# The hash is added automatically: app-config-7fghj9k2m
# Deployments referencing this ConfigMap auto-roll when config changes
CI/CD Integration
GitHub Actions:
# .github/workflows/deploy.yml
name: Deploy to Kubernetes
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubeconfig
run: |
echo "${{ secrets.KUBECONFIG }}" | base64 -d > /tmp/kubeconfig
export KUBECONFIG=/tmp/kubeconfig
- name: Update image tag
run: |
cd k8s/overlays/production
kustomize edit set image my-org/web-app=my-org/web-app:${{ github.sha }}
- name: Deploy
run: |
kubectl apply -k k8s/overlays/production/
kubectl rollout status deployment/web-app -n production
GitLab CI:
# .gitlab-ci.yml
deploy-production:
stage: deploy
image: bitnami/kubectl:latest
script:
- kustomize edit set image my-org/web-app=my-org/web-app:$CI_COMMIT_SHA
--kustomization=k8s/overlays/production/kustomization.yaml
- kubectl apply -k k8s/overlays/production/
only:
- main
Troubleshooting
Build errors — resource not found:
# Validate kustomization structure
kustomize build k8s/overlays/production/ 2>&1
# Check all referenced files exist
ls k8s/base/*.yaml k8s/overlays/production/*.yaml
Patches not applying:
# Use kustomize build to see the rendered output
kustomize build k8s/overlays/production/ | grep -A 5 "replicas"
# Ensure the target name in the patch matches the resource name exactly
# Common error: strategic merge patch name doesn't match resource name
Namespace not being set:
# Verify namespace field is set in overlay kustomization.yaml
grep namespace k8s/overlays/production/kustomization.yaml
# Note: namespace field does NOT apply to Namespace resources themselves
ConfigMap hash changing unexpectedly:
# If you want a stable name (no hash suffix):
configMapGenerator:
- name: my-config
literals:
- KEY=value
options:
disableNameSuffixHash: true
Conclusion
Kustomize provides a clean, template-free approach to Kubernetes configuration management by layering overlays on top of shared bases. Its built-in generators, patch mechanisms, and transformers handle the most common environment customization patterns without introducing complex templating syntax. Integrate Kustomize into your CI/CD pipelines to automate image tag updates and maintain a single source of truth for cluster configuration in Git.


