Learning Kubernetes - Episode 39 - Introduction and Explanation of Kustomize

Learning Kubernetes - Episode 39 - Introduction and Explanation of Kustomize

In this episode, we'll discuss Kustomize for customizing Kubernetes manifests without templating. We'll learn how to use overlays, patches, bases, and best practices for managing multiple environments.

Arman Dwi Pangestu
Arman Dwi PangestuApril 14, 2026
0 views
5 min read

Introduction

Note

If you want to read the previous episode, you can click the Episode 38 thumbnail below

Episode 38Episode 38

In the previous episode, we explored Helm Charts, which simplify packaging and deploying Kubernetes applications. Now we'll dive into Kustomize, which provides an alternative approach to customizing Kubernetes manifests.

Note: Here I'll be using a Kubernetes Cluster installed through K3s.

Kustomize is a native Kubernetes tool for customizing YAML manifests. Unlike Helm, Kustomize doesn't use templating. Instead, it uses a declarative approach with overlays and patches. Think of Kustomize like Git for Kubernetes manifests - it lets you compose, customize, and manage multiple versions of your configurations without template syntax.

Understanding Kustomize

Kustomize allows you to customize Kubernetes manifests by composing base configurations with overlays. It's built into kubectl, so you don't need to install anything extra.

Why Kustomize Matters

1. No Templating Language

Use plain YAML without template syntax.

2. Declarative Approach

Describe what you want, not how to get it.

3. Reusability

Share base configurations across projects.

4. Multiple Environments

Easily manage dev, staging, and production.

5. Built-in to kubectl

No additional tools needed.

6. Git-Friendly

Works well with version control.

Kustomize Structure

A typical Kustomize project has this structure:

plaintext
my-app/
├── base/
│   ├── kustomization.yaml
│   ├── deployment.yaml
│   ├── service.yaml
│   └── configmap.yaml
└── overlays/
    ├── dev/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    ├── staging/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    └── production/
        ├── kustomization.yaml
        ├── patch-replicas.yaml
        └── patch-resources.yaml

Base Configuration

The base directory contains the common Kubernetes manifests:

Kubernetesbase/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml
 
commonLabels:
  app: my-app
  version: v1
 
commonAnnotations:
  managed-by: kustomize
Kubernetesbase/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: myapp:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
Kubernetesbase/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-app
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: my-app

Overlay Configuration

Overlays customize the base configuration for specific environments:

Kubernetesoverlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
bases:
  - ../../base
 
replicas:
  - name: my-app
    count: 1
 
patchesStrategicMerge:
  - patch-replicas.yaml
 
commonLabels:
  environment: dev
Kubernetesoverlays/dev/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
Kubernetesoverlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
bases:
  - ../../base
 
replicas:
  - name: my-app
    count: 3
 
patchesStrategicMerge:
  - patch-replicas.yaml
  - patch-resources.yaml
 
commonLabels:
  environment: production
 
images:
  - name: myapp
    newTag: "2.0"
Kubernetesoverlays/production/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
Kubernetesoverlays/production/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: app
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 2000m
            memory: 2Gi

Using Kustomize

Build Kustomization

Kubernetesbash
kustomize build overlays/dev

Outputs the customized YAML.

Apply with kubectl

Kubernetesbash
kubectl apply -k overlays/dev

Applies the customized manifests to the cluster.

Dry Run

Kubernetesbash
kubectl apply -k overlays/dev --dry-run=client -o yaml

Shows what would be applied without actually deploying.

Diff

Kubernetesbash
kubectl diff -k overlays/dev

Shows differences between current and desired state.

Kustomization Features

CommonLabels and CommonAnnotations

KubernetesCommon Labels and Annotations
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
commonLabels:
  app: my-app
  version: v1
  managed-by: kustomize
 
commonAnnotations:
  description: "My application"
  team: platform

Replicas

KubernetesSet Replicas
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
replicas:
  - name: my-app
    count: 3
  - name: worker
    count: 5

Images

KubernetesUpdate Images
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
images:
  - name: myapp
    newName: myregistry.azurecr.io/myapp
    newTag: "2.0"
  - name: worker
    newTag: "1.5"

Patches

Strategic Merge Patch

KubernetesStrategic Merge Patch
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
patchesStrategicMerge:
  - patch-deployment.yaml

JSON Patch

KubernetesJSON Patch
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: my-app
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 3

NamePrefix and NameSuffix

KubernetesName Prefix and Suffix
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
namePrefix: prod-
nameSuffix: -v1
 
resources:
  - deployment.yaml

This creates resources named prod-my-app-v1.

Namespace

KubernetesSet Namespace
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
namespace: production
 
resources:
  - deployment.yaml

ConfigMap and Secret Generators

KubernetesGenerate ConfigMap
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
configMapGenerator:
  - name: app-config
    literals:
      - LOG_LEVEL=info
      - DATABASE_HOST=db.example.com
    files:
      - config.yaml
 
secretGenerator:
  - name: app-secret
    literals:
      - DATABASE_PASSWORD=secret123
    files:
      - .env

Practical Examples

Multi-Environment Setup

Kubernetesbase/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - deployment.yaml
  - service.yaml
 
commonLabels:
  app: myapp
Kubernetesoverlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
bases:
  - ../../base
 
namespace: dev
 
replicas:
  - name: myapp
    count: 1
 
images:
  - name: myapp
    newTag: "dev"
 
commonLabels:
  environment: dev
Kubernetesoverlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
bases:
  - ../../base
 
namespace: production
 
replicas:
  - name: myapp
    count: 3
 
images:
  - name: myapp
    newTag: "v1.0.0"
 
patchesStrategicMerge:
  - patch-resources.yaml
 
commonLabels:
  environment: production

Patch Example

Kubernetesoverlays/production/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
      - name: app
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 2000m
            memory: 2Gi

Common Mistakes and Pitfalls

Mistake 1: Duplicating Base Configuration

Problem: Overlays duplicate base configuration instead of patching.

KubernetesMistake: Duplication
# DON'T DO THIS - Duplicating entire deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  # ... entire spec duplicated

Solution: Use patches instead:

KubernetesCorrect: Patch
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3

Mistake 2: Not Using Bases

Problem: Each overlay is independent and duplicates configuration.

Solution: Always use bases for common configuration:

KubernetesCorrect: Use Bases
bases:
  - ../../base

Mistake 3: Incorrect Patch Syntax

Problem: Patches don't apply correctly.

KubernetesMistake: Wrong Patch
# DON'T DO THIS - Incomplete patch
spec:
  replicas: 3

Solution: Include full metadata:

KubernetesCorrect: Full Patch
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3

Mistake 4: Mixing Templating with Kustomize

Problem: Using template syntax defeats the purpose of Kustomize.

Solution: Use pure YAML with Kustomize features.

Mistake 5: Not Testing Builds

Problem: Kustomization builds fail in production.

Solution: Always test before deploying:

Kubernetesbash
kustomize build overlays/production
kubectl apply -k overlays/production --dry-run=client

Best Practices

1. Organize by Environment

plaintext
overlays/
├── dev/
├── staging/
└── production/

2. Use Descriptive Names

Kubernetesyaml
namePrefix: prod-
nameSuffix: -v1

3. Keep Bases Simple

Base should contain only common configuration.

4. Use Patches for Differences

Kubernetesyaml
patchesStrategicMerge:
  - patch-replicas.yaml
  - patch-resources.yaml

5. Document Overlays

Add comments explaining what each overlay does:

Kubernetesyaml
# Production overlay
# - 3 replicas for high availability
# - Production image tag
# - Higher resource limits

6. Version Control

Keep Kustomize files in Git:

Kubernetesbash
git add base/ overlays/
git commit -m "Update kustomization for v2.0"

7. Use ConfigMap Generators

Kubernetesyaml
configMapGenerator:
  - name: app-config
    literals:
      - LOG_LEVEL=info

Kustomize vs Helm

AspectKustomizeHelm
TemplatingNoYes
Learning CurveEasierSteeper
FlexibilityGoodExcellent
Package ManagementNoYes
Built-in to kubectlYesNo
Community ChartsNoYes
Use CaseConfiguration ManagementPackage Management

Advanced Features

Vars

KubernetesUse Variables
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
vars:
  - name: REPLICAS
    objref:
      kind: Deployment
      name: my-app
      apiVersion: apps/v1
    fieldref:
      fieldpath: spec.replicas

Resources

KubernetesInclude Resources
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - deployment.yaml
  - service.yaml
  - ../other-app/base

Bases

KubernetesMultiple Bases
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
bases:
  - ../../base
  - ../../common

Conclusion

In episode 39, we've explored Kustomize in Kubernetes in depth. We've learned how to customize Kubernetes manifests using overlays, patches, and bases without templating.

Key takeaways:

  • Kustomize customizes Kubernetes manifests declaratively
  • Base - Common configuration
  • Overlay - Environment-specific customization
  • Patches - Modify base configuration
  • CommonLabels - Add labels to all resources
  • Replicas - Set replica counts
  • Images - Update image tags
  • Namespace - Set namespace for resources
  • ConfigMapGenerator - Generate ConfigMaps
  • SecretGenerator - Generate Secrets
  • No templating - Use pure YAML
  • Built-in to kubectl - No additional tools
  • Git-friendly - Works well with version control
  • Multiple environments - Easy to manage dev, staging, production
  • Declarative approach - Describe what you want

Kustomize provides a simpler alternative to Helm for managing Kubernetes configurations across multiple environments.

Note

If you want to continue to the next episode, you can click the Episode 40 thumbnail below

Episode 40Episode 40

Related Posts