Sitemap

Kubernetes Kustomize Explained: Deploy NGINX Across Dev, QA & Production

5 min readOct 31, 2026

--

Press enter or click to view image in full size

Imagine you are managing a Kubernetes application across Development, QA, and Production.

In Development, you need one replica. In QA, you need two replicas. In Production, you need four replicas with a specific image version.

How would you manage these differences?

One option is to maintain separate Deployment and Service YAML files for every environment. But as your application grows, maintaining multiple copies becomes difficult. A change in one environment might be missed in another.

Kustomize solves this problem by allowing us to reuse Kubernetes YAML and customize it for different environments without duplicating the entire configuration.

Let’s understand how it works using a simple NGINX application.

1. What Is Kustomize?

Kustomize is a Kubernetes configuration management tool that customizes existing YAML manifests without requiring a template language.

It is integrated into kubectl, so we can render and apply configurations directly.

Kustomize has two important concepts:

  • Base: The common Kubernetes configuration shared across environments.
  • Overlay: The environment-specific customizations applied to that base.

Instead of maintaining three copies of the same Deployment, we define it once and customize only the differences.

Official documentation: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/

2. Before Kustomize: The Problem

Suppose we deploy NGINX using a Deployment and a Service.

Our environments have different requirements:

SettingDev, QA, Production Replicas 1, 2, 4 ImageNGINX development versionTested versionApproved versionNamespacedevqaprod

Without Kustomize, we might create separate directories:

kubernetes/
├── dev/
│ ├── deployment.yaml
│ └── service.yaml
├── qa/
│ ├── deployment.yaml
│ └── service.yaml
└── prod/
├── deployment.yaml
└── service.yaml

The problem is that the Deployment and Service definitions are repeated.

If we need to change a container setting, we must ensure that every copy is updated correctly.

This creates unnecessary maintenance and increases the risk of configuration drift.

What if we could define the common configuration once and reuse it everywhere?

That’s where Kustomize comes in.

3. Create a Normal NGINX Deployment and Service

Before using Kustomize, let’s understand the Kubernetes resources themselves.

Create a file named deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.28
ports:
- containerPort: 80

This Deployment runs one NGINX replica.

Now create service.yaml:

apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80
targetPort: 80

The Service provides a stable internal endpoint for the NGINX Pods.

We can deploy these resources directly using:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

This works perfectly well for a simple deployment.

But when we need to manage multiple environments, we need a maintainable way to reuse and customize these configurations.

Let’s introduce Kustomize.

4. Create the Kustomize Base

A base contains the common Kubernetes resources that we want to reuse.

Create this directory structure:

kustomize/
└── base/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml

Move the NGINX Deployment and Service manifests into the base directory.

Now create base/kustomization.yaml:

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

That’s our base.

We have not changed how Kubernetes Deployments or Services work. We have simply told Kustomize which resources belong together.

We can render the base using:

kubectl kustomize kustomize/base

Kustomize reads the configuration and generates the combined Kubernetes YAML.

5. Create Environment Overlays

Now comes the useful part.

We want to reuse the same NGINX Deployment and Service across Dev, QA, and Production.

Get Lokeshbabu Nalluri’s stories in your inbox

Join Medium for free to get updates from this writer.

Create this structure:

kustomize/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
├── qa/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml

Each overlay references the same base and defines the changes required for its environment.

Development overlay

Create overlays/dev/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: devreplicas:
- name: nginx
count: 1

QA overlay

Create overlays/qa/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: qareplicas:
- name: nginx
count: 2

Production overlay

Create overlays/prod/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: prodreplicas:
- name: nginx
count: 4

Look at what we have achieved.

We defined the Deployment and Service only once.

Each overlay reuses the base but sets its own namespace and replica count.

We do not need separate copies of the Deployment YAML just to change the number of replicas.

6. How Do We Deploy Each Environment?

Before deploying, render the Development configuration:

kubectl kustomize kustomize/overlays/dev

The generated Deployment will have one replica and the dev namespace.

Render QA:

kubectl kustomize kustomize/overlays/qa

The generated Deployment will have two replicas and the qa namespace.

Render Production:

kubectl kustomize kustomize/overlays/prod

The generated Deployment will have four replicas and the prod namespace.

Once the output has been reviewed, we can deploy the selected environment.

For Development:

kubectl apply -k kustomize/overlays/dev

For QA:

kubectl apply -k kustomize/overlays/qa

For Production:

kubectl apply -k kustomize/overlays/prod

The target cluster must be configured, and the namespaces must exist or be created as part of the deployment process.

We can verify the resources using:

kubectl get deployments -n dev
kubectl get pods -n dev
kubectl get services -n dev

Use the corresponding namespace to check QA or Production.

Important: The examples above are intended for learning. A production deployment also requires suitable image versions, resource requests and limits, health probes, security controls, monitoring, and an appropriate release process.

7. Why Is This Useful in Production?

Consider a typical application deployment workflow.

A developer changes the application code. The CI pipeline builds and tests a new container image.

After the image is available in the registry, the deployment configuration is updated with the intended image version.

Kustomize renders the configuration for Development. The team reviews and validates the generated manifests before deployment.

Once testing succeeds, the same application release can be promoted to QA and then Production, with only the approved environment-specific differences.

Kustomize also works well with GitOps tools such as Argo CD, which can monitor configuration stored in Git and synchronize it with the desired Kubernetes state.

This approach provides several benefits:

  • Less duplication: Common resources are defined once.
  • Consistent configuration: Environments share the same base.
  • Controlled differences: Overlays show what changes between environments.
  • Easier reviews: Teams can review configuration changes in Git.
  • Automation-ready: The same structure can be used in CI/CD workflows.

For Production, use approved image versions or immutable digests rather than relying on mutable tags such as latest. Keep secrets out of plaintext YAML committed to Git, and protect production deployments with appropriate permissions and approval controls.

Remember that Kustomize manages configuration; it does not build images, run tests, approve releases, or monitor application health by itself.

8. Final Thoughts

Kustomize helps solve a common Kubernetes challenge: managing the same application across multiple environments without maintaining duplicate copies of every manifest.

With a base and environment-specific overlays, we can reuse the NGINX Deployment and Service while customizing replica counts and namespaces for Dev, QA, and Production.

The same pattern can be extended to larger applications with multiple Deployments, Services, ConfigMaps, and other Kubernetes resources.

The next step is to automate this workflow using GitHub Actions, allowing us to validate configuration changes and deploy approved releases through different environments.

Define the common configuration once. Customize only what changes. Deploy with confidence.

--

--

Lokeshbabu Nalluri
Lokeshbabu Nalluri

Written by Lokeshbabu Nalluri

DevOps & Cloud Engineer | AWS | Kubernetes | Terraform | Exploring MLOps | Building scalable, production-ready systems and sharing real-world learnings.