Skip to content
docktionary

Kubernetes

Kustomize

Kustomize customizes plain YAML without templating it. You keep one valid set of manifests (the base) and describe each environment as a small overlay of changes on top. It's built into kubectl, so there's nothing extra to install to start.

Base and overlays

The base is ordinary Kubernetes YAML that you could kubectl apply on its own, plus a kustomization.yaml listing the files. Each overlay is another directory whose kustomization.yaml points at the base and says what differs.

layout
app/
├── base/
│   ├── kustomization.yaml
│   ├── deployment.yaml
│   └── service.yaml
└── overlays/
    ├── dev/
    │   └── kustomization.yaml
    └── prod/
        ├── kustomization.yaml
        └── limits-patch.yaml
base/kustomization.yaml
resources:
  - deployment.yaml
  - service.yaml
overlays/prod/kustomization.yaml
resources:
  - ../../base          # pull in the base

namespace: shop-prod    # set on every namespaced resource
namePrefix: prod-       # prod-web, prod-db, ... (references are rewritten too)

images:
  - name: myapp         # matches the image name in the base
    newTag: "2.4.1"

replicas:
  - name: web           # the Deployment's name in the base
    count: 5

Render an overlay to see exactly what it produces, or apply it directly with -k:

terminal
kubectl kustomize overlays/prod        # print the result, change nothing
kubectl apply -k overlays/prod         # build and apply in one step
kubectl diff -k overlays/prod          # what would change in the cluster

Like docker compose config for Compose’s merged files, the render step is the habit worth building: read the output before applying it.

Patches

For changes the built-in fields don’t cover, add a patch. The default style is a strategic merge patch: a partial manifest naming the same kind and name, containing only the fields to change.

overlays/prod/limits-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  template:
    spec:
      containers:
        - name: web          # lists of containers merge by name
          resources:
            limits:
              memory: 512Mi
overlays/prod/kustomization.yaml (excerpt)
patches:
  - path: limits-patch.yaml

That’s the key difference from Compose’s file merging: Kubernetes lists such as containers are merged by their name key rather than appended, so the patch above changes the existing web container instead of adding a second one.

When you need an exact edit (remove an item, change one list index, patch many resources at once), use a JSON 6902 patch with a target:

overlays/prod/kustomization.yaml (excerpt)
patches:
  - target:
      kind: Deployment
      name: web
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/imagePullPolicy
        value: Always

Generating ConfigMaps and Secrets

configMapGenerator builds a ConfigMap from literals or files and appends a content hash to its name. Change the contents and the name changes, so every Deployment that references it rolls automatically. See config & storage for why that matters. References to the generated name in the manifests are rewritten for you.

overlays/prod/kustomization.yaml (excerpt)
configMapGenerator:
  - name: app-config
    behavior: merge        # extend the base's app-config instead of replacing it
    literals:
      - LOG_LEVEL=warn

Labels, carefully

The older commonLabels field is deprecated in favor of labels. The reason is that commonLabels also rewrote selectors, and a Deployment’s spec.selector is immutable once created, so adding a label to an existing app could fail the apply. With labels you opt into selector changes explicitly:

overlays/prod/kustomization.yaml (excerpt)
labels:
  - pairs:
      env: prod
    includeSelectors: false   # label the objects, leave selectors alone

Kustomize or Helm?

They solve different problems. Helm packages an app as a parameterized, versioned chart for other people to install. Kustomize adapts YAML you already own across your own environments, and the base stays valid on its own. Kustomize is usually the simpler fit for “the same app, three environments”; Helm fits distributing software or when you need logic and conditionals. The two also combine: you can post-process a Helm chart’s rendered output with a Kustomize overlay when you can’t change the chart itself.

Coming from Compose? The overlay idea is the Kubernetes counterpart of docker-compose.override.yml; see coming from Compose for the rest of the mapping, and lint the output with the Kubernetes linter.