KubernetesCV · KustomizeKustomize
Base + overlay — the canonical Kustomize pattern
What you'll learn
- Design the base + overlay directory structure
- Apply patches via overlays (strategic merge, JSON 6902)
- Reason about inheritance and overrides across overlays
- Apply the operational discipline of using base + overlay for environment configuration
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
Base + overlay is the canonical Kustomize pattern for environment-specific configuration. This lesson walks the directory structure, the kustomization.yaml, the patch types, the inheritance rules, and the discipline.
The directory structure
flowchart LR
A["app/"] --> B["base/"]
A --> C["overlays/"]
B --> B1[kustomization.yaml]
B --> B2[deployment.yaml]
B --> B3[service.yaml]
B --> B4[configmap.yaml]
C --> C1["dev/"]
C --> C2["staging/"]
C --> C3["prod/"]
C1 --> C1a[kustomization.yaml]
C2 --> C2a[kustomization.yaml]
C3 --> C3a[kustomization.yaml]
The structure:
app/base/— common manifests.app/overlays/dev/— dev-specific customisations.app/overlays/staging/— staging-specific.app/overlays/prod/— production-specific.
The base holds what is common across environments; each overlay holds what is unique.
The base kustomization.yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: myapp
managed-by: kustomize
The base declares:
resources— the manifests to include.commonLabels— labels added to all resources (and selectors).
commonLabels is applied to every resource, including
selectors. This is useful for grouping resources but
can break selectors if the labels are not in the Pod
template.
An overlay kustomization.yaml
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: prod-app
namePrefix: prod-
labels:
- includeSelectors: true
pairs:
env: prod
patches:
- path: deployment-patch.yaml
target:
kind: Deployment
name: myapp
The overlay:
resources— references the base (or any other kustomization).namespace— sets the namespace.namePrefix— prefixes all resource names.labels— adds labels with selector inclusion.patches— applies patches to specific resources.
A patch file (strategic merge)
# overlays/prod/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 5
template:
spec:
containers:
- name: myapp
image: myapp:2.0.0
resources:
requests:
cpu: 500m
memory: 512Mi
Strategic merge patches merge by field; lists are merged by element. The patch overrides fields; fields not in the patch are inherited from the base.
A JSON 6902 patch
# overlays/prod/json-patch.yaml
- op: replace
path: /spec/replicas
value: 5
- op: replace
path: /spec/template/spec/containers/0/image
value: myapp:2.0.0
JSON 6902 patches are precise: each operation specifies the path and the value. Useful for complex changes that strategic merge cannot express (e.g., adding an element to a list at a specific index).
Inheritance and overrides
flowchart LR
A["Base: replicas 3"] --> C["Overlay prod: replicas 5"]
A --> D["Overlay dev: replicas 1"]
A --> E["Overlay staging: replicas 2"]
Inheritance rules:
- Fields not in the overlay are inherited from the base.
- Fields in the overlay override the base.
- Patches apply on top of the inherited values.
A field that is replicas: 3 in the base and
replicas: 5 in the overlay’s patch becomes 5.
commonLabels and selectors
flowchart LR
A["Base: labels app myapp"] --> B["Overlay: commonLabels env prod"]
B --> C["Resource: labels app myapp, env prod"]
commonLabels adds labels to every resource. With
includeSelectors: true, the labels are also added
to selectors (which is required for Deployments to
match Pods).
The pitfall: adding labels to selectors can break
existing selectors. Always verify the result with
kubectl kustomize before applying.
Quiz
Knowledge check · 4 questions
Q1. In a base-and-overlay layout, where does the environment-specific replica count belong?
Q2. Kustomize overlays can add resources that do not exist in the base.
Q3. Fix an overlay that fails to build because it declares a resource the base already provides.
`kubectl apply -k overlays/prod` fails with `may not add resource with an already registered id: apps_v1_Deployment|~X|checkout`. The prod overlay's `resources` list contains both `../../base` and its own copy of `deployment.yaml`, added last month so somebody could change the replica count. The copy has since diverged: it names image tag `1.4.0` where the base names `1.6.2`.
Q4. What does an overlay's `resources` field contain in the base + overlay pattern, and how does the overlay change a field the base already sets?
Passing score: 75%. Answers are checked in this browser.
The operational discipline
Base + overlay in production rests on five non-negotiable elements:
- Base is deployable as-is. The base must be valid for some environment; do not put environment-specific values in the base.
- Overlays are reviewed. Every overlay change is reviewed in the PR.
- Render before apply. Use
kubectl kustomizeto verify the output. - Avoid commonLabels pitfalls. Verify selectors after adding commonLabels.
- Test in staging first. An overlay that breaks in production is a hot fix.
Base + overlay is the discipline of separating common from specific. The discipline is to keep the base clean and the overlays focused.