← Kubernetes: Kustomize и Helm
6 мин · просто · Урок 3 из 9

Kustomize: патчи

Точечная правка одного ресурса: strategic merge patch, формат JSON 6902 и как выбирать цель.

Трансформер бьёт по всем ресурсам группы. Префикс уходит на каждое имя, label на каждый объект. Иногда это лишнее: реплики надо поднять у одного Deployment, лимиты памяти поправить у одного контейнера, остальное трогать нельзя.

Патч - это правка, адресованная конкретному ресурсу. Kustomize берёт собранный объект и накладывает на него изменение, описанное в одном из двух форматов.

Strategic merge patch

containers: ключ слияния name база - name: app image: nginx - name: log + патч - name: app image: nginx:1.26 → результат - name: app image: nginx:1.26 - name: log args: ключа слияния нет база - --log=info - --port=80 + патч - --log=debug → результат - --log=debug --port=80 пропал
Слияние идёт по ключу name; у списка строк ключа нет, и патч затирает его целиком.

Самый читаемый вариант. Вы пишете обрезанный кусок того же манифеста: только меняемое поле плюс минимум для опознания объекта (apiVersion, kind, metadata.name).

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
patches:
  - target:
      kind: Deployment
      name: web
    patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: web
      spec:
        replicas: 3

Исходный deployment.yaml не меняется, в отрендеренном выводе replicas станет 3. Блок target говорит, к какому объекту применить правку.

Слово strategic в названии означает, что Kubernetes знает структуру своих типов и умеет сливать списки по ключу, а не заменять их целиком. Для списка контейнеров ключ слияния - это name. Поэтому такой патч поправит ресурсы одного контейнера и не выкинет остальные:

patches:
  - target:
      kind: Deployment
      name: web
    patch: |
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: web
      spec:
        template:
          spec:
            containers:
              - name: app
                resources:
                  limits:
                    memory: 512Mi

Контейнер ищется по name: app. Если такого контейнера в Deployment нет, Kustomize добавит новый, а не сообщит об ошибке.

Ключ слияния есть не у всех списков. У контейнеров он есть, а у списков строк (command, args) нет: такой список патч заменяет целиком. Дописать один аргумент к существующим strategic merge не даст, нужен JSON 6902 с add и путём, оканчивающимся на -.

Патч в отдельном файле

Инлайн удобен для двух строк. Когда правка разрастается, её выносят:

patches:
  - path: patches/resources.yaml
    target:
      kind: Deployment
      name: web

Внутри файла лежит тот же обрезанный манифест. Если в файле указаны apiVersion, kind и metadata.name, блок target можно не писать: Kustomize найдёт цель по этим полям.

JSON 6902

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

patches:
  - target:
      kind: Deployment
      name: web
    patch: |
      - op: replace
        path: /spec/replicas
        value: 3
      - op: add
        path: /spec/template/spec/containers/0/env/-
        value:
          name: LOG_LEVEL
          value: debug

Доступны операции add, remove, replace, move, copy и test. Путь пишется как JSON Pointer: сегменты через слэш, элементы списка по числовому индексу.

Символ - вместо индекса означает конец списка, то есть добавление в хвост. Это единственный способ дописать элемент, не зная текущей длины.

Strategic merge читается легче и подходит для большинства правок. JSON 6902 незаменим там, где нужно адресовать элемент списка по позиции, удалить конкретный элемент или поправить объект без известной Kubernetes схемы слияния, например Custom Resource.

Как выбирать цель

target умеет больше, чем kind и name:

patches:
  - path: patches/probe.yaml
    target:
      kind: Deployment
      labelSelector: "tier=backend"

Помимо labelSelector есть annotationSelector, namespace, group, version. Поле name понимает регулярное выражение, так что name: "web-.*" накроет несколько объектов одним патчем.

Что обычно ломается

Операция replace в JSON 6902 требует, чтобы путь уже существовал. Если поля в манифесте нет, патч упадёт с ошибкой про отсутствующий путь. В таком случае берут add: она и создаёт, и перезаписывает.

Патч, который ни в кого не попал, чаще всего означает опечатку в target. Проверить проще всего рендером: kubectl kustomize . покажет объекты после наложения всех правок, и станет видно, применилась правка или нет.

Удаление поля через strategic merge делается директивой $patch: delete, а не отсутствием поля. Просто убрать строку из патча недостаточно: патч описывает только то, что добавляется или меняется.

Домашка

Теорию закрепляет задание на своём кластере: 1 шаг с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-kustomize-patches     # развернуть стартовое состояние
./run.sh verify k8s-kustomize-patches    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.