Kubernetes Overlays with Kustomize: One Base, Many Environments

· 1 min read · Kubernetes Tutorials

What is Kustomize #

Kustomize customizes Kubernetes YAML without templates. You keep a base with plain manifests and add overlays that change only what differs in each environment. It is built into kubectl, so there is nothing to install.

Use a cluster such as kind to follow along.

Layout #

app/
  base/
    deployment.yaml
    service.yaml
    kustomization.yaml
  overlays/
    dev/
      kustomization.yaml
    prod/
      kustomization.yaml
      replicas.yaml

The base #

base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx:stable
          ports:
            - containerPort: 80
base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - port: 80
base/kustomization.yaml
resources:
  - deployment.yaml
  - service.yaml

Render it to see what Kustomize produces, without applying anything:

kubectl kustomize base

Overlays #

The dev overlay puts everything in its own namespace with a name prefix and a pinned image:

overlays/dev/kustomization.yaml
resources:
  - ../../base
namespace: dev
namePrefix: dev-
images:
  - name: nginx
    newTag: "1.27"

The prod overlay changes the number of replicas with a patch file:

overlays/prod/kustomization.yaml
resources:
  - ../../base
namespace: prod
namePrefix: prod-
patches:
  - path: replicas.yaml
overlays/prod/replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 4

The patch is a partial manifest that is merged with the base by kind and name (a strategic merge patch). For small changes use an inline JSON patch:

patches:
  - target:
      kind: Deployment
      name: web
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/image
        value: nginx:1.27-alpine

Apply #

kubectl create namespace dev
kubectl apply -k overlays/dev
kubectl get deploy,svc -n dev

kubectl create namespace prod
kubectl apply -k overlays/prod
kubectl get pods -n prod

kubectl diff -k overlays/prod shows what would change before you apply. Delete with kubectl delete -k overlays/prod.

Generate ConfigMaps and Secrets #

overlays/dev/kustomization.yaml
configMapGenerator:
  - name: web-config
    literals:
      - LOG_LEVEL=debug

The generator appends a hash to the name and updates every reference, so changing the content triggers a rollout of the pods that use it. Do not commit real secrets to Git, even with secretGenerator.

Labels #

labels:
  - pairs:
      app.kubernetes.io/part-of: shop
    includeSelectors: false

Setting selectors after the first deployment is not allowed in Kubernetes, which is why includeSelectors is false here.

Kustomize or Helm #

Kustomize is simple and has no new language, but it cannot loop or compute values. Helm fits packages that other people install with options. Many teams use Helm for third-party software and Kustomize for their own applications. Argo CD deploys both directly from Git.

#Kubernetes #Kustomize #Kubectl