Skip to main content

Deploy an application with Kustomize

Inspect 1.36

Kustomize adapts plain YAML to each environment without a template language. There are no {{ }} placeholders and nothing to install: it ships inside kubectl as apply -k, and your manifests stay manifests. Use it when Helm's templating is more than you need and dev, staging, and prod really only differ in a handful of fields.

Base and overlays#

One base holds the real manifests; one overlay per environment patches what differs.

text
		app/
  base/
    deployment.yaml
    service.yaml
    kustomization.yaml
  overlays/
    staging/kustomization.yaml
    prod/kustomization.yaml
	

The base's kustomization.yaml lists its resources. Each overlay points back at the base and layers the environment on top:

overlays/prod/kustomization.yamlyaml
		resources:
  - ../../base
namePrefix: prod-
images:
  - name: your/app
    newTag: "1.4.0" # prod pins a released tag
patches:
  - path: replicas.yaml # prod runs more replicas per pool
  - path: lb-location.yaml # place the LoadBalancer in Falkenstein
  - path: storage-class.yaml # bind PVCs to local-nvme
	

Those last two patches carry the genuinely cluster-specific fields: lb-location.yaml sets load-balancer.hetzner.cloud/location: fsn1 on the Service, and storage-class.yaml points the PersistentVolumeClaims at local-nvme. Keep them in the overlay rather than the base, so staging can bind somewhere else. Apply with kubectl apply -k overlays/prod, but render it first. kubectl kustomize overlays/prod | less shows the exact YAML before it reaches the cluster, and that habit catches most mistakes.

What an overlay can change#

  • images swaps a tag per environment: prod pins a release, staging tracks latest.
  • namePrefix / nameSuffix and namespace keep each environment's objects distinct.
  • patches rewrite any field (replica count, resource requests, an env var, a LoadBalancer annotation) as a strategic-merge or JSON patch.
  • configMapGenerator / secretGenerator build config from files or literals and hash the name, so editing the content changes the name and the rollout happens on its own. That is the same trick a does by hand, done for you.

Helm or Kustomize#

Both parameterize manifests; they start from opposite ends. Use Kustomize to adapt manifests you already own, layering small per-environment differences over a shared base in plain YAML. Use to install and version packaged software, especially third-party charts. Many teams run both: Helm for off-the-shelf components, Kustomize for their own manifests, and let render either straight from Git so a merged pull request is the deploy.