Kustomize: альтернатива templating
Helm берёт YAML и подставляет туда переменные через Go templates. Kustomize — противоположный подход: никаких переменных, только patches на base manifests. Файлы в Kustomize-проекте — всегда valid YAML, который можно открыть в редакторе с подсветкой, прогнать через kubectl apply напрямую и понять без рендеринга. Этот урок — про философию Kustomize, его primitives и типичные паттерны.
Override-файлы: base + dev + prod конфигурации в Compose
Что такое Kustomize
Kustomize — declarative customization tool for Kubernetes. Создан Google, встроен в kubectl начиная с v1.14 (2019). Запускается через kubectl apply -k <directory> или standalone бинарь kustomize build <directory>.
Философия:
- Никакого templating — все файлы валидный YAML.
- Composition over inheritance — base manifests + overlay-патчи.
- Declarative —
kustomization.yamlдекларирует, что и как изменить, никаких императивных команд.
# kubectl-встроенный (предпочтительный для CKAD)
kubectl apply -k ./overlays/prod
# Standalone бинарь (для CI, более новые фичи)
kustomize build ./overlays/prod | kubectl apply -f -
# Render без apply (debug)
kustomize build ./overlays/prod
В kubectl встроена своя версия Kustomize, которая обычно отстаёт от standalone бинаря на 1-2 minor. Если нужны новые features (alpha-плагины, новые API) — используй standalone kustomize build. На CKAD достаточно встроенной версии.
Структура: base + overlays
Типичный layout:
myapp/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ ├── deployment-patch.yaml
│ └── config-dev.yaml
├── staging/
│ ├── kustomization.yaml
│ └── deployment-patch.yaml
└── prod/
├── kustomization.yaml
├── deployment-patch.yaml
└── hpa.yaml
base/— общая, generic версия манифестов. Подходит для любого env (с минимальной нагрузкой).overlays/<env>/— env-специфичные изменения. Ссылаются на base и применяют patches/overrides.
base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
commonLabels:
app: myapp
commonAnnotations:
owner: platform-team
overlays/prod/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- hpa.yaml
namespace: production
namePrefix: prod-
nameSuffix: -v1
commonLabels:
environment: production
replicas:
- name: myapp
count: 10
images:
- name: myapp
newName: registry.example.com/myapp
newTag: v2.5.0
patches:
- path: deployment-patch.yaml
Применение:
kubectl apply -k overlays/prod
kustomization.yaml: top-level директивы
Файл kustomization.yaml управляет тем, что Kustomize делает. Основные секции:
resources
Список файлов или директорий-ссылок:
resources:
- deployment.yaml # local file
- service.yaml
- ../base # parent directory как base
- github.com/org/repo//path?ref=v1.0.0 # remote (отлично для shared bases)
Remote resources — мощный feature, но осторожно (зависимость от внешнего источника).
labels (современный способ) / commonLabels (legacy) / commonAnnotations
Добавляются ко всем resources И к их selectors:
# Современный способ (Kustomize 5.x — рекомендованный):
labels:
- includeSelectors: true # явно: добавлять и в spec.selector.matchLabels
pairs:
app: myapp
environment: production
# Legacy (всё ещё работает, но deprecated в новых версиях):
commonLabels:
app: myapp
environment: production
commonLabels и labels с includeSelectors: true имеют одинаковый эффект — применяют labels к metadata.labels, spec.template.metadata.labels И к spec.selector.matchLabels. Это критично: иначе Service не находит Pods после patching labels. Новые проекты пишите через labels с includeSelectors — это явно и контролируемо (можно иметь несколько групп labels с разной семантикой). commonAnnotations остаётся стандартом для annotations.
namespace / namePrefix / nameSuffix
namespace: production
namePrefix: prod-
nameSuffix: -stable
Всё резолвится в final имена ресурсов: Deployment myapp становится prod-myapp-stable в namespace production.
replicas
replicas:
- name: myapp # имя resource (Deployment / StatefulSet)
count: 10
Удобный shortcut для override replicas без полного patch.
images
images:
- name: nginx # имя image в base manifest
newName: registry.example.com/my-nginx # переименовать
newTag: 1.26 # сменить tag
- name: myapp
digest: sha256:abc123 # вместо tag — digest (immutable)
Kustomize ищет всех containers с image: nginx:* и заменяет.
Patches: два типа
Patches — самая мощная часть Kustomize. Они меняют что угодно в base resources.
1. Strategic Merge Patch (default)
Это native K8s формат. Указываешь только то, что меняешь, structure совпадает с original:
# overlays/prod/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
resources:
limits:
cpu: 1000m
memory: 1Gi
В kustomization.yaml:
patches:
- path: deployment-patch.yaml
Strategic merge “умный”: для lists с merge-key (containers — merge by name) делает merge, не replace. Поэтому в patch только name: app и resources — остальные fields в container не трогаются.
2. JSON Patch (RFC 6902)
Точечные операции:
# overlays/prod/replica-patch.yaml
- op: replace
path: /spec/replicas
value: 10
- op: add
path: /spec/template/spec/tolerations
value:
- key: dedicated
operator: Equal
value: prod
В kustomization.yaml:
patches:
- target:
kind: Deployment
name: myapp
path: replica-patch.yaml
Операции: add, remove, replace, move, copy, test. JSON Patch более precise но менее читаем.
Inline patches
Можно избежать отдельного файла и описать patch прямо в kustomization.yaml:
patches:
- target:
kind: Deployment
name: myapp
patch: |
- op: replace
path: /spec/replicas
value: 10
Generators: ConfigMap и Secret
Уникальная фича Kustomize — генерация ConfigMap и Secret из files / literals:
# kustomization.yaml
configMapGenerator:
- name: app-config
literals:
- DB_HOST=postgres.production.svc
- LOG_LEVEL=info
- name: nginx-config
files:
- configs/nginx.conf
- configs/upstream.conf
- name: env-config
envs:
- .env
secretGenerator:
- name: db-credentials
literals:
- username=admin
- password=secret123
type: Opaque
- name: tls-cert
files:
- tls.crt
- tls.key
type: kubernetes.io/tls
Чем эти generators лучше plain ConfigMap manifest?
- Hash suffix: ConfigMap получает имя
app-config-<hash>, где hash — это SHA256 содержимого. При изменении data — hash меняется — имя меняется — Deployment, ссылающийся на этот ConfigMap, видит новое имя — делает rolling update. - Автоматический rollout на изменение config. Это то, что в Helm требует
checksum/configannotation hack.
Если не хочешь hash:
configMapGenerator:
- name: app-config
literals:
- DB_HOST=postgres
options:
disableNameSuffixHash: true
Hash suffix — killer feature Kustomize. В Helm для этого паттерн с sha256sum annotation и pod template digest — Kustomize делает это автоматически и более правильно (изменилась config — новый ресурс, immutable rollout). Это основная причина выбирать Kustomize для GitOps workflows.
Practical example: dev → prod overlay
base/
base/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: myapp
overlays/dev/
overlays/dev/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: development
namePrefix: dev-
images:
- name: myapp
newTag: latest
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=debug
overlays/prod/
overlays/prod/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- hpa.yaml
namespace: production
namePrefix: prod-
images:
- name: myapp
newTag: v2.5.0
replicas:
- name: myapp
count: 5
patches:
- path: prod-resources.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
overlays/prod/prod-resources.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
Применение:
kubectl apply -k overlays/dev # dev
kubectl apply -k overlays/prod # prod
Stateless design: что значит для управления
Главное отличие от Helm: Kustomize stateless. Никаких Release Secrets, никакой истории, никакого kustomize uninstall.
- Что было применено — определяется git-ом (последний
kubectl apply -kкоммит). - Удаление:
kubectl delete -k overlays/prod. Удалит то, что описано в текущей версии — но если что-то было раньше и убрано, оно останется orphan. - Cleanup orphan: использовать
kubectl prune(alpha) или labels-based delete (kubectl delete -l app=myapp).
Stateless design Kustomize означает, что rollback — это git revert + apply. Никаких helm rollback. Это особенность GitOps-философии: git — source of truth, кластер должен совпадать с git. Tools типа ArgoCD/Flux реализуют этот flow автоматически.
kustomize edit: CLI для модификации
Standalone бинарь kustomize имеет helper-команды:
# В директории overlays/prod
kustomize edit set image myapp=myapp:v3.0.0
kustomize edit set replicas myapp=10
kustomize edit set namespace production
kustomize edit add resource hpa.yaml
kustomize edit add patch --path deployment-patch.yaml
Они модифицируют kustomization.yaml in-place. Удобно для CI: build pipeline может обновить image tag без ручного редактирования YAML.
Killer-моменты
- Kustomize встроен в kubectl —
kubectl apply -k <dir>работает без отдельного бинаря. На CKAD это default. - Patches типа strategic merge merge-ятся по name в lists. Поэтому в patch только
name: appплюс полей-для-override — остальные fields не overwritten. commonLabelsприменяется и к selectors — критично, иначе Service ломается. Это feature, не bug.configMapGeneratorдобавляет hash suffix — изменение config приводит к immutable rollout Deployment-а. Это elegantly решает проблему “ConfigMap update без restart”.- Kustomize stateless — нет releases, нет history. Rollback = git revert + apply.
resources: - ../../base— путь относительный, не должен начинаться с/. Можно ссылаться на git repo:github.com/org/repo//path?ref=v1.0.0.