Claude-skill-registry kustomize
Kubernetes native configuration management with Kustomize. Use for environment-specific configs, resource patching, manifest organization, multi-environment deployments, and GitOps workflows. Triggers: kustomize, kustomization, overlay, base, patch, strategic merge, json patch, json6902, configmap generator, secret generator, namespace, namePrefix, nameSuffix, commonLabels, commonAnnotations, component, transformer, replacement, multi-environment, dev/staging/prod configs, k8s manifest management.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/kustomize" ~/.claude/skills/majiayu000-claude-skill-registry-kustomize && rm -rf "$T"
skills/data/kustomize/SKILL.mdKustomize Skill
Overview
Kustomize is a Kubernetes-native configuration management tool that uses declarative customization to manage environment-specific configurations without templates. It follows the principles of declarative application management and integrates directly with kubectl.
Primary use cases: Multi-environment deployments, resource patching, GitOps workflows, ConfigMap/Secret generation, cross-cutting transformations.
What This Skill Covers
- Multi-Environment Overlays: Dev/staging/prod pattern with base + overlays
- Patch Strategies: Strategic merge vs JSON 6902 patches, when to use each
- Generators: ConfigMap and Secret generation with automatic content hashing
- Transformers: Cross-cutting changes (labels, annotations, namespace, namePrefix/Suffix, images, replicas)
- Components: Reusable optional feature bundles (monitoring, ingress, debug-tools)
- Replacements: Dynamic field substitution for propagating values between resources
- GitOps Integration: ArgoCD, Flux, CI/CD pipeline patterns
- Security: Secret management, image pinning, validation, RBAC patterns
Core Concepts
- Base: A directory containing a
and a set of resources (typically common/shared configurations)kustomization.yaml - Overlay: A directory with a
that refers to a base and applies customizations (environment-specific configs like dev/staging/prod)kustomization.yaml - Patch: A partial resource definition that modifies existing resources (strategic merge or JSON patch)
- Component: Reusable customization bundles that can be included in multiple kustomizations (e.g., monitoring, ingress)
- Generator: Creates ConfigMaps and Secrets from files, literals, or env files with automatic content hashing
- Transformer: Modifies resources across the board (labels, annotations, namespaces, namePrefix, nameSuffix, replicas, images)
- Replacement: Dynamic field substitution that propagates values between resources (e.g., ConfigMap names with hash suffixes)
Key Principles
- Bases are reusable: Define common configuration once, customize per environment
- Overlays are composable: Stack multiple customizations for different environments
- Resources are not modified: Original base files remain unchanged
- No templating: Uses declarative merging instead of variable substitution
- kubectl integration:
natively supports Kustomizekubectl apply -k <directory> - Content hashing: ConfigMaps and Secrets get automatic name suffixes based on content for immutable deployments
Directory Structure
Recommended Layout
k8s/ ├── base/ │ ├── kustomization.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── configmap.yaml ├── overlays/ │ ├── dev/ │ │ ├── kustomization.yaml │ │ ├── patch-replicas.yaml │ │ └── config-values.env │ ├── staging/ │ │ ├── kustomization.yaml │ │ ├── patch-replicas.yaml │ │ └── config-values.env │ └── prod/ │ ├── kustomization.yaml │ ├── patch-replicas.yaml │ ├── patch-resources.yaml │ └── config-values.env └── components/ ├── monitoring/ │ ├── kustomization.yaml │ └── servicemonitor.yaml └── ingress/ ├── kustomization.yaml └── ingress.yaml
Multi-Service Structure
k8s/ ├── base/ │ ├── kustomization.yaml (references all services) │ ├── namespace.yaml │ └── services/ │ ├── api/ │ │ ├── kustomization.yaml │ │ ├── deployment.yaml │ │ └── service.yaml │ └── worker/ │ ├── kustomization.yaml │ ├── deployment.yaml │ └── service.yaml └── overlays/ ├── dev/ │ └── kustomization.yaml ├── staging/ │ └── kustomization.yaml └── prod/ └── kustomization.yaml
Quick Reference
Common Operations
| Task | Command |
|---|---|
| Build manifests | |
| Preview changes | |
| Apply to cluster | |
| Validate syntax | |
| Update image tag | |
| Add resource | |
| Add ConfigMap | |
Multi-Environment Pattern
k8s/ ├── base/ # Shared configuration ├── overlays/ │ ├── dev/ # Development-specific (low resources, debug enabled) │ ├── staging/ # Staging-specific (moderate resources, monitoring) │ └── prod/ # Production-specific (high resources, HA, security) └── components/ # Optional features (monitoring, ingress, debug-tools)
Generator Quick Start
| Generator Type | Use Case | Example |
|---|---|---|
| ConfigMap literals | Simple key-value config | |
| ConfigMap files | Config files | |
| ConfigMap env file | Environment variables | |
| Secret literals | Simple secrets | |
| Secret files | Certificate/key files | |
Transformer Quick Start
| Transformer | Use Case | Example |
|---|---|---|
| namespace | Set namespace for all resources | |
| namePrefix | Add prefix to resource names | |
| nameSuffix | Add suffix to resource names | |
| commonLabels | Add labels to all resources | |
| commonAnnotations | Add annotations to all resources | |
| images | Update container images | |
| replicas | Set replica count | |
Workflow
1. Create Base Configuration
Start with common resources that apply to all environments:
mkdir -p k8s/base cd k8s/base # Create resource files (deployment.yaml, service.yaml, etc.) # Create kustomization.yaml to reference them
2. Build and Verify Base
kustomize build k8s/base # or kubectl kustomize k8s/base
3. Create Environment Overlays
mkdir -p k8s/overlays/dev cd k8s/overlays/dev # Create kustomization.yaml that references base # Add patches and customizations
4. Apply to Cluster
# Preview changes kubectl diff -k k8s/overlays/dev # Apply kubectl apply -k k8s/overlays/dev # Delete kubectl delete -k k8s/overlays/dev
5. Iterate and Refactor
- Extract common patterns to components
- Use generators for ConfigMaps and Secrets
- Apply transformers for cross-cutting concerns
Patch Strategies
Strategic Merge Patch (Default)
Strategic merge is the default patch strategy. It uses Kubernetes-aware merging logic.
Strategic Merge Characteristics
- Merges maps/objects by key
- Replaces arrays by default (unless special directives)
- Uses
and$patch: delete
directives$patch: replace - More intuitive for Kubernetes resources
Strategic Merge Use Cases
- Simple field updates (replicas, image, env vars)
- Adding or replacing containers
- Updating resource limits
- Most common use case
JSON Patch (RFC 6902)
JSON Patch provides precise array manipulation and field operations.
JSON Patch Characteristics
- Operations: add, remove, replace, move, copy, test
- Uses JSON Pointer paths (e.g.,
)/spec/template/spec/containers/0/image - Precise array element targeting
- More verbose but more precise
JSON Patch Use Cases
- Precise array element manipulation
- Conditional patches (test operation)
- Complex nested updates
- When strategic merge is too coarse
Component Patterns
Components are reusable customization bundles that can be selectively included in overlays. They're ideal for optional features that only some environments need.
When to Use Components
| Pattern | Use Components For | Use Patches For |
|---|---|---|
| Optional features | Monitoring, ingress, debug tools | Required modifications |
| Cross-environment reuse | Feature available in staging+prod | Environment-specific changes |
| Clean composition | Independent feature sets | Tweaking existing resources |
| Conditional inclusion | Enable per environment | Always apply in overlay |
Component Structure
# k8s/components/monitoring/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component resources: - servicemonitor.yaml - prometheusrule.yaml patches: - path: patch-metrics.yaml target: kind: Deployment labels: - pairs: prometheus.io/scrape: "true"
Including Components
# k8s/overlays/prod/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ../../base components: - ../../components/monitoring - ../../components/ingress - ../../components/security-hardening
Common Component Patterns
Monitoring Component: ServiceMonitor, PrometheusRules, metrics port patch Ingress Component: Ingress resource, TLS config, service annotations Debug Tools Component: Debug env vars, profiling ports, verbose logging Security Hardening Component: SecurityContext, NetworkPolicy, PodSecurityPolicy Backup Component: CronJob for backups, PersistentVolume, ServiceAccount with backup permissions
Component vs Overlay Decision Tree
Need to include optional features? → Component Need environment-specific values? → Overlay Need both? → Component for features + Overlay patches for values
Best Practices
Directory Organization
- Keep bases generic: Avoid environment-specific values in base
- One concern per patch: Create separate patch files for different modifications
- Use descriptive names:
,patch-replicas.yaml
, notpatch-monitoring.yamlpatch1.yaml - Group related resources: Keep services, deployments, and configs together
- Use components for features: Extract optional features (monitoring, ingress) as components
Patch Hygiene
- Minimize patch size: Only include fields being changed
- Document complex patches: Add comments explaining why patch is needed
- Prefer strategic merge: Use JSON patch only when necessary
- Validate patches: Run
to verify outputkustomize build - Test combinations: Ensure patches compose correctly
Resource Management
- Use generators for dynamic data: ConfigMaps and Secrets should use generators
- Enable name suffixes: Add content hash to ConfigMap/Secret names for immutability
- Reference by resource: Use
for automatic name updatesnameReference - Common labels: Apply consistent labels across all resources
- Namespace management: Set namespace in kustomization, not individual resources
Version Control
- Commit generated manifests: Consider committing
output for GitOpskustomize build - Document dependencies: Note any external resources or ordering requirements
- Pin versions: Reference bases by version/tag when using remote bases
- Review rendered output: Always check the final manifests before applying
Security
- Never commit secrets: Use sealed-secrets, external-secrets, or secret generators with gitignored files
- Use RBAC: Limit who can modify base vs overlays
- Validate resources: Use kustomize plugins or OPA for policy enforcement
- Separate sensitive overlays: Consider separate repos for prod configurations
Examples
Basic Base Kustomization
k8s/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: myapp commonLabels: app: myapp managed-by: kustomize commonAnnotations: contact: team@example.com resources: - deployment.yaml - service.yaml - serviceaccount.yaml configMapGenerator: - name: app-config literals: - LOG_LEVEL=info - MAX_CONNECTIONS=100 images: - name: myapp newName: registry.example.com/myapp newTag: latest
k8s/base/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: serviceAccountName: myapp containers: - name: app image: myapp ports: - containerPort: 8080 name: http envFrom: - configMapRef: name: app-config resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 5 periodSeconds: 5
k8s/base/service.yaml
apiVersion: v1 kind: Service metadata: name: myapp spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app: myapp
k8s/base/serviceaccount.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: myapp
Development Overlay
k8s/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: myapp-dev namePrefix: dev- nameSuffix: -v1 commonLabels: environment: dev version: v1 resources: - ../../base patches: - path: patch-replicas.yaml target: kind: Deployment name: myapp configMapGenerator: - name: app-config behavior: merge literals: - LOG_LEVEL=debug - ENABLE_DEBUG_ROUTES=true envs: - config-values.env images: - name: myapp newTag: dev-latest replicas: - name: myapp count: 1
k8s/overlays/dev/patch-replicas.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 1 template: spec: containers: - name: app resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "128Mi" cpu: "100m"
k8s/overlays/dev/config-values.env
DATABASE_URL=postgres://localhost:5432/myapp_dev REDIS_URL=redis://localhost:6379 ENABLE_PROFILING=true
Staging Overlay
k8s/overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: myapp-staging commonLabels: environment: staging resources: - ../../base patches: - path: patch-replicas.yaml - path: patch-tolerations.yaml configMapGenerator: - name: app-config behavior: merge envs: - config-values.env secretGenerator: - name: app-secrets envs: - secrets.env # gitignored file images: - name: myapp newTag: v1.2.3-rc1 replicas: - name: myapp count: 2 components: - ../../components/monitoring
k8s/overlays/staging/patch-replicas.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 2 template: spec: containers: - name: app resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"
k8s/overlays/staging/patch-tolerations.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: tolerations: - key: "workload" operator: "Equal" value: "staging" effect: "NoSchedule" nodeSelector: environment: staging
Production Overlay
k8s/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: myapp-prod commonLabels: environment: prod criticality: high commonAnnotations: oncall: sre-team@example.com runbook: https://wiki.example.com/myapp-runbook resources: - ../../base patches: - path: patch-replicas.yaml - path: patch-resources.yaml - path: patch-affinity.yaml - path: patch-pdb.yaml - path: patch-security.yaml configMapGenerator: - name: app-config behavior: merge envs: - config-values.env secretGenerator: - name: app-secrets envs: - secrets.env # Managed by external secret management images: - name: myapp newTag: v1.2.3 digest: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 replicas: - name: myapp count: 5 components: - ../../components/monitoring - ../../components/ingress resources: - poddisruptionbudget.yaml - horizontalpodautoscaler.yaml - networkpolicy.yaml
k8s/overlays/prod/patch-resources.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 5 template: spec: containers: - name: app resources: requests: memory: "512Mi" cpu: "500m" limits: memory: "1Gi" cpu: "1000m"
k8s/overlays/prod/patch-affinity.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: myapp topologyKey: kubernetes.io/hostname nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: workload-type operator: In values: - production
k8s/overlays/prod/patch-security.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault containers: - name: app securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true volumeMounts: - name: tmp mountPath: /tmp - name: cache mountPath: /app/cache volumes: - name: tmp emptyDir: {} - name: cache emptyDir: {}
k8s/overlays/prod/poddisruptionbudget.yaml
apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: myapp-pdb spec: minAvailable: 2 selector: matchLabels: app: myapp
k8s/overlays/prod/horizontalpodautoscaler.yaml
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - type: Percent value: 50 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 0 policies: - type: Percent value: 100 periodSeconds: 30 - type: Pods value: 2 periodSeconds: 30 selectPolicy: Max
k8s/overlays/prod/networkpolicy.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: myapp-netpol spec: podSelector: matchLabels: app: myapp policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: name: ingress-nginx ports: - protocol: TCP port: 8080 egress: - to: - namespaceSelector: matchLabels: name: database ports: - protocol: TCP port: 5432 - to: - namespaceSelector: matchLabels: name: kube-system podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53
JSON 6902 Patch Example
k8s/overlays/prod/kustomization.yaml (excerpt)
patchesJson6902: - target: group: apps version: v1 kind: Deployment name: myapp path: json-patch-containers.yaml
k8s/overlays/prod/json-patch-containers.yaml
# Add a sidecar container - op: add path: /spec/template/spec/containers/- value: name: log-shipper image: fluent/fluent-bit:2.0 volumeMounts: - name: logs mountPath: /var/log/app readOnly: true # Replace the image of the main container (first container) - op: replace path: /spec/template/spec/containers/0/image value: registry.example.com/myapp:v1.2.3 # Add environment variable to specific container - op: add path: /spec/template/spec/containers/0/env/- value: name: FEATURE_FLAG_X value: "enabled" # Remove a specific environment variable (by index) - op: remove path: /spec/template/spec/containers/0/env/3 # Test that a value exists before patching (conditional patch) - op: test path: /spec/replicas value: 1 - op: replace path: /spec/replicas value: 5 # Add a volume - op: add path: /spec/template/spec/volumes/- value: name: logs emptyDir: {}
ConfigMap Generator Examples
Literal values
configMapGenerator: - name: app-config literals: - LOG_LEVEL=info - MAX_RETRIES=3 - TIMEOUT=30s
ConfigMap from Files
configMapGenerator: - name: app-config files: - application.properties - config.json - tls.crt=certs/server.crt
ConfigMap from Env File
configMapGenerator: - name: app-config envs: - config.env
ConfigMap Merging in Overlay
configMapGenerator: - name: app-config behavior: merge # Options: create (default), replace, merge literals: - LOG_LEVEL=debug # Overrides base value
Disable name suffix hash
configMapGenerator: - name: app-config options: disableNameSuffixHash: true literals: - KEY=value
Secret Generator Examples
Secret from Literals
secretGenerator: - name: app-secrets literals: - username=admin - password=changeme
Secret from Files
secretGenerator: - name: tls-secrets files: - tls.crt - tls.key type: kubernetes.io/tls
Secret from Env File (Gitignored)
secretGenerator: - name: app-secrets envs: - secrets.env # File not committed to git
Component Example: Monitoring
k8s/components/monitoring/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component resources: - servicemonitor.yaml - prometheusrule.yaml patches: - path: patch-metrics.yaml target: kind: Deployment labels: - pairs: prometheus.io/scrape: "true" includeSelectors: false
k8s/components/monitoring/servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: myapp spec: selector: matchLabels: app: myapp endpoints: - port: metrics interval: 30s path: /metrics
k8s/components/monitoring/prometheusrule.yaml
apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: myapp-alerts spec: groups: - name: myapp interval: 30s rules: - alert: HighErrorRate expr: | rate(http_requests_total{status=~"5.."}[5m]) > 0.05 for: 5m labels: severity: warning annotations: summary: High error rate detected description: Error rate is {{ $value }} req/s
k8s/components/monitoring/patch-metrics.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: not-important spec: template: spec: containers: - name: app ports: - containerPort: 9090 name: metrics protocol: TCP
Component Example: Ingress
k8s/components/ingress/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component resources: - ingress.yaml patches: - path: patch-service.yaml target: kind: Service
k8s/components/ingress/ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp annotations: cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/rate-limit: "100" spec: ingressClassName: nginx tls: - hosts: - myapp.example.com secretName: myapp-tls rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp port: name: http
k8s/components/ingress/patch-service.yaml
apiVersion: v1 kind: Service metadata: name: not-important annotations: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
Transformers Example
Using built-in transformers
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization # Add prefix to all resource names namePrefix: myapp- # Add suffix to all resource names nameSuffix: -v2 # Set namespace for all resources namespace: production # Add labels to all resources commonLabels: app: myapp team: platform environment: prod # Add annotations to all resources commonAnnotations: managed-by: kustomize contact: team@example.com # Transform images images: - name: nginx newName: my-registry/nginx newTag: 1.21.0 - name: redis newName: my-registry/redis digest: sha256:a4d4e6f8c9b0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6 # Set replicas for deployments replicas: - name: myapp count: 3 - name: worker count: 2 # Add labels to specific resources labels: - pairs: version: v2 includeSelectors: true includeTemplates: true # Transform resource names/namespaces replacements: - source: kind: ConfigMap name: app-config fieldPath: metadata.name targets: - select: kind: Deployment fieldPaths: - spec.template.spec.volumes.[name=config].configMap.name
Advanced: Using Replacements for Dynamic References
Replacements Base Configuration
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - service.yaml - configmap.yaml replacements: # Replace service name in ingress based on actual service name - source: kind: Service name: myapp fieldPath: metadata.name targets: - select: kind: Ingress fieldPaths: - spec.rules.[host=myapp.example.com].http.paths.[path=/].backend.service.name # Propagate ConfigMap name to Deployment (handles hash suffix) - source: kind: ConfigMap name: app-config fieldPath: metadata.name targets: - select: kind: Deployment fieldPaths: - spec.template.spec.volumes.[name=config].configMap.name
Using Remote Bases
Remote Base Reference
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: # GitHub repo - https://github.com/org/repo/k8s/base?ref=v1.0.0 # Specific path in repo - github.com/org/repo/manifests?ref=main patches: - path: local-patch.yaml
Multi-Environment with Shared Component
Shared Component Base Configuration
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - service.yaml
Shared Component Dev Overlay
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: dev resources: - ../../base components: - ../../components/debug-tools replicas: - name: myapp count: 1
Shared Component Prod Overlay
apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: prod resources: - ../../base components: - ../../components/monitoring - ../../components/ingress replicas: - name: myapp count: 5
k8s/components/debug-tools/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1 kind: Component patches: - path: patch-debug.yaml configMapGenerator: - name: app-config behavior: merge literals: - DEBUG=true - ENABLE_PPROF=true
Common Tasks
Validate Kustomization
# Build and validate kustomize build k8s/overlays/prod # Use kubectl (includes additional validation) kubectl kustomize k8s/overlays/prod # Validate against cluster without applying kubectl apply -k k8s/overlays/prod --dry-run=server # Check diff before applying kubectl diff -k k8s/overlays/prod
Extract Common Configuration
When you notice duplication across overlays:
- Identify common patches or resources
- Move to base or create a component
- Reference from overlays
# Before: Same patch in dev, staging, prod # After: Move to component mkdir -p k8s/components/common-settings # Create component kustomization # Reference from each overlay
Debug Name Transformations
# See final resource names after transformations kustomize build k8s/overlays/prod | grep "^ name:" # Check ConfigMap/Secret name with hash kustomize build k8s/overlays/prod | grep -A 2 "kind: ConfigMap"
Convert Existing Manifests
# Generate kustomization.yaml from existing resources cd k8s/base kustomize create --autodetect # Or manually specify kustomize create --resources deployment.yaml,service.yaml
Update Image Tags
# Update image tag in kustomization.yaml cd k8s/overlays/prod kustomize edit set image myapp=registry.example.com/myapp:v1.3.0 # Or use kubectl kubectl set image deployment/myapp myapp=registry.example.com/myapp:v1.3.0 --dry-run=client -o yaml | kubectl apply -k .
Add Resources
cd k8s/base kustomize edit add resource new-deployment.yaml
Add ConfigMap Generator
cd k8s/overlays/dev kustomize edit add configmap app-config --from-literal=KEY=value
Integration Patterns
GitOps with ArgoCD
argocd-application.yaml
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: myapp-prod namespace: argocd spec: project: default source: repoURL: https://github.com/org/repo targetRevision: main path: k8s/overlays/prod destination: server: https://kubernetes.default.svc namespace: myapp-prod syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true
GitOps with Flux
kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: myapp-prod namespace: flux-system spec: interval: 10m path: ./k8s/overlays/prod prune: true sourceRef: kind: GitRepository name: myapp validation: client healthChecks: - apiVersion: apps/v1 kind: Deployment name: myapp namespace: myapp-prod
CI/CD Pipeline
#!/bin/bash # build-and-validate.sh set -euo pipefail OVERLAY=${1:-dev} OUTPUT_DIR="manifests/${OVERLAY}" # Build manifests kustomize build "k8s/overlays/${OVERLAY}" > "${OUTPUT_DIR}/all.yaml" # Validate with kubeval kubeval --strict "${OUTPUT_DIR}/all.yaml" # Validate with kube-score kube-score score "${OUTPUT_DIR}/all.yaml" # Policy validation with OPA/Conftest conftest test "${OUTPUT_DIR}/all.yaml" # Commit rendered manifests for GitOps git add "${OUTPUT_DIR}/all.yaml"
Helm Integration
# Use kustomize to customize Helm output apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization helmCharts: - name: postgresql repo: https://charts.bitnami.com/bitnami version: 12.1.2 releaseName: myapp-db namespace: database valuesInline: auth: username: myapp database: myapp_prod patches: - path: patch-postgresql.yaml target: kind: StatefulSet name: myapp-db-postgresql
Troubleshooting
Common Errors
Error: Accumulating Resources
accumulating resources: accumulation err='accumulating resources from '../../base': evalsymlink failure on '/path/to/base' : lstat /path/to/base: no such file or directory'
- Solution: Check that base path in overlay's kustomization.yaml is correct
- Paths are relative to the kustomization.yaml location
Error: No Matches for OriginalId
no matches for OriginalId ~G_v1_ConfigMap|~X|app-config; failed to find unique target for patch
- Solution: Ensure the resource being patched exists in base
- Check resource name and kind match exactly
Error: Conflict Between Patches
conflict: multiple matches for ...
- Solution: Make patches more specific with metadata
- Use JSON patch for precise targeting
Error: Cyclic Dependency
base 'overlays/dev' refers to base '../../base' which refers back to 'overlays/dev'
- Solution: Check for circular references in bases
- Bases should not reference overlays
Debugging Techniques
# Enable verbose output kustomize build k8s/overlays/prod --enable-alpha-plugins --load-restrictor=LoadRestrictionsNone # Show resources before and after transformation kustomize build k8s/base > base.yaml kustomize build k8s/overlays/prod > overlay.yaml diff base.yaml overlay.yaml # Validate specific resource kustomize build k8s/overlays/prod | kubectl apply --dry-run=client -f - # Check for YAML syntax errors kustomize build k8s/overlays/prod | yamllint - # Inspect ConfigMap hash generation kustomize build k8s/overlays/prod | grep -A 10 "kind: ConfigMap"
Performance Optimization
Large-Scale Kustomizations
- Use components for modularity: Break large kustomizations into components
- Avoid deep overlay chains: Keep hierarchy shallow (base -> overlay, not base -> overlay1 -> overlay2)
- Cache remote bases: Use local copies for frequently referenced remote bases
- Parallelize builds: Build multiple overlays in parallel in CI
- Limit resource scope: Don't kustomize resources that don't need customization
Build Time Optimization
# Use --load-restrictor=LoadRestrictionsNone to allow loading files outside kustomization root kustomize build --load-restrictor=LoadRestrictionsNone k8s/overlays/prod # Build multiple environments in parallel parallel kustomize build k8s/overlays/{} ::: dev staging prod
Security Considerations
-
Secret Management: Never commit secrets to git
- Use external secret operators (sealed-secrets, external-secrets-operator)
- Use secret generators with gitignored files
- Consider using SOPS for encrypted secrets in git
-
Image Security: Pin images by digest in production
images: - name: myapp digest: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -
RBAC: Separate access to base vs overlays
- Base: Restricted to platform team
- Overlays: Application teams can customize
-
Validation: Use admission controllers
- OPA Gatekeeper
- Kyverno policies
- Custom admission webhooks
-
Audit: Track kustomization changes
- Git commit history
- CI/CD logs
- Kubernetes audit logs
Summary
Kustomize provides a declarative, Kubernetes-native approach to configuration management:
- Use bases for shared, environment-agnostic configuration
- Use overlays for environment-specific customization
- Use components for optional, reusable features
- Use generators for ConfigMaps and Secrets with content hashing
- Use transformers for cross-cutting modifications
- Prefer strategic merge for simplicity, JSON patch for precision
- Keep structure shallow to avoid complexity
- Validate early with
andkustomize buildkubectl diff - Secure secrets with external tools, never commit sensitive data
- Document patterns so team members understand customization strategy
Kustomize integrates seamlessly with kubectl, GitOps tools (ArgoCD, Flux), and CI/CD pipelines, making it an excellent choice for Kubernetes configuration management.