K8s — Kustomize
Kustomize is a native Kubernetes configuration management tool that enables DevOps engineers to customize raw, template-free YAML files for multiple environments (dev, staging, prod) without duplicating or forking manifests. It is built into kubectl (v1.14+) and is widely used across AWS, Azure, GCP, NixOS, and CI/CD pipelines.
Why Use Kustomize?
- Declarative overlays: Manage environment-specific changes (replicas, image tags, labels) without editing base YAML files.
- No templates: Works directly with YAML, avoiding the complexity of templating engines.
- Built-in to kubectl: No extra dependencies for most Kubernetes users.
- Cloud-native: Used in GitOps, ArgoCD, Flux, and CI/CD workflows.
Installation
kubectl (v1.14+): Kustomize is built-in:
kubectl kustomize ./path/to/overlay
Standalone (Linux/macOS/NixOS):
- Official releases
-
NixOS (declarative): Add to
/etc/nixos/configuration.nix:environment.systemPackages = with pkgs; [ kustomize ];Then run:
sudo nixos-rebuild switch
Basic Example: Image Tag Overlay
Let’s first take a look at one example of how to use Kustomize, to give a taste of how it works and why we need it.
Assuming you have the following application structure:
$ tree
./sample-app
└── base
├── kustomization.yml
├── nginx_deploy.yml
└── nginx_service.yml
1 directory, 3 files
0 directories, 2 files
We already familiar with the nginx Deployment and Service file, let’s focus on the kustomization.yml file:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: nginx
newTag: 1.21.0
resources:
- nginx_deploy.yml
- nginx_service.yml
As you can see from the above file content, we set a new tag for the nginx image, and sets which resources to apply the settings to. As Service does not have images, Kustomize will only apply to the Deployment, but since we will need Service in the later steps, so we are setting it anyway.
Now let’s run the kubectl kustomize base command:
$ kubectl kustomize base
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.21.0
imagePullPolicy: IfNotPresent
name: nginx
As you can see from the above output, Kustomize generated Service and Deployment content. If you pay attention, the contents of Service did not change, but the contents of Deployment changed.
The containers definition in nginx_deploy.yml file:
containers:
- name: nginx
image: nginx:1.20.0
imagePullPolicy: IfNotPresent
compare with the output from kustomize command output:
containers:
- name: nginx
image: nginx:1.21.0
imagePullPolicy: IfNotPresent
we see that image: nginx:1.20.0 got changed to — image: nginx:1.21.0, as was specified in the kustomization.yml file. Without updating the nginx_deploy.yml file, we can change the image tag during deployment.
Multi-Environment Overlays (Dev, Prod, etc.)
kustomize encourages defining multiple variants - e.g. dev, staging and prod, as overlays on a common base. It’s possible to create an additional overlay to compose these variants together — just declare the overlays as the bases of a new kustomization.
This is also a means to apply a common label or annotation across the variants, if for some reason the base isn’t under your control. It also allows one to define a left-most namePrefix across the variants — something that cannot be done by modifying the common base.
Let’s demo how to use kustomize in overlays. First, still in our sample-app folder, let’s define a common base directory:
pwd
/home/txu/sample-app
mkdir base
cd base
Now in the base directory, let’s create kustomization.yml with the following content:
$ vim kustomization.yaml
# kustomization.yaml contents
resources:
- pod.yml
The pod.yml file:
# pod.yaml contents
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:latest
Dev Overlay
Let’s make a dev variant overlaying base :
mkdir dev
cd dev
Create a kustomize file in dev :
$ vim kustomization.yml
# kustomization.yaml contents
resources:
- ./../base
namePrefix: dev-
Production Overlay
Similar to dev overlaying, let’s create a prod variant overlaying base :
mkdir prod
cd prod
Create a kustomize file in prod :
$ vim kustomization.yml
# kustomization.yaml contents
resources:
- ./../base
namePrefix: prod-
Now at project root level, define a kustomize file:
# kustomization.yaml contents
resources:
- ./dev
- ./prod
namePrefix: cluster-a-
The entire app structure looks like:
$ tree
.
├── base
│ ├── kustomization.yml
│ └── pod.yml
├── dev
│ └── kustomization.yml
├── kustomization.yml
└── prod
└── kustomization.yml
3 directories, 5 files
Now let’s build the final output:
$ kubectl kustomize
apiVersion: v1
kind: Pod
metadata:
labels:
app: myapp
name: cluster-a-dev-myapp-pod
spec:
containers:
- image: nginx:latest
name: nginx
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: myapp
name: cluster-a-prod-myapp-pod
spec:
containers:
- image: nginx:latest
name: nginx
Real-World DevOps Example: Multi-Cloud GitOps
Suppose you manage clusters in AWS EKS, Azure AKS, and GCP GKE. Use Kustomize overlays for each environment:
├── base
│ ├── deployment.yaml
│ └── kustomization.yaml
├── overlays
│ ├── aws
│ │ └── kustomization.yaml
│ ├── azure
│ │ └── kustomization.yaml
│ └── gcp
│ └── kustomization.yaml
Each overlay can patch image tags, resource limits, or add cloud-specific labels. Deploy with:
kubectl apply -k overlays/aws
kubectl apply -k overlays/azure
kubectl apply -k overlays/gcp
Kustomize vs Helm
- Kustomize: Overlay engine, no templates, built into kubectl, great for environment overlays and GitOps.
- Helm: Templating engine, supports variables and charts, better for complex parameterization and packaging.
Best Practice: Use Kustomize for overlays and environment-specific changes; use Helm for reusable application packaging.
Best Practices
- Store base and overlays in version control (Git)
- Use overlays for environment-specific changes (replicas, image tags, secrets)
- Integrate Kustomize with CI/CD (GitHub Actions, ArgoCD, Flux)
- Validate output with
kubectl kustomizebefore applying - Avoid duplicating YAML—use patches and generators
References
Tip: Use Kustomize overlays for safe, repeatable multi-environment deployments in cloud-native and GitOps workflows.