Skip to main content
RunBook Academy

KubernetesCV · KustomizeKustomize

Base + overlay — the canonical Kustomize pattern

Advanced⏱ ~16 minkubectlkustomize

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

Not yet marked complete on this device.

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

  1. Q1. In a base-and-overlay layout, where does the environment-specific replica count belong?

  2. Q2. Kustomize overlays can add resources that do not exist in the base.

  3. 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`.

  4. 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 kustomize to 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.