Kubernetes Overlays with Kustomize: One Base, Many Environments
What is Kustomize #
Kustomize customizes Kubernetes YAML without templates. You keep a base with plain manifests and add overlays that change only what differs in each environment. It is built into kubectl, so there is nothing to install.
Use a cluster such as kind to follow along.
Layout #
app/
base/
deployment.yaml
service.yaml
kustomization.yaml
overlays/
dev/
kustomization.yaml
prod/
kustomization.yaml
replicas.yaml
The base #
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:stable
ports:
- containerPort: 80apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80resources:
- deployment.yaml
- service.yamlRender it to see what Kustomize produces, without applying anything:
kubectl kustomize base
Overlays #
The dev overlay puts everything in its own namespace with a name prefix and a pinned image:
resources:
- ../../base
namespace: dev
namePrefix: dev-
images:
- name: nginx
newTag: "1.27"The prod overlay changes the number of replicas with a patch file:
resources:
- ../../base
namespace: prod
namePrefix: prod-
patches:
- path: replicas.yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 4The patch is a partial manifest that is merged with the base by kind and name (a strategic merge patch). For small changes use an inline JSON patch:
patches:
- target:
kind: Deployment
name: web
patch: |-
- op: replace
path: /spec/template/spec/containers/0/image
value: nginx:1.27-alpine
Apply #
kubectl create namespace dev
kubectl apply -k overlays/dev
kubectl get deploy,svc -n dev
kubectl create namespace prod
kubectl apply -k overlays/prod
kubectl get pods -n prod
kubectl diff -k overlays/prod shows what would change before you apply. Delete with kubectl delete -k overlays/prod.
Generate ConfigMaps and Secrets #
configMapGenerator:
- name: web-config
literals:
- LOG_LEVEL=debugThe generator appends a hash to the name and updates every reference, so changing the content triggers a rollout of the pods that use it. Do not commit real secrets to Git, even with secretGenerator.
Labels #
labels:
- pairs:
app.kubernetes.io/part-of: shop
includeSelectors: false
Setting selectors after the first deployment is not allowed in Kubernetes, which is why includeSelectors is false here.
Kustomize or Helm #
Kustomize is simple and has no new language, but it cannot loop or compute values. Helm fits packages that other people install with options. Many teams use Helm for third-party software and Kustomize for their own applications. Argo CD deploys both directly from Git.