Skip to content

Kustomize Reference: Overlays, Patches, ConfigMapGenerator & ArgoCD GitOps

Kustomize is built into kubectl (since 1.14) and lets you manage Kubernetes manifests across environments without templating — using patches, overlays, and generators.

1. Kustomize vs Helm

When to use Kustomize, when to use Helm
Kustomize Helm
Approach Overlays and patches (no templating) Go templates + values files
Learning curve Low — it’s just YAML Medium — template syntax, hooks
Multiple environments Overlays (base + prod/staging) Values files per environment
Third-party apps Patch existing manifests Install charts from registries
Secrets SecretGenerator (SOPS integration) Helm secrets plugin
GitOps (ArgoCD/Flux) Native support, no extra step Native support
Best for Your own apps, internal tools Third-party software (databases, monitoring)
# Rule of thumb:
# Kustomize = your own apps across environments (base + overlays)
# Helm = installing third-party software from a chart registry
# They're complementary — many teams use both

2. Directory Structure

Base + overlay pattern — the standard layout
k8s/
├── base/
│   ├── kustomization.yaml         # base resources
│   ├── deployment.yaml
│   ├── service.yaml
│   └── configmap.yaml
└── overlays/
    ├── staging/
    │   ├── kustomization.yaml     # extends base
    │   └── patch-replicas.yaml    # staging-specific patches
    └── production/
        ├── kustomization.yaml
        ├── patch-replicas.yaml
        └── patch-resources.yaml

# base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml

# overlays/production/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base      # extend the base
namePrefix: prod-   # prefix all resource names
namespace: production
commonLabels:
  environment: production
patches:
  - path: patch-replicas.yaml
  - path: patch-resources.yaml

# Build and apply:
kubectl kustomize overlays/production | kubectl apply -f -
# Or (equivalent, but deploys directly):
kubectl apply -k overlays/production

3. Patches

Strategic merge patch, JSON patch, and inline patches
# Strategic Merge Patch (most readable):
# patch-replicas.yaml — only changes replicas, everything else from base is preserved
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app          # must match the base Deployment name
spec:
  replicas: 5           # override to 5 in production

# JSON 6902 Patch (surgical changes by path):
# kustomization.yaml:
patches:
  - target:
      kind: Deployment
      name: my-app
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: ENVIRONMENT
          value: production
      - op: remove
        path: /spec/template/spec/containers/0/resources/limits/cpu

# Inline patch (no separate file):
patches:
  - target:
      kind: Deployment
      name: my-app
    patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: my-app
      spec:
        template:
          spec:
            containers:
              - name: my-app
                image: my-app:production-tag
                resources:
                  limits:
                    memory: "1Gi"
                  requests:
                    memory: "512Mi"

4. Images — No Templating Needed

Override image tags per environment without string substitution
# In overlays/production/kustomization.yaml:
images:
  - name: my-app                          # image name in base manifest
    newTag: "1.4.0"                       # pin to specific tag
  - name: nginx
    newTag: "1.25.4-alpine"
  - name: my-app
    newName: gcr.io/my-project/my-app     # change registry too
    newTag: "${IMAGE_TAG}"                # CI/CD can set this with kustomize edit

# In CI/CD (set tag without editing files manually):
kustomize edit set image my-app=my-app:${GIT_SHA}

# Full CI/CD pattern:
# 1. Build + push image with SHA tag
# 2. kustomize edit set image my-app=registry.io/my-app:${GIT_SHA}
# 3. git commit + push (triggers ArgoCD/Flux sync)
kustomize edit set image my-app=registry.io/my-app:${GIT_SHA}
git add k8s/overlays/production/kustomization.yaml
git commit -m "ci: deploy ${GIT_SHA}"

5. ConfigMapGenerator & SecretGenerator

Auto-roll deployments when config changes
# ConfigMapGenerator — creates ConfigMap from files or literals
# AND appends a content hash to the name (e.g., my-config-5c8hb97g)
# This forces a rolling Deployment restart when config changes!

# kustomization.yaml:
configMapGenerator:
  - name: my-app-config
    files:
      - config.properties         # file in same directory
    literals:
      - LOG_LEVEL=info
      - MAX_POOL_SIZE=10

# Deployment auto-references by base name, Kustomize resolves the hash:
spec:
  containers:
    - envFrom:
        - configMapRef:
            name: my-app-config   # Kustomize replaces with my-app-config-XXXX

# SecretGenerator (base64 encoding handled automatically):
secretGenerator:
  - name: my-app-secrets
    literals:
      - DB_PASSWORD=mysecret
    type: Opaque
  - name: tls-cert
    files:
      - tls.crt
      - tls.key
    type: kubernetes.io/tls

# For production: use SOPS encryption
# Store encrypted secrets in git, kustomize-controller decrypts on-cluster
# Or use External Secrets Operator to fetch from Vault/AWS SM
The hash suffix is the key feature: when config content changes, Kustomize generates a new ConfigMap name, which updates the Deployment spec, which triggers a rolling restart. No more kubectl rollout restart after config changes.

6. Components & ArgoCD Integration

Reusable components and GitOps patterns
# Kustomize Components (Kustomize 4.1+) — reusable feature modules
# components/monitoring/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
resources:
  - servicemonitor.yaml
patches:
  - path: add-prometheus-annotations.yaml

# Include optional components in overlay:
# overlays/production/kustomization.yaml:
components:
  - ../../components/monitoring    # opt-in monitoring for production
  - ../../components/network-policy

# ArgoCD Application pointing to Kustomize overlay:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-production
spec:
  source:
    repoURL: https://github.com/myorg/my-app
    path: k8s/overlays/production   # Kustomize overlay path
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated: {prune: true, selfHeal: true}
# ArgoCD auto-detects kustomization.yaml and runs kustomize build

# Build + validate locally:
kustomize build overlays/production               # render final YAML
kustomize build overlays/production | kubectl apply --dry-run=server -f -  # server-side validate
kubectl kustomize overlays/production             # built-in kubectl version

Track Kubernetes and Kustomize version compatibility.
ReleaseRun monitors releases for Kubernetes, Docker, Helm, ArgoCD, and 13+ technologies.

Related: Helm Reference | ArgoCD & GitOps Reference | Kubernetes YAML Reference

🔍 Free tool: K8s YAML Security Linter — after kustomize build, paste the output here to check 12 K8s security misconfigurations before applying.

Founded

2023 in London, UK

Contact

hello@releaserun.com