Kustomize появился как ответ на боль от копирования одинаковых YAML-манифестов по окружениям. Вместо шаблонов с подстановками он предлагает наложение слоёв: есть базовый набор ресурсов и есть overlay, который меняет только отличия. В 2026 году Kustomize встроен в kubectl, поэтому отдельная установка нужна не всегда, а Helm и Kustomize спокойно сосуществуют в одном GitOps-репозитории. Разберём структуру каталогов, патчи, генераторы и проверку результата до применения в кластер.

Зачем нужен Kustomize при живом Helm

Helm хорош, когда приложение поставляется как продукт: чарт, values, версия, релиз. Kustomize хорош, когда манифесты уже есть и нужно собрать из них несколько вариантов — dev, stage, prod — без языка шаблонов. Он не хранит состояние релиза, не умеет условий и циклов и не подставляет значения в произвольные места. Зато результат полностью детерминирован, а kustomize build можно сравнить с тем, что реально лежит в кластере.

На практике их комбинируют: Helm рендерит сторонние компоненты, а Kustomize накладывает правки площадки — ресурсы, реплики, теги образов. Есть и обратный порядок, когда чарт генерируется из kustomize-сборки, но он сложнее в поддержке.

Структура: base и overlay

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml

База содержит ресурсы без привязки к среде. Overlay ссылается на неё и добавляет отличия: namespace, префикс имён, тег образа, количество реплик.

# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: shop-prod
namePrefix: prod-
labels:
  - pairs:
      env: prod
    includeSelectors: true
images:
  - name: registry.example.com/shop/api
    newTag: "1.42.0"
replicas:
  - name: api
    count: 3

Поле labels с includeSelectors заменило устаревшее commonLabels: метка попадает и в селектор, поэтому меняется вместе с шаблоном пода. Старое поле bases в Kustomize 5 удалено, вместо него везде используется resources. Если в репозитории остались bases или patchesStrategicMerge, сборка предупредит или упадёт — миграция занимает минуты, но её лучше сделать заранее.

Патчи: strategic merge и JSON 6902

Патч strategic merge выглядит как частичный манифест: вы описываете только те поля, которые меняете. Для списков Kubernetes применяет стратегию слияния по ключу, поэтому контейнер с тем же именем обновляется, а не дублируется.

# overlays/prod/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  template:
    spec:
      containers:
        - name: api
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              memory: 1Gi

Сам по себе файл ничего не меняет: его нужно подключить в kustomization.yaml overlay. Без строки patches он останется мёртвым грузом, и вы будете долго искать, почему ресурсы не применились.

# overlays/prod/kustomization.yaml
patches:
  - path: patch-resources.yaml

Имя в патче указывайте такое, как в базе: префикс из overlay добавляется на этапе трансформации имён, и с namePrefix исходное имя иногда приходится проверять отдельно.

Тот же раздел patches принимает JSON 6902: он удобен для полей, которые нужно именно заменить или удалить.

# фрагмент overlays/prod/kustomization.yaml
patches:
  - target:
      kind: Deployment
      labelSelector: app=api
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/memory
        value: 2Gi
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: APP_ENV
          value: production

Путь с индексом 0 хрупок: порядок контейнеров может измениться. Если есть возможность, используйте strategic merge с именем контейнера. Селектор в target надёжнее имени, когда включён namePrefix.

Генераторы ConfigMap и Secret

Kustomize умеет собирать ConfigMap и Secret из файлов и литералов и добавлять к имени хеш содержимого. Хеш меняет имя объекта, Deployment ссылается на новое имя, и поды перезапускаются при изменении конфигурации. Это поведение по умолчанию, и его стоит сохранять.

configMapGenerator:
  - name: app-config
    literals:
      - LOG_LEVEL=info
      - FEATURE_FLAGS=orders,search
    files:
      - nginx.conf
secretGenerator:
  - name: db-auth
    envs:
      - db.env
generatorOptions:
  immutable: false

Секреты из db.env не должны попадать в Git: в репозитории держите шаблон, а реальные значения подставляйте в CI из хранилища секретов. disableNameSuffixHash: true отключает хеш, но тогда обновление ConfigMap не приведёт к перезапуску подов — это частая причина ситуации «конфиг изменил, а приложение работает по-старому».

Компоненты и порядок слоёв

Компонент — переиспользуемый кусок конфигурации, который подключается не ко всем средам. В отличие от базы, компонент не является самостоятельным приложением: это набор патчей и ресурсов, который добавляют в overlay выборочно.

# components/observability/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
patches:
  - path: metrics-sidecar.yaml
    target:
      kind: Deployment

В overlay достаточно добавить components: [../../components/observability]. Порядок применения фиксирован и не зависит от того, как ключи расположены в файле. Поэтому не рассчитывайте, что патч одного overlay переопределит патч другого: конфликтующие правки лучше держать в одном слое и проверять собранный результат целиком.

Проверка и типичные ошибки

kustomize build overlays/prod
kubectl diff -k overlays/prod
kubectl apply -k overlays/prod --dry-run=server
(cd overlays/prod && kustomize edit set image registry.example.com/shop/api=registry.example.com/shop/api:1.43.0)

kubectl diff показывает, что изменится, и не трогает кластер. --dry-run=server прогоняет валидацию API, включая вебхуки и квоты. Если сборка не находит файл за пределами каталога, помогает флаг --load-restrictor LoadRestrictionsNone, но злоупотреблять им не стоит: он ломает воспроизводимость.

  • Namespace не переименовывает ClusterRole и CRD. Это кластерные ресурсы, префикс к ним не применяется автоматически.
  • ConfigMap стал неизменяемым. При immutable: true повторное применение с новыми данными упадёт; удалите объект или снимите флаг.
  • Патч не применяется. Проверьте target, имя и метки: селектор должен совпадать с исходным ресурсом.
  • Дубликаты ресурсов. Два overlay подключают один и тот же файл; Kustomize сообщит об этом, а не молча перезапишет.
  • Секреты в открытом виде. secretGenerator не шифрует данные, он лишь кодирует их в base64.

Чек-лист перед применением

  1. Сборка воспроизводится из чистого клона без локальных файлов.
  2. kubectl diff показывает только ожидаемые изменения.
  3. Тег образа зафиксирован, а не равен latest.
  4. Секреты приходят из CI или внешнего хранилища, а не из Git.
  5. Есть план отката: предыдущий коммит и известная рабочая ревизия.

Итог

Kustomize остаётся самым предсказуемым способом собрать манифесты для нескольких сред: база хранит общее, overlay — отличия, патчи описывают только изменяемые поля. В 2026 году его достаточно иметь в составе kubectl, а отдельный бинарник нужен лишь для CI и старых скриптов. Начните с двух overlay и одного strategic merge патча, проверьте результат через kubectl diff — и только потом добавляйте компоненты и генераторы.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте