k8wiz
All graphs

Kustomize graph

Kustomize: a base, two overlays, a component and generated ConfigMaps

How kustomize build assembles manifests: a base that lists resources, overlays that patch it per environment, a reusable component, a configMapGenerator with its hash suffix, image and replica transformers, and the objects that come out.

Kustomize builds manifests from other manifests, with no templates. A kustomization.yaml lists resources and the changes to make to them. An overlay points at a base and adds its own changes on top, so each environment is a short file of differences.

The nodes here are files in a repository, apart from the last three, which are what kubectl apply -k overlays/production sends to the cluster.

Interactive graph

Click a resource to see what it does, or follow the setup step by step.

You write itMade by a toolreferencescreatesselects by label

How it works

All 9 resources and what they do

Kustomization base/kustomization.yamlkustomize.config.k8s.io/v1beta1
What every environment shares: the Deployment and Service, common labels and a generated ConfigMap. It builds on its own, which is a good test of a base.
Deployment base/deployment.yamlapps/v1
A plain manifest with sensible defaults. It refers to the ConfigMap by its short name, shop-config, and Kustomize rewrites the reference when it adds the hash.
Component components/metrics/kustomization.yamlkustomize.config.k8s.io/v1alpha1
An optional feature that any overlay can switch on. Unlike a base, it patches whatever the overlay has built so far, here by adding a metrics port and scrape annotations.
Kustomization overlays/staging/kustomization.yamlkustomize.config.k8s.io/v1beta1
The smallest overlay: a namespace, a name prefix and an image tag. Everything else comes from the base unchanged.
Kustomization overlays/production/kustomization.yamlkustomize.config.k8s.io/v1beta1
Production's differences: a pinned image tag, three replicas, the metrics component, a patch file for resources and one changed key merged into the base's ConfigMap.
Patch file overlays/production/resources.yaml
A strategic merge patch: a partial Deployment with only the fields to change. Kustomize matches it to its target by kind and name, and merges containers by their name.
ConfigMap shop-config-7m2k9t4f8hv1
The merged ConfigMap, named with a hash of its content. Change a value and the name changes, which changes the Deployment's Pod template and rolls the Pods.
Deployment shopapps/v1
The base Deployment after every change: image ghcr.io/acme/shop:2.4.1, three replicas, requests, the scrape annotations, the shared label on selector and template, and envFrom pointing at the hashed ConfigMap name.
Service shopv1
From base/service.yaml, with the namespace set and the shared label added to its selector, so it still matches the Pods.

Common mistakes

  • A patch that names an object the build doesn't contain fails with no matches for Id. With namePrefix in play, patches still target the original name from the base.
  • A generator in an overlay with the same name as one in the base needs behavior: merge or replace. Without it the build fails on the duplicate.
  • Each change to a generated ConfigMap leaves the old one behind, since its name differs. Apply with --prune and a label, or let Flux or Argo CD prune.
  • images matches on the image name without the tag. A manifest that writes the registry differently, such as docker.io/library/nginx against nginx, isn't matched.
  • commonLabels adds labels to selectors, which are immutable on a Deployment. Adding it to a base that is already deployed breaks the next apply; labels with includeSelectors: false doesn't.

The manifests you write

Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
labels:
  - pairs:
      app.kubernetes.io/name: shop
    includeSelectors: true
configMapGenerator:
  - name: shop-config
    literals:
      - LOG_LEVEL=info
      - FEATURE_ORDERS=false
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop
spec:
  replicas: 1
  selector:
    matchLabels:
      app: shop
  template:
    metadata:
      labels:
        app: shop
    spec:
      containers:
        - name: shop
          image: ghcr.io/acme/shop
          envFrom:
            - configMapRef:
                name: shop-config
---
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
patches:
  - target:
      kind: Deployment
      name: shop
    patch: |-
      - op: add
        path: /spec/template/metadata/annotations
        value:
          prometheus.io/scrape: "true"
          prometheus.io/port: "9090"
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: shop-staging
namePrefix: staging-
resources:
  - ../../base
images:
  - name: ghcr.io/acme/shop
    newTag: 2.5.0-rc.1
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: shop
resources:
  - ../../base
components:
  - ../../components/metrics
images:
  - name: ghcr.io/acme/shop
    newTag: 2.4.1
replicas:
  - name: shop
    count: 3
patches:
  - path: resources.yaml
configMapGenerator:
  - name: shop-config
    behavior: merge
    literals:
      - FEATURE_ORDERS=true
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop
spec:
  template:
    spec:
      containers:
        - name: shop
          resources:
            requests:
              cpu: 250m
              memory: 256Mi

Keep going

More graphs