Skip to content
Learni
View all tutorials
Kubernetes

How to Master Kustomize for Kubernetes in 2026

Lire en français

Introduction

Kustomize, natively integrated into kubectl since v1.14, revolutionizes Kubernetes manifest management in 2026. Unlike Helm, which relies on templates, Kustomize applies declarative transformations using pure YAML files, enabling pure GitOps. Imagine a common base for an Nginx deployment, overlaid for environments (dev/prod) without duplication or magic variables.

Why adopt it? It avoids templating errors, integrates seamlessly with ArgoCD/Flux, and handles strategic patches for post-build mutations. This advanced tutorial covers everything from basic structure to Secret generators, with 8 complete YAML examples. By the end, you'll deploy a modular, scalable microservices app on EKS/GKE/AKS clusters. Ideal for senior DevOps engineers managing 100+ manifests.

Prerequisites

  • kubectl 1.28+ with built-in Kustomize (kubectl kustomize)
  • Accessible Kubernetes cluster (Minikube for testing, or production cloud)
  • Advanced knowledge: Deployments, ConfigMaps, Secrets, RBAC
  • Git for versioning overlays
  • Standalone kustomize CLI (optional, via brew install kustomize)

Install and Verify Kustomize

terminal
# Standalone installation (macOS/Linux)
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/

# Check with integrated kubectl
kubectl kustomize version

# Basic test
mkdir test-kust && cd test-kust
echo 'apiVersion: v1
kind: ConfigMap
metadata:
  name: test' > configmap.yaml
echo 'resources:
- configmap.yaml' > kustomization.yaml
kubectl kustomize .

This script installs Kustomize v5+ and verifies its kubectl integration. The test creates a simple ConfigMap via kustomization.yaml, demonstrating the build without kubectl apply. Avoid outdated versions for alpha generators like StrategicMergePatch.

Basic Kustomization Structure

A Kustomize project relies on a kustomization.yaml file that lists resources and transformations. Create a base/ folder for common, reusable manifests referenced via bases:. Think of it like Lego: the base assembles the pieces, and overlays add the colors.

Create a Simple Nginx Base

base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml

namespace: default

namePrefix: app-
nameSuffix: -v1

commonLabels:
  app.kubernetes.io/name: nginx-app
  version: v1.0

This base kustomization.yaml references an Nginx Deployment and Service, adds common labels, and applies name pre/suffixes. Run kubectl kustomize . to generate the transformed manifests. Pitfall: omitting apiVersion causes parsing errors in v1beta1+.

Base Manifests (Deployment + Service)

base/deployment.yaml et service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

These manifests form the base: Deployment with 2 Nginx replicas, ClusterIP Service. Kustomize assembles them without initial changes. Copy-paste ready; test with kubectl apply -k base/. Note: labels must match for the selector.

Implement Overlays for Environments

Overlays extend the base via bases: [../base]. Create overlays/dev/ and overlays/prod/ for dev/prod. Use patches to mutate replicas, images, etc.

Dev Overlay with Patches

overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../../base

patchesStrategicMerge:
- deployment-patch.yaml

images:
- name: nginx
  newTag: 1.25-alpine

replicas:
- name: nginx-deployment
  count: 1

namespace: dev

This overlay points to the base, patches the Deployment (replicas/image), and targets the dev namespace. patchesStrategicMerge merges mergeable fields. Build with kubectl kustomize overlays/dev. Avoid patchesJson6902 unless dealing with non-mergeables like arrays.

Strategic Patch for Deployment

overlays/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  template:
    spec:
      containers:
      - name: nginx
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1

This patch adds resources and a RollingUpdate strategy to the base Deployment. StrategicMerge merges without overwriting. Crucial for prod: maxUnavailable: 0 ensures zero-downtime. Test diffs with kustomize build --enable-helm . if needed.

ConfigMap and Secret Generators

Kustomize excels with generators to inject sensitive or env-specific values without manual base64. configMapGenerator and secretGenerator hash files for immutability.

Prod Overlay with Generators

overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
- ../../base

configMapGenerator:
- name: app-config
  files:
  - config.properties=app-config.properties
  - database.properties=db.properties

secretGenerator:
- name: db-secret
  files:
  - db-pass.txt=db-password.txt
  type: Opaque

patchesStrategicMerge:
- |-
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: nginx-deployment
  spec:
    template:
      spec:
        volumes:
        - name: config-volume
          configMap:
            name: app-config
        - name: secret-volume
          secret:
            secretName: db-secret
        containers:
        - name: nginx
          volumeMounts:
          - name: config-volume
            mountPath: /etc/config
          - name: secret-volume
            mountPath: /etc/secrets
            readOnly: true

images:
- name: nginx
  newTag: 1.25
  newName: nginx

replicas:
- name: nginx-deployment
  count: 5

namespace: prod

This overlay generates ConfigMap/Secret from files, patches the Deployment for volumes/mounts. Hash suffixes ensure rebuilds on changes. Place app-config.properties and db-password.txt in the folder. Secures secrets without kubectl create secret.

Advanced Patches and PostBuild

JSON6902 patches for precise mutations (e.g., arrays), postBuild for vars like GitOps image SHAs.

JSON6902 Patch and Vars

overlays/prod/patch-json.yaml
apiVersion: apps/v1
$patch: replace
$operation: add
path: /spec/template/spec/containers/0/env
value:
- name: ENV
  value: production
- name: DB_HOST
  valueFrom:
    secretKeyRef:
      name: db-secret
      key: host

---
# In kustomization.yaml, add:
# vars:
# - name: IMAGE_TAG
#   objref:
#     kind: Deployment
#     name: nginx-deployment
#     apiVersion: apps/v1
#   fieldref:
#     fieldpath: spec.template.spec.containers.[name=nginx].image
# patchesJson6902: [patch-json.yaml]
# postBuild:
#   substitute:
#     IMAGE_TAG: latest-sha

# Full postBuild example in kustomization.yaml:
postBuild:
  substitute:
    app-name: "nginx-prod"
    sha: "abc123"

JSON6902 adds env vars to the first container. vars and postBuild.substitute enable dynamic injection (e.g., CI/CD SHA). Add to prod kustomization.yaml. Powerful for ArgoCD sync waves.

Full Deployment via kubectl

terminal-deploy
# Directory structure:
# kustomize-app/
# ├── base/
# │   ├── kustomization.yaml
# │   ├── deployment.yaml
# │   └── service.yaml
# └── overlays/
#     ├── dev/
#     │   ├── kustomization.yaml
#     │   └── deployment-patch.yaml
#     └── prod/
#         ├── kustomization.yaml
#         ├── deployment-patch.yaml
#         ├── patch-json.yaml
#         ├── app-config.properties
#         └── db-password.txt

# Build and dry-run
kubectl kustomize overlays/prod | kubectl apply --dry-run=client -f -

# Real deployment
kubectl apply -k overlays/prod

# Verify
kubectl get all -n prod
kubectl rollout status deployment/nginx-deployment -n prod

This script assumes the full directory structure, performs build/dry-run then apply. -k uses built-in Kustomize. rollout status waits for readiness. Perfect for CI pipelines like GitHub Actions/Jenkins.

Best Practices

  • Directory structure: base/ + overlays/{env}/{team}/ for multi-team scalability.
  • Hashed generators: Always use secretGenerator with type: Opaque and literals/files.
  • Patch priority: StrategicMerge > JSON6902; test diffs with k diff.
  • GitOps ready: Commit overlays, ignore sensitive files via .gitignore + SealedSecrets.
  • Helm fallback: Enable enableHelm: true for hybrid, but prioritize pure Kustomize.

Common Errors to Avoid

  • Missing apiVersion v1beta1: Causes no kind "Kustomization"; always specify.
  • Merge conflicts: Non-mergeable arrays break; use JSON6902 with $patch: replace.
  • Plaintext secrets: Never commit; use literal: or SOPS + sopsGenerator plugin.
  • Missing namespace: Apply without -n fails; force via namespace: in kustomization.

Next Steps