Anurag's Notes

Kustomize Basics (2025 Updates)

← 13 Helm Basics (2025 Updates) · Index · 15 Other Topics →

Contents


14.1 Kustomize Problem Statement and Ideology

Source: KodeKloud notes

The problem: same app, several environments

  • Same manifests deployed to dev (local), stg (staging), prod; only a few values differ per environment.
EnvironmentReplicas
dev1
stg2
prod5
  • Naive approach: copy every manifest into dev/, stg/, prod/ (each holding nginx-depl.yml + service.yml) and edit only the env-specific values, then kubectl apply -f <env>/.
  • Breaks down as resources grow (Services, ConfigMaps, Secrets, more Deployments): every new or changed file must be copied/synced into every env folder → missed copies → drift and inconsistent environments.
kubectl apply -f dev/     # deployment.apps/nginx-deployment created
kubectl apply -f stg/     # same Deployment, separately maintained copy

Kustomize model: base + overlays

TermMeaning
BaseCanonical YAML common to all environments (the defaults)
OverlayPer-environment directory holding only the differences (patches, extra env-specific resources) applied on top of the base
  • Kustomize loads the base → applies overlay patches/transformations → emits final manifests for that env. Full manifests are never duplicated.
  • Everything stays plain YAML, no templating, so linters, validators and CI/CD tooling work on it as is.

Kustomize base vs overlays flow Diagram (new): base manifests are referenced by each overlay; building an overlay yields that environment's manifests.

# base/nginx-depl.yaml  (base: replicas 1, so dev needs no override)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: nginx
  template:
    metadata:
      labels:
        component: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
# overlays/stg/replicas-patch.yaml  (prod: identical but replicas: 5)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment      # must match the base resource name (+ kind) to target it
spec:
  replicas: 2
# overlays/stg/kustomization.yaml  (each overlay needs one)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base                 # pull in the base directory (it has its own kustomization.yaml)
patchesStrategicMerge:
  - replicas-patch.yaml

[!CAUTION] Correction: patchesStrategicMerge is deprecated since Kustomize v5 (bundled in kubectl ≥ 1.27). It still works but prints a warning. Current form:

patches:
  - path: replicas-patch.yaml

Patch types are covered in §14.12–§14.15.

Typical repo layout

k8s/
├─ base/
│  ├─ kustomization.yaml
│  ├─ nginx-depl.yaml
│  ├─ service.yaml
│  └─ redis-depl.yaml
└─ overlays/
   ├─ dev/   { kustomization.yaml, config-map.yaml }
   ├─ stg/   { kustomization.yaml, config-map.yaml }
   └─ prod/  { kustomization.yaml, config-map.yaml }
  • Workflow: shared manifests in base/ → one folder per env under overlays/ → each overlay references base + only its patches/extra resources → build/apply per env.
kubectl apply -k overlays/stg          # build + apply one environment
kubectl kustomize overlays/stg         # render only (same as: kustomize build overlays/stg)

Why Kustomize

  • Built into kubectl (kubectl kustomize, kubectl apply -k), no extra package needed. The embedded version lags the standalone release, so install the standalone kustomize CLI if you need the newest features/flags (releases).
  • No complex, hard-to-read templating system to learn (unlike Helm).
  • Every artifact is plain YAML, so it can be validated and processed as such.

[!NOTE] Beyond the course: the CKA curriculum lists "use Helm and Kustomize to install cluster components". Don't assume the standalone kustomize binary exists in the exam terminal; kubectl kustomize <dir> and kubectl apply -k <dir> always work. kubectl version --client shows the embedded Kustomize version.

14.2 Kustomize vs Helm

Source: KodeKloud notes

Helm recap (full coverage in §13)

  • Helm is a package manager for apps (like apt/yum), not just a per-environment customiser: charts, release lifecycle (install/upgrade/rollback), repositories/registries.
  • Concepts: Chart = packaged app · Templates = manifests with Go template markers {{ ... }} · Values = config in values.yaml, overridden with -f / --set · Release = deployed instance of a chart.
  • Extra features: conditionals, loops, functions, hooks.
# templates/deployment.yaml  (Go templating; not valid YAML until rendered)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Values.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "nginx:{{ .Values.image.tag }}"
# values.yaml → renders replicas: 1, image nginx:2.4.4
name: nginx
replicaCount: 1
image:
  tag: "2.4.4"

Helm per-environment layout

k8s/
├── Chart.yaml
├── values.yaml                 # defaults
├── environments/
│   ├── values.dev.yaml         # env overrides of values.yaml
│   ├── values.stg.yaml
│   └── values.prod.yaml
└── templates/                  # templated manifests
    ├── nginx-deployment.yaml
    ├── nginx-service.yaml
    ├── db-deployment.yaml
    └── db-service.yaml
helm install my-release ./k8s -f k8s/environments/values.dev.yaml    # values files merge in order; later wins
helm upgrade my-release ./k8s -f k8s/environments/values.stg.yaml
helm template my-release ./k8s -f k8s/environments/values.dev.yaml   # render locally, install nothing

Comparison

AreaKustomizeHelm
ModelDeclarative YAML overlays/patchesGo templates rendered at install time
ReadabilityPlain YAML, easy to inspectTemplates not valid YAML until rendered; complex charts hard to read
PowerSimpler, fits straightforward overlaysConditionals, loops, functions, hooks
PackagingNot a package managerFull package manager (charts, releases, repos)
Per-env strategyOverlays + components (kustomization.yaml)values.yaml + -f merging + --set
FitsPlain-YAML / GitOps teamsAdvanced templating + release lifecycle needs
  • Pick Helm for packaging, heavy templating, release management; Kustomize for simple YAML-native overlays.
  • They combine: Helm charts for packaged apps + Kustomize overlays for env patches in GitOps pipelines.

14.3 InstallationSetup

Source: KodeKloud notes

Prerequisites

RequirementWhy
Running Kubernetes clusterTo apply what Kustomize generates
kubectl installed + configuredTo talk to the cluster and apply resources
Rights to install binarieskustomize must land on PATH
kubectl cluster-info                  # cluster reachable?
kubectl get nodes
kubectl config current-context        # confirm the target context
  • Platforms: Linux, macOS, Windows.

Install (maintainers' script, detects OS)

curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin && sudo chmod +x /usr/local/bin/kustomize   # if not already on PATH

# safer: download, inspect, then run
curl -O "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
bash install_kustomize.sh
PlatformMethod
macOSbrew install kustomize
Windowsscoop install kustomize or choco install kustomize
Any OSPrebuilt binary from GitHub releases

[!CAUTION] Correction: the install script drops the kustomize binary in the current directory (or a directory passed as an argument). It does not put it on PATH, so the mv step is normally required.

Verify

kustomize version              # course used --short: kustomize/v4.4.1 2021-11-11T23:36:27Z
kubectl version --client       # includes Kustomize Version
kustomize build .              # in a dir with a kustomization.yaml: should print YAML
  • No output? Reopen the terminal, check echo $PATH (Windows echo %PATH%), move the binary to /usr/local/bin + chmod +x, re-run.

[!CAUTION] Correction: kubectl version --short was removed in kubectl 1.28; use kubectl version --client. Its output also includes a Kustomize Version: line. In Kustomize v5, plain kustomize version prints only v5.x.y, and --short is deprecated or gone depending on the release.

14.4 The kustomizationyaml File

Source: KodeKloud notes

Role of the file

  • Pointing Kustomize at a dir does not process every YAML in it. It reads only the explicit entry point kustomization.yaml (also accepted: kustomization.yml, Kustomization).
  • Contains two things: (1) resources, the list of manifests (relative paths) to manage; (2) customizations/transformations to apply to them.
FieldPurposeExample
resourcesFiles (or dirs) to include- nginx-deployment.yaml
commonLabelsAdd labels to every resourcecompany: KodeKloud
namePrefix / nameSuffixPrefix/suffix every namenamePrefix: prod-
patchesStrategicMergeApply YAML patches- deployment-patch.yaml
imagesChange image names/tags- name: nginx / newTag: "1.21"
# k8s/kustomization.yaml
resources:                     # kubernetes resources to be managed by kustomize
  - nginx-deployment.yaml
  - nginx-service.yaml
commonLabels:                  # customization: label added to every resource
  company: KodeKloud

Build

kustomize build k8s/           # dir containing kustomization.yaml; prints final YAML to stdout
# output (Service and Deployment both got the label, incl. selectors and pod template)
apiVersion: v1
kind: Service
metadata:
  labels:
    company: KodeKloud
  name: nginx-loadbalancer-service
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 3000
  selector:
    company: KodeKloud
    component: nginx
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    company: KodeKloud
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      company: KodeKloud
      component: nginx
  template:
    metadata:
      labels:
        company: KodeKloud
        component: nginx
    spec:
      containers:
        - image: nginx
          name: nginx
  • kustomize build combines the manifests and applies the transformations. It does not apply/deploy anything. To deploy, pipe it:
kustomize build k8s/ | kubectl apply -f -     # check kubectl context/namespace first: this changes the live cluster

[!WARNING] Exam traps / remember:

  • No kustomization.yaml in the dir → build fails; extra YAML files in the dir are ignored unless listed in resources.
  • commonLabels also rewrites selectors (Service spec.selector, Deployment spec.selector.matchLabels). Adding or changing it on an already-deployed Deployment hits the immutable selector error on apply.

[!NOTE] Beyond the course: commonLabels is deprecated in Kustomize v5 in favour of labels: (- pairs: {company: KodeKloud} with includeSelectors: true for the same selector behaviour). kustomize edit fix migrates deprecated fields. images tags must be strings (newTag: "1.21") or YAML may parse them as numbers.

14.5 Kustomize Output

Source: KodeKloud notes

What kustomize build does

  • Collects everything referenced by kustomization.yaml (bases, resources, patches…) → applies transformations (patches, namePrefix, namespace, image tags, commonLabels…) → writes rendered YAML to stdout.
  • Never touches the cluster: kubectl get pods/deployments/services shows no change until you apply.

Apply / delete

ActionCommand
Build only (print)kustomize build k8s/
Build + apply (pipe)kustomize build k8s/ | kubectl apply -f -
Apply via kubectl's kustomizekubectl apply -k k8s/
Build + delete (pipe)kustomize build k8s/ | kubectl delete -f -
Delete via kubectl's kustomizekubectl delete -k k8s/
Save for inspectionkustomize build k8s/ > manifests.yaml
kustomize build k8s/ | kubectl apply -f -
# service/nginx-loadbalancer-service created
# deployment.apps/nginx-deployment created
kustomize build k8s/ | kubectl delete -f -
# service/nginx-loadbalancer-service deleted
# deployment.apps/nginx-deployment deleted
  • | sends left command's stdout to right command's stdin. -f - = read manifests from stdin.
  • kubectl apply -k k8s/ = read k8s/kustomization.yaml, run kustomize, apply; same result as the pipe.
  • Troubleshooting: ensure kustomization.yaml exists in the target dir. If -k fails on a newer field, the kubectl-bundled kustomize may be too old → use the standalone binary.

[!TIP] Exam speed: kubectl kustomize k8s/ to preview, kubectl apply -k k8s/ to apply, kubectl delete -k k8s/ to clean up. No standalone binary needed.

[!NOTE] Beyond the course: kubectl diff -k k8s/ shows what an apply would change. Output is sorted by kind (Namespaces, ConfigMaps/Secrets, Services… before Deployments) rather than resources order, which is why Services print before Deployments.

14.6 Kustomize ApiVersion and Kind

Source: KodeKloud notes

apiVersion: kustomize.config.k8s.io/v1beta1   # optional but recommended
kind: Kustomization                            # always this value for kustomization files
resources:
  - deployment.yaml
  - service.yaml
FieldPurposeValue
apiVersionKustomize API schema used to parse/validate the filekustomize.config.k8s.io/v1beta1
kindMarks the file as a kustomization, removing ambiguity for toolingKustomization
resourcesFiles or directories to include- deployment.yaml
  • Both fields are optional: kustomize/kubectl infer defaults if omitted. Set them explicitly for clarity, portability, and stable behaviour across Kustomize/kubectl versions and CI pipelines.
  • Kustomize evolves (new fields/behaviour), so apiVersion pins the intended schema. When upgrading Kustomize (or the kubectl that bundles it), check whether a new API version (e.g. v1) exists and update the files.
  • Errors like "unknown field" / "unsupported apiVersion" → check the kubectl-bundled or standalone Kustomize version, then align apiVersion or tooling versions.
kustomize build ./path/to/overlay     # render locally
kubectl apply -k ./path/to/overlay    # apply

[!NOTE] Beyond the course: kind: Kustomization is still kustomize.config.k8s.io/v1beta1; there is no v1 Kustomization yet. Components use apiVersion: kustomize.config.k8s.io/v1alpha1, kind: Component (§14.17).

14.7 Managing Directories

Source: KodeKloud notes

Without Kustomize

  • Flat k8s/ with api-depl.yaml, api-service.yaml, db-depl.yaml, db-service.yaml → kubectl apply -f k8s/ (plain kubectl, no Kustomize).
  • Split into k8s/api/ and k8s/db/ → one kubectl apply -f per dir. Gets tedious as directories grow, especially in CI/CD.
kubectl apply -f k8s/api/
kubectl apply -f k8s/db/

Option 1: single root kustomization listing files

# k8s/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:                    # paths are relative to THIS file's directory
  - api/api-depl.yaml
  - api/api-service.yaml
  - db/db-depl.yaml
  - db/db-service.yaml
kustomize build k8s/ | kubectl apply -f -     # or: kubectl apply -k k8s/
# service/api-service created
# service/db-service created
# deployment.apps/api-deployment created
# deployment.apps/db-deployment created

Option 2: nested kustomizations (scales: api, db, cache, kafka…)

  • Listing every file in the root gets unwieldy. Put a kustomization.yaml in each subdir and list directories in the root.
  • A directory in resources → Kustomize looks for a kustomization file (kustomization.yaml/.yml) inside it and pulls in whatever that file lists.
# k8s/kustomization.yaml (root)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api/
  - db/
  - cache/
  - kafka/
---
# k8s/db/kustomization.yaml (one per subdir)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - db-depl.yaml
  - db-service.yaml

Nested kustomization resolution and apply pipeline Diagram (new): the root lists directories, each subdirectory's kustomization lists its files, and one build feeds one apply.

ApproachCommandWhen
Flat directory applykubectl apply -f k8s/Small repos, one-offs
Kustomize build pipekustomize build k8s/ | kubectl apply -f -Standalone binary / custom render steps
kubectl embedded Kustomizekubectl apply -k k8s/Simple native workflow; convenient in CI
  • Best practices: keep each kustomization.yaml next to the resources it lists. Treat each directory (service, database, cache) as a logical unit. Prefer kubectl apply -k in CI unless you need features missing from the embedded version.

[!WARNING] Exam traps / remember:

  • Each directory listed in resources must contain its own kustomization file, or the build errors.
  • resources paths are relative to the kustomization file that lists them, not to your shell's cwd.
  • The YAML block above shows two files separated by --- for brevity. Each is a separate file on disk.

[!NOTE] Beyond the course: without Kustomize, kubectl apply -R -f k8s/ (--recursive) applies all subdirectories in one go.

14.8 Managing Directories Demo

Source: KodeKloud notes

Theory: §14.7. Layout used in the demo:

DirPurposeFiles
k8s/apiAPI serviceapi-deploy.yaml, api-service.yaml
k8s/cacheRedisredis-config.yaml, redis-deploy.yaml, redis-service.yaml
k8s/dbMongoDBdb-config.yaml, db-deploy.yaml, db-service.yaml

Representative manifests:

# k8s/db/db-deploy.yaml: Mongo creds read from ConfigMap db-credentials
apiVersion: apps/v1
kind: Deployment
metadata:
  name: db-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: db
  template:
    metadata:
      labels:
        component: db
    spec:
      containers:
        - name: mongo
          image: mongo
          env:
            - name: MONGO_INITDB_ROOT_USERNAME
              valueFrom:
                configMapKeyRef: { name: db-credentials, key: username }
            - name: MONGO_INITDB_ROOT_PASSWORD
              valueFrom:
                configMapKeyRef: { name: db-credentials, key: password }
---
# k8s/cache/redis-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: redis
  ports:
    - port: 6379
      targetPort: 6379
      protocol: TCP

Drill

  1. Apply manually, no Kustomize (one call per dir, or several -f in one call):
    kubectl apply -f k8s/api       # deployment.apps/api-deployment, service/api-service
    kubectl apply -f k8s/cache     # configmap/redis-credentials, deployment.apps/redis-deployment, service/redis-cluster-ip-service
    kubectl apply -f k8s/db        # configmap/db-credentials, deployment.apps/db-deployment, service/db-service
    kubectl apply -f k8s/db -f k8s/cache -f k8s/api
    Gotcha: fine for small projects; tedious and error-prone as dirs grow.
  2. Single root kustomization listing all 8 files:
    # k8s/kustomization.yaml
    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
      - api/api-deploy.yaml
      - api/api-service.yaml
      - cache/redis-config.yaml
      - cache/redis-deploy.yaml
      - cache/redis-service.yaml
      - db/db-config.yaml
      - db/db-deploy.yaml
      - db/db-service.yaml
    kustomize build k8s/                       # preview: ConfigMaps (db-credentials root/example, redis-credentials redis/password123), Services (api-service 80→3000, selector component: api), Deployments
    kustomize build k8s/ | kubectl apply -f -  # or: kubectl apply -k k8s
    Output order: configmap/db-credentials, configmap/redis-credentials, service/api-service, service/db-service, service/redis-cluster-ip-service, deployment.apps/api-deployment, deployment.apps/db-deployment, deployment.apps/redis-deployment (all created).
  3. Verify:
    kubectl get pods      # api-deployment-…, db-deployment-…, redis-deployment-… all 1/1 Running
  4. Per-directory kustomizations (recommended): one file per subdir, root lists dirs.
    # k8s/api/kustomization.yaml
    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources: [api-deploy.yaml, api-service.yaml]
    ---
    # k8s/cache/kustomization.yaml
    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources: [redis-config.yaml, redis-deploy.yaml, redis-service.yaml]
    ---
    # k8s/db/kustomization.yaml
    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources: [db-config.yaml, db-deploy.yaml, db-service.yaml]
    ---
    # k8s/kustomization.yaml (root)
    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
      - api
      - cache
      - db
    kustomize build k8s/                          # same combined output as step 2
    kubectl apply -k k8s                          # or: kustomize build k8s/ | kubectl apply -f -
    kubectl get pods
ApproachProsCons
Single root kustomizationQuick for small projects; one central listGrows large, harder to maintain
Per-directory kustomizations (recommended)Modular, per-component team ownership, supports overlays/env customizationsA few more files, much cleaner at scale

[!CAUTION] Correction: the demo names the files Kustomization.yaml (capital K). Kustomize only recognises kustomization.yaml, kustomization.yml or Kustomization (no extension). That spelling only resolves on a case-insensitive filesystem (e.g. macOS default); the source does not establish which filesystem the demo used. On Linux, including exam nodes, the build fails with "unable to find one of 'kustomization.yaml'…". Use lowercase kustomization.yaml.

[!NOTE] Beyond the course: the demo keeps the Mongo password in a ConfigMap. Credentials belong in a Secret (secretKeyRef), which Kustomize can also generate (secretGenerator).

14.9 Common Transformers

Source: KodeKloud notes

Purpose

  • Apply the same change (label, annotation, namespace, name prefix/suffix) to every resource referenced by a kustomization, set once in kustomization.yaml instead of hand-editing each file. Kustomize ships built-in common transformers and also supports custom ones. Image transformer: §14.10.
TransformerEffectExample
commonLabelsAdds label(s) to all resources (+ pod templates, selectors)commonLabels: {org: KodeKloud}
namePrefix / nameSuffixPrefix and/or suffix on every resource namenamePrefix: kodekloud- · nameSuffix: -dev
namespaceSets metadata.namespace on all resourcesnamespace: lab
commonAnnotationsAdds annotation(s) to all resourcescommonAnnotations: {branch: master}

Examples (put in the dir holding the referenced files)

# 1. commonLabels → metadata.labels + Deployment spec.template.metadata.labels (+ selectors)
resources:
  - deployment.yaml
  - service.yaml
commonLabels:
  org: KodeKloud
# 2. namespace → every resource gets metadata.namespace: lab
resources:
  - service.yaml
namespace: lab            # does NOT create the Namespace; include a Namespace manifest for that
# 3. prefix/suffix → api-service becomes kodekloud-api-service-dev
resources:
  - service.yaml
namePrefix: kodekloud-
nameSuffix: -dev
# 4. commonAnnotations → metadata.annotations.branch: master on each resource
resources:
  - service.yaml
  - deployment.yaml
commonAnnotations:
  branch: master
# all together
resources:
  - deployment.yaml
  - service.yaml
namespace: lab
namePrefix: kodekloud-
nameSuffix: -dev
commonLabels:
  org: KodeKloud
commonAnnotations:
  branch: master
kustomize build .        # or: kubectl apply -k .

Worked example (labels + suffix)

Input: Deployment api-deployment (selector component: api, container nginx) + Service db-service (selector component: db-depl, TCP 27017→27017, type: LoadBalancer). With commonLabels: {org: KodeKloud} and nameSuffix: -dev:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment-dev
  labels:
    org: KodeKloud
spec:
  replicas: 1
  selector:
    matchLabels:
      component: api
      org: KodeKloud
  template:
    metadata:
      labels:
        component: api
        org: KodeKloud
    spec:
      containers:
        - name: nginx
          image: nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    org: KodeKloud
  name: db-service-dev
spec:
  selector:
    component: db-depl
    org: KodeKloud          # added by commonLabels (see correction)
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017
  type: LoadBalancer

[!CAUTION] Correction:

  • The course's expected output leaves the Service selector unchanged. commonLabels does add the label to Service spec.selector too, as the §14.4 output shows (company: KodeKloud in the selector). Corrected above.
  • namePrefix: KodeKloud- renders fine, but Kubernetes object names must be lowercase RFC 1123 names, so kubectl apply rejects KodeKloud-api-service-dev. Use lowercase prefixes, e.g. kodekloud-.

[!WARNING] Exam traps / remember:

  • Transformers only affect resources referenced by that kustomization. Use overlays or separate kustomization directories for env-specific transforms (§14.16).
  • namespace: overrides any namespace already set in the manifests and doesn't create the Namespace object.
  • namePrefix/nameSuffix also update references Kustomize knows about (e.g. ConfigMap names in a Deployment's configMapKeyRef). A hard-coded name inside an arbitrary string won't be rewritten.
  • Field names are plural (commonLabels, commonAnnotations). The slide's "commonLabel" is a typo.

[!NOTE] Beyond the course: commonLabels is deprecated in Kustomize v5 in favour of labels: (includeSelectors: true reproduces selector injection; omit it to label metadata only, which avoids immutable-selector errors on existing Deployments).

[!NOTE] Beyond the course: known references (configMapKeyRef, Secret/Service names, etc.) are renamed only when the referenced resource is part of the same Kustomize build; external objects are left unchanged.


14.10 Image Transformers

Source: KodeKloud notes

images: transformer

  • Rewrites container image name and/or tag in rendered manifests without touching the source YAML. Use cases: per-environment overrides, CI/CD pipelines, swapping an image across many manifests from one place.
  • images[].name matches the image reference (image: nginx), not the container name: (name: web is irrelevant to matching).
  • Fields: newName (replace image name), newTag (replace tag). Either or both.
  • Multiple entries allowed in the images: list → transform several base images at once.

Base Deployment (deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: web
  template:
    metadata:
      labels:
        component: web
    spec:
      containers:
        - name: web          # container name: NOT used for image matching
          image: nginx       # <- this is what images[].name matches
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
images:
  - name: nginx          # image to match
    newName: haproxy     # optional: new image name
    newTag: "2.4"        # optional: new tag — ALWAYS quote
images: entryRendered image:
name: nginx + newName: haproxyhaproxy
name: nginx + newTag: "2.4"nginx:2.4
name: nginx + newName: haproxy + newTag: "2.4"haproxy:2.4
kustomize build .        # render transformed YAML to stdout
kubectl kustomize .      # same, using kubectl's built-in kustomize
kubectl apply -k .       # render + apply

Best practices

  • Matching is strict on the image reference: use the same base reference as the manifests (e.g. nginx, or full registry path gcr.io/myproj/nginx).
  • Always preview (kustomize build / kubectl kustomize) before kubectl apply -k ..
  • Put per-environment image overrides in overlays (§14.16) so the base stays immutable.

[!NOTE] Beyond the course (verified with kubectl v1.33 / kustomize v5.6): name: nginx also matches nginx:1.21 (existing tag is ignored and replaced by newTag), but does not match gcr.io/myproj/nginx — a registry-prefixed image needs the full path in name. A digest: field also exists (pins image@sha256:…). Imperative edit: kustomize edit set image nginx=haproxy:2.4.

[!WARNING] Exam traps / remember:

  • images[].name = image name, not container name.
  • Unquoted numeric tag (newTag: 2.4) fails: cannot unmarshal number into Go struct field … newTag of type string. Quote it.
  • Container name: is never changed by the image transformer — only image:.

14.11 Transformers Demo

Source: KodeKloud notes

Theory of each transformer: see §14.9 / §14.10. Key lesson here: placement = scope. A transformer in a kustomization affects only the resources that kustomization pulls in (its own resources + child kustomizations).

Layout

k8s/
├── kustomization.yaml        # root: resources: [api/, db/]
├── api/
│   ├── kustomization.yaml    # resources: [api-depl.yaml, api-service.yaml]
│   ├── api-depl.yaml
│   └── api-service.yaml
└── db/
    ├── kustomization.yaml    # resources: [db-config.yaml, db-depl.yaml, db-service.yaml]
    ├── db-config.yaml        # ConfigMap db-credentials
    ├── db-depl.yaml          # Deployment, container mongo
    └── db-service.yaml

Drill

#TaskWhereSnippetResult
1Label everythingrootcommonLabels: {department: engineering}all api + db resources (incl. Service selector) get department: engineering
2Label only APIapi/commonLabels: {feature: api}only api resources; db unaffected
2bLabel only DBdb/commonLabels: {feature: db}only db resources
3Namespace everythingrootnamespace: debuggingmetadata.namespace: debugging on all namespaced resources
4Global prefixrootnamePrefix: kodekloud-include trailing -
4bPer-component suffixapi/ / db/nameSuffix: -web / nameSuffix: -storageapi-deployment → kodekloud-api-deployment-web; db-deployment → kodekloud-db-deployment-storage
5Annotate everythingrootcommonAnnotations: {logging: verbose}metadata.annotations.logging: verbose on all
6mongo → postgres only in DBdb/images: [{name: mongo, newName: postgres, newTag: "4.2"}]db container image: postgres:4.2, container name: mongo unchanged

Final files:

# k8s/kustomization.yaml (root)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api/
  - db/
commonLabels:
  department: engineering
namespace: debugging
namePrefix: kodekloud-
commonAnnotations:
  logging: verbose
# k8s/api/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api-depl.yaml
  - api-service.yaml
commonLabels:
  feature: api
nameSuffix: -web
# k8s/db/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - db-config.yaml
  - db-depl.yaml
  - db-service.yaml
commonLabels:
  feature: db
nameSuffix: -storage
images:
  - name: mongo
    newName: postgres
    newTag: "4.2"      # quoted, else "cannot unmarshal number ..."
kustomize build k8s      # inspect composed output after each change

Rendered DB container (note name references follow renames):

      containers:
        - name: mongo                 # container name untouched
          image: postgres:4.2         # rewritten
          env:
            - name: MONGO_INITDB_ROOT_USERNAME
              valueFrom:
                configMapKeyRef:
                  name: kodekloud-db-credentials-storage   # ref auto-updated to prefixed+suffixed ConfigMap
                  key: username
            - name: MONGO_INITDB_ROOT_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: kodekloud-db-credentials-storage
                  key: password

Transformer scope: root vs subdirectory kustomizations Diagram (new): root-level transformers hit every resource; subdirectory transformers hit only that directory's resources.

Scope reference

TransformerRoot kustomizationSubdirectory kustomization
commonLabelsglobalonly that dir's resources
commonAnnotationsglobal (typical)—
namespaceglobal (typical)—
namePrefixglobal (recommended)—
nameSuffix—per-component distinguisher (typical)
imagesevery matching image in the compositiononly that dir's resources

Moving the images: block from db/ to root → every mongo image anywhere in the output becomes postgres:4.2.

[!WARNING] Exam traps / remember:

  • Scope is decided by which kustomization.yaml holds the transformer, not by where the file sits on disk.
  • commonLabels also injects labels into Service selector and Deployment spec.selector.matchLabels + pod template labels.
  • Prefix/suffix renames are propagated to references (configMapKeyRef, etc.) automatically.
  • Forgetting the - in namePrefix/nameSuffix concatenates names (KodeKloudapi-deployment).

[!CAUTION] Correction: the course prefix KodeKloud- renders fine but kubectl apply rejects it — object names must be lowercase RFC 1123 ([a-z0-9-.]). Use e.g. kodekloud- in practice.

[!NOTE] Beyond the course: kustomize v5 (embedded in kubectl ≥ 1.27) warns 'commonLabels' is deprecated. Please use 'labels' instead. Equivalent: labels: [{pairs: {department: engineering}, includeSelectors: true}] (includeSelectors: false = metadata only, safer for existing Deployments since selectors are immutable). commonLabels still works.

14.12 Patches Intro

Source: KodeKloud notes

Transformer vs patch

  • Transformer (§14.9): same change across many resources (label all, namespace all).
  • Patch: "surgical" change to one/few specific resources or sections (e.g. replicas of one Deployment).

Three patch parameters

Patch parameters: operation, target fields, value

ParameterContent
Operation typeadd (insert value, e.g. append container to list) · remove (delete label / list element) · replace (swap value, e.g. replicas 5 → 10)
Targetmatch by kind, version/group, name, namespace, labelSelector, annotationSelector — combinable for precision
Valuenew data; only for add/replace — remove needs only target + path
  • path = JSON Pointer into the YAML tree: /metadata/name, /spec/replicas.
  • JSON Patch also has move, copy, test (rare); add/remove/replace are the common ones.

JSON 6902 inline patch examples

Base: Deployment api-deployment, replicas: 1, container nginx.

# kustomization.yaml — rename the Deployment
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api-depl.yaml
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-              # YAML block scalar embeds the patch inline
      - op: replace
        path: /metadata/name
        value: web-deployment

→ rendered metadata.name: web-deployment, everything else unchanged.

# kustomization.yaml — change replicas 1 -> 5
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5

→ rendered spec.replicas: 5.

  • JSON 6902 patch body = YAML list of ops, each with op, path, optional value.

Two patch styles

StyleShapeUse when
JSON 6902 (RFC 6902)list of op/path/valuefine-grained ops with explicit paths; predictable element-level list ops
Strategic mergepartial K8s YAML with only fields to changereadability; conventional K8s fields
# Strategic merge patch, inline, via patches:
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: api-deployment     # identifies the object when no explicit target is given
      spec:
        replicas: 5              # only the changed field
  • Without target:, Kustomize identifies a strategic merge patch’s resource from its own metadata; with target:, resource selection follows the explicit target.

[!WARNING] Exam traps / remember:

  • Strategic merge on lists merges by merge key (containers → name); a wrong assumption can replace or duplicate list items. Use JSON 6902 for exact element-level list ops (§14.15).
  • remove has no value.
  • patch: |- content must be correctly indented under patch:.

[!NOTE] Beyond the course: a JSON 6902 patch requires a target (error: must specify a target for JSON patch); a strategic merge patch may omit target (matched by its kind/metadata.name). JSON Pointer escaping: / in a key → ~1, ~ → ~0 (e.g. /metadata/labels/app.kubernetes.io~1name). add fails if the parent map doesn't exist (e.g. /metadata/labels/x when there are no labels).

[!NOTE] Beyond the course: an explicit target: takes precedence over the strategic merge patch’s metadata.name; broad targets can apply one patch to several matching resources.

14.13 Different Types of Patches

Source: KodeKloud notes

  • 2 patch types × 2 placements: JSON 6902 / strategic merge, each inline in kustomization.yaml or in an external file.
  • Inline = fine for small tweaks; many/large patches → separate files to keep kustomization.yaml readable.
  • JSON 6902: RFC 6902 array of operations (add, remove, replace, test, move) — exact JSON paths, scriptable.
  • Strategic merge: Kubernetes-aware partial YAML merged into the object — easiest for replicas, labels, etc.

JSON 6902 (patchesJson6902, as taught)

# inline — patch body can be a JSON array
patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: api-deployment
    patch: |-
      [
        { "op": "replace", "path": "/spec/replicas", "value": 5 }
      ]
# external file
patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: api-deployment
    path: replica-patch.json
[
  { "op": "replace", "path": "/spec/replicas", "value": 5 }
]

Strategic merge (patchesStrategicMerge, as taught)

# inline — list item is the patch document itself
patchesStrategicMerge:
  - |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: api-deployment
    spec:
      replicas: 5
# external file
patchesStrategicMerge:
  - replica-strategic-patch.yaml
# replica-strategic-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 5
TypeSyntaxBest forInline / external
JSON 6902JSON Patch arrayprecise path ops (replace/add/remove), automationboth; external for many/complex
Strategic mergepartial K8s YAMLreadable merges of typical fields (replicas, labels, spec/metadata)both; external for many

Best practices: keep kustomization.yaml short (external files for long/numerous patches); validate JSON 6902 arrays as valid JSON (CI/lint).

[!NOTE] Beyond the course: patchesJson6902 and patchesStrategicMerge are deprecated in kustomize v5 (kubectl ≥ 1.27 prints 'patchesStrategicMerge' is deprecated. Please use 'patches' instead); they still work. kustomize edit fix converts them. Unified patches: equivalents (both verified):

patches:
  - path: replica-strategic-patch.yaml        # SMP file (target optional)
  - path: replica-patch.json                  # JSON 6902 file (target required)
    target:
      group: apps
      version: v1
      kind: Deployment
      name: api-deployment

14.14 Patches Dictionary

Source: KodeKloud notes

Patching a map (here: pod-template labels spec.template.metadata.labels) of base Deployment api-deployment (selector + template label component: api, container nginx).

Drill: replace / add / remove a key

TaskJSON 6902 (inline patches + target)Strategic merge (label-patch.yaml)Result labels
Replace component: api → webop: replace, path: /spec/template/metadata/labels/component, value: weblabels: {component: web}component: web
Add org: KodeKloudop: add, path: /spec/template/metadata/labels/org, value: KodeKloudlabels: {org: KodeKloud}component: api, org: KodeKloud
Remove orgop: remove, path: /spec/template/metadata/labels/org (no value)labels: {org: null}component: api

JSON 6902 form (swap op/path/value per row):

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api-depl.yaml
patches:
  - target:
      kind: Deployment
      name: api-deployment
    patch: |-
      - op: replace                                   # or add / remove
        path: /spec/template/metadata/labels/component
        value: web                                    # omit for remove

Strategic merge form — include only identifying fields + fields to change:

# kustomization.yaml
patches:
  - path: label-patch.yaml
# label-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    metadata:
      labels:
        component: web     # replace existing key
        # org: KodeKloud   # add new key (merged, existing keys kept)
        # org: null        # null = delete this key
  • SMP preserves all unspecified fields; JSON 6902 does exactly one atomic op per entry.

[!CAUTION] Correction: the course writes patches: followed by a bare filename (- label-patch.yaml). Kustomize rejects that (cannot unmarshal string into Go struct field Kustomization.patches of type types.Patch). Under patches: each item must be an object: - path: label-patch.yaml. (Bare filenames are valid only under the deprecated patchesStrategicMerge:.)

[!WARNING] Exam traps / remember:

  • Changing pod-template labels does not change spec.selector.matchLabels (still component: api after the replace). Update the selector too if the Deployment must select the new pods.
  • Beyond the course: the "replace" result as rendered (selector component: api, template component: web) is rejected by the API server (selector does not match template labels); and spec.selector of an existing Deployment is immutable, so changing it means delete + recreate. Adding a label (org) is safe.
  • SMP delete of a map key = key: null; JSON 6902 delete = op: remove.

14.15 Patches List

Source: KodeKloud notes

Same add/replace/remove ideas, applied to an ordered list (spec.template.spec.containers).

  • JSON 6902 → index-based (0-based); - at end of path = append.
  • Strategic merge → merge-key-based (containers matched by name).
OperationPatch typeHow
Replace whole itemJSON 6902op: replace, path: /spec/template/spec/containers/0, value = full container
Modify fields of an itemSMPlist item with same name, only changed fields
Append / insertJSON 6902op: add, path: …/containers/- (append) or …/containers/N (insert at N)
Add distinct itemSMPlist item with a new name → added alongside
Remove itemJSON 6902op: remove, path: …/containers/N
Remove itemSMPitem with name + $patch: delete

Base api-depl.yaml: Deployment api-deployment, container nginx/nginx (for add-SMP: web/nginx; for remove: web/nginx + database/mongo).

Drill (JSON 6902, as taught with patchesJson6902)

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - api-depl.yaml
patchesJson6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: api-deployment
    patch: |-
      # 1) Replace container at index 0 (both name and image change)
      - op: replace
        path: /spec/template/spec/containers/0
        value:
          name: haproxy
          image: haproxy

Exercises 2 and 3 are alternative patch: bodies: replace exercise 1, using each exercise’s original base. Combining them would create duplicate container names; exercise 3 uses the web + database base.

      # 2) Append a container (use /containers/0 to insert first, /containers/1 for second ...)
      - op: add
        path: /spec/template/spec/containers/-
        value:
          name: haproxy
          image: haproxy
      # 3) Remove the 2nd container (database at index 1) — no value
      - op: remove
        path: /spec/template/spec/containers/1

Drill (strategic merge, as taught with patchesStrategicMerge: [label-patch.yaml])

# label-patch.yaml — modify: container "nginx" keeps its name, image -> haproxy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: nginx        # merge key: matches existing item
          image: haproxy
# label-patch.yaml — add: base has "web"; new name => both web + haproxy present
spec:
  template:
    spec:
      containers:
        - name: haproxy
          image: haproxy
# label-patch.yaml — delete: removes container "database", leaves "web"
spec:
  template:
    spec:
      containers:
        - name: database
          $patch: delete     # SMP delete directive

(Each SMP file also needs the apiVersion/kind/metadata.name: api-deployment header shown in the first one.)

[!WARNING] Exam traps / remember:

  • Index ops are fragile: if anything reorders the list, /containers/0 hits the wrong item. Prefer SMP by name when changing fields.
  • JSON 6902 replace at an index swaps the entire item; SMP changes only listed fields.
  • SMP item with an unknown name is added, not an error — a typo in the name silently adds a broken container.
  • List delete in SMP = $patch: delete; map-key delete = key: null (§14.14).

[!NOTE] Beyond the course: with current kustomize use patches: instead of the deprecated patchesJson6902 / patchesStrategicMerge (see §14.13 note); the patch bodies are identical.

14.16 Overlays

Source: KodeKloud notes

Base + overlays

  • Base: shared manifests common to all environments (minimal, generic).
  • Overlay: one dir per environment; imports the base via relative path and adds env-specific patches and/or extra resources.
  • Reference base with resources: - ../../base. Older kustomize used a bases: field (deprecated).
  • ../../base from k8s/overlays/dev/ → up to overlays → up to k8s → into base.
k8s/
├── base/
│   ├── kustomization.yaml     # resources: nginx-depl.yaml, service.yaml, redis-depl.yaml
│   ├── nginx-depl.yaml
│   ├── service.yaml
│   └── redis-depl.yaml
└── overlays/
    ├── dev/   { kustomization.yaml, config-map.yaml, volume.yaml, replica-patch.yaml }
    ├── stg/   { kustomization.yaml, config-map.yaml }
    └── prod/  { kustomization.yaml, config-map.yaml, replica-patch.yaml, grafana-depl.yaml }
# base/kustomization.yaml
resources:
  - nginx-depl.yaml
  - service.yaml
  - redis-depl.yaml
# base/nginx-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:stable
          ports:
            - containerPort: 80

Drill: per-environment replicas + extra resource

# overlays/dev/kustomization.yaml
resources:
  - ../../base
patchesStrategicMerge:
  - replica-patch.yaml
# overlays/dev/replica-patch.yaml   (prod: same file with replicas: 3)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
# overlays/prod/kustomization.yaml — base + prod-only Grafana
resources:
  - ../../base
  - grafana-depl.yaml          # resource that exists only in prod
patchesStrategicMerge:
  - replica-patch.yaml         # replicas: 3
# overlays/prod/grafana-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
        - name: grafana
          image: grafana/grafana:latest
          ports:
            - containerPort: 3000
kustomize build overlays/dev        # render the dev overlay
kubectl kustomize overlays/dev      # same via kubectl
kubectl apply -k overlays/dev       # render + apply

Flexible structure

  • Base can be split into feature subdirs (base/db/, base/api/, each with its own kustomization.yaml), and overlays can mirror it (overlays/dev/db/{db-patch.yaml,kustomization.yaml}, overlays/dev/api/…). Each kustomization imports what it needs; keep env patches next to the overlay they modify.
ConceptPurposeExample
Baseshared manifestsbase/nginx-depl.yaml with replicas: 1
Overlayenv-specific patches / extra resourcesoverlays/prod/grafana-depl.yaml, replica patch
Patch typeshow overlays change basepatchesStrategicMerge (simple overrides: replicas, image) / patchesJson6902 (JSON Patch)

Best practices: keep base minimal; env settings in overlays; relative paths for portability; env-only components (monitoring, debug tools) as overlay resources.

[!WARNING] Exam traps / remember:

  • Build/apply the overlay dir (overlays/dev), not base — applying base skips all env changes.
  • Path is relative to the overlay's own kustomization.yaml; ../base vs ../../base mistakes → must build at directory: not a valid directory … no such file or directory.
  • Overlay-only resources must be listed in the overlay's resources: — just placing the file in the dir does nothing.

[!NOTE] Beyond the course: in current kustomize prefer patches: [- path: replica-patch.yaml] over deprecated patchesStrategicMerge; bases: is deprecated in favour of resources:. Kustomize by default refuses to load files outside the kustomization root except via another kustomization dir (--load-restrictor LoadRestrictionsRootOnly default) — so reference ../../base (a dir with a kustomization), not ../../base/nginx-depl.yaml (error: security; file … is not in or below …).

14.17 Components

Source: KodeKloud notes

Concept

  • Component = self-contained, reusable bundle (resources + generators e.g. secrets + patches) for one optional feature.
  • Use when a feature belongs in some overlays, not all → avoids copy-pasting the same config into multiple overlays. Needed in every overlay → put it in the base.
  • Example: overlays dev, premium, standalone (self-hosted); features caching (Redis) → premium + standalone; external DB (Postgres) → dev + premium.
k8s/
├─ base/        { kustomization.yaml, api-depl.yaml }
├─ components/
│  ├─ caching/  { kustomization.yaml, deployment-patch.yaml, redis-depl.yaml }
│  └─ db/       { kustomization.yaml, deployment-patch.yaml, postgres-depl.yaml }
└─ overlays/
   ├─ dev/        kustomization.yaml
   ├─ premium/    kustomization.yaml
   └─ standalone/ kustomization.yaml

Base, overlays and optional components Diagram (new): every overlay imports the base via resources:; each overlay opts into components via components:.

Component files (db component)

# components/db/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1   # Component requires v1alpha1 (see Correction)
kind: Component                                # not Kustomization
resources:
  - postgres-depl.yaml                         # feature's own resources
secretGenerator:                               # generator: DB password Secret
  - name: postgres-cred
    literals:
      - password=postgres123
patches:
  - path: deployment-patch.yaml                # patch a BASE resource
# components/db/postgres-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: postgres
  template:
    metadata:
      labels:
        component: postgres
    spec:
      containers:
        - name: postgres
          image: postgres
# components/db/deployment-patch.yaml — base api Deployment reads the generated secret
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  template:
    spec:
      containers:
        - name: api
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-cred     # kustomize rewrites to hashed name postgres-cred-<hash>
                  key: password

Using components in overlays

# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base                 # base still via resources
components:
  - ../../components/db        # opt-in features
Overlaycomponents:
dev../../components/db
premium../../components/db, ../../components/caching
standalone../../components/caching
kustomize build overlays/premium   # test each overlay that imports components

[!CAUTION] Correction: the course says a Component may use apiVersion: kustomize.config.k8s.io/v1beta1 and lists its patch as patches: - deployment-patch.yaml. Both fail on kustomize v5.6 (kubectl v1.33): apiVersion for Component should be kustomize.config.k8s.io/v1alpha1, and bare strings under patches: are rejected → use apiVersion: kustomize.config.k8s.io/v1alpha1 and - path: deployment-patch.yaml. (The course's own warning — check apiVersion/kind compatibility and test with kustomize build — applies.)

[!WARNING] Exam traps / remember:

  • Component file: kind: Component (v1alpha1). Overlay file: kind: Kustomization (v1beta1).
  • Components go under components:, not resources:; the base still goes under resources:.
  • Component patches can target resources from the base because components are applied after the overlay's resources are accumulated.

← 13 Helm Basics (2025 Updates) · Index · 15 Other Topics →


Reference

Based on the KodeKloud Certified Kubernetes Administrator (CKA) course notes.

On this page