Kustomize: bases, overlays and patches

Template-free customization built into kubectl: a base of plain manifests, overlays that set namespaces, names, labels, images and replicas, patches, and generated ConfigMaps with content hashes.

Architecture · 25%35 min2 tasks

After this lesson

  • 01You can write an overlay that changes namespace, name prefix, labels, image tag and replica count without touching the base.
  • 02You can patch a resource with a strategic merge patch or a JSON 6902 patch and pick the right one.
  • 03You can generate ConfigMaps and Secrets, explain the hash suffix, and render, diff, apply and delete with -k.

Kustomize is the other half of Use Helm and Kustomize to install cluster components, and it is already in your terminal: kubectl kustomize <dir> renders and kubectl apply -k <dir> applies. There are no templates. Plain manifests live in a base, and each environment gets an overlay, a directory whose kustomization.yaml lists the base and the changes to make. Exam tasks usually hand you a base and ask for an overlay, or hand you an overlay that does not build.

What a kustomization.yaml can do

FieldEffectWatch out for
resourcesFiles, directories (each with its own kustomization.yaml) or remote URLs to includeOutput is sorted by kind, Namespaces and CRDs first, so one apply -k can create a namespace and fill it
namespaceSets metadata.namespace on every namespaced objectIt does not create the Namespace. Add a Namespace manifest to resources for that
namePrefix, nameSuffixRenames objects and rewrites name references (configMapRef, volumes, serviceAccountName, roleRef)Namespace objects keep their names. Label selectors are not names and are not changed
labelsAdds labels to metadata; includeTemplates: true also labels pod templates, includeSelectors: true also changes selectorsReplaces commonLabels, which always rewrote selectors. Selectors of an existing Deployment are immutable
commonAnnotationsAdds annotations to every object
imagesChanges newName, newTag or digest of matching container imagesMatches on the image name without its tag; quote numeric tags ("1.27")
replicasSets spec.replicas by object nameUse the base name, not the prefixed one
patchesStrategic merge or JSON 6902 patches, inline or from a file, optionally selected by targetReplaces the deprecated patchesStrategicMerge and patchesJson6902
configMapGenerator, secretGeneratorBuilds ConfigMaps and Secrets from literals, files or env files, with a content hash in the nameReferences are rewritten to the hashed name; a hard-coded name elsewhere is not

Bases and overlays

app/overlays/prod/kustomization.yamlyaml
# Layout:
#   app/base/kustomization.yaml            resources: [deployment.yaml, service.yaml]
#   app/overlays/dev/kustomization.yaml    resources: [../../base]
#   app/overlays/prod/kustomization.yaml   this file
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
  - namespace.yaml            # apiVersion: v1, kind: Namespace, metadata.name: shop-prod
namespace: shop-prod
namePrefix: prod-
labels:
  - pairs:
      env: prod
    includeTemplates: true     # label the Pods too, leave selectors alone
images:
  - name: nginx                # every container whose image is nginx:<anything>
    newTag: "1.27"
replicas:
  - name: api                  # the base name, before the prefix
    count: 3
Render, compare, apply, removebash
kubectl kustomize app/overlays/prod                      # print the result, change nothing
kubectl kustomize app/overlays/prod | grep -nE 'name:|namespace:|image:|replicas:'
kubectl diff -k app/overlays/prod                         # what would change on the live cluster
kubectl apply -k app/overlays/prod
kubectl get -k app/overlays/prod                          # the live objects this overlay produces
kubectl delete -k app/overlays/prod
kubectl version --client                                  # also prints the bundled Kustomize version

Patches: strategic merge and JSON 6902

A strategic merge patch is a partial copy of the object holding only the fields to change. Lists that Kubernetes knows how to merge, such as containers (keyed by name), are merged instead of replaced, so you can change one container without repeating the others. A JSON 6902 patch is a list of explicit operations (add, replace, remove, move, copy, test) on paths such as /spec/template/spec/containers/0/image; use it to remove a field, address a list item by index, or patch many objects through a target selector. Both forms go under patches, inline or from a file.

Both patch styles, and generators, in one overlayyaml
patches:
  # Strategic merge: name the object, write only what changes
  - patch: |-
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: api
      spec:
        template:
          spec:
            containers:
              - name: api                 # merged by container name
                resources:
                  limits:
                    memory: 256Mi
  # JSON 6902: operations need a target
  - target:
      kind: Service
      name: api
    patch: |-
      - op: replace
        path: /spec/type
        value: NodePort
      - op: add
        path: /metadata/labels/exposed
        value: "true"
  # Either kind can live in a file next to kustomization.yaml
  - path: probe-patch.yaml

configMapGenerator:
  - name: api-config
    literals:
      - MODE=production
      - CACHE_TTL=300
    files:
      - nginx.conf                  # key "nginx.conf", value the file's content
  - name: api-env
    envs:
      - api.env                     # each KEY=value line becomes a key
secretGenerator:
  - name: api-credentials
    literals:
      - password=change-me
generatorOptions:
  disableNameSuffixHash: false      # true keeps plain names and loses automatic rollouts

A generated ConfigMap is named api-config-<hash>, where the hash is computed from its content. Kustomize rewrites every reference it recognizes (envFrom, valueFrom, volumes) to that name. Change one literal and the name changes, the pod template changes with it, and the Deployment rolls; that is the point of the hash. The previous ConfigMap stays behind until you delete it.

In the docs · the tab you get on exam day

Taskar-kust-1
Architecture6%~7 min

context · kubectl config use-context kind-cka

Build a production overlay

A Kustomize base for an app called web is in /tmp/cka/kustomize/base. Without modifying the base, create an overlay in /tmp/cka/kustomize/overlays/prod that puts every resource in namespace arx-kust-prod (the overlay must create this namespace), prefixes all names with prod-, runs 3 replicas, changes the nginx image tag to 1.27, and adds the label env=prod to every resource. Apply the overlay with kubectl apply -k.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-1/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-1/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-1/cleanup | bash
Taskar-kust-2
Architecture6%~8 min

context · kubectl config use-context kind-cka

Generated config and patches in a staging overlay

Using the base in /tmp/cka/kustomize/base unchanged, create an overlay in /tmp/cka/kustomize/overlays/staging that deploys into the existing namespace arx-kust-staging and: generates a ConfigMap named web-config with the keys MODE=staging and LOG_LEVEL=debug; loads every key of that ConfigMap as environment variables into the web container; and changes the Service web to type NodePort. Keep the generated name hash. Apply the overlay with kubectl apply -k.
  1. 01

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-2/setup | bash
  2. 02

    Solve it in your terminal

    Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under /tmp/cka/.

  3. 03

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-2/verify | bash
    Counts toward your readiness score.
  4. 04

    Clean up

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-kust-2/cleanup | bash

Finished reading?

0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.