YAML уже много лет остаётся стандартным способом писать манифесты Kubernetes. Любой пример, туториал и файл конфигурации, которые попадаются на глаза, написаны на нём. Проблема не в том, что YAML — плохой формат. Проблема в том, что YAML даёт множество вариантов, и не все они одинаково хороши для манифестов Kubernetes. Одни возможности делают файлы менее читаемыми, другими легко воспользоваться неправильно, а третьи приводят к неожиданному поведению.

Интересно вот что: большинство этих возможностей Kubernetes не нужны. Он опирается лишь на небольшое подмножество YAML. Отсюда возник простой вопрос: если Kubernetes нужна только малая часть YAML, почему бы не стандартизировать именно эту часть, а остальное не использовать? Вместо того чтобы вводить новый язык конфигурации, SIG CLI представила KYAML, более строгий и последовательный способ писать YAML. А мы в VK Cloud перевели об этом статью.

Что такое KYAM

KYAML — это строгое подмножество (или «диалект») стандартного YAML, спроектированное так, чтобы существующая экосистема разбирала его без изменений, как предложено в KEP 5295. Он не вводит ни нового формата, ни нового парсера. Он лишь сужает набор решений при написании YAML, чтобы в итоге все принимали одни и те же.

Воспринимайте его не столько как новый язык, сколько как согласованный стиль. Всё, что допустимо в KYAML, допустимо и в YAML.

Как KYAML это решает

У стандартного YAML есть несколько известных ловушек. Свои есть и у JSON.

Чувствительность к отступам. В YAML структуру задают отступы, а значит, файл с неправильным отступом может остаться синтаксически корректным, но описывать не тот объект, который задумывался. Особенно болезненно это проявляется с инструментами шаблонизации вроде Helm, где отступами управляют снаружи, вне контекста YAML.

Неявное приведение типов. Кавычки вокруг строк в YAML необязательны, и это звучит удобно ровно до тех пор, пока не перестаёт быть удобным. Некоторые значения, похожие на строки, без предупреждения превращаются в другие типы. Классический пример — «Norway Bug».

country: NO

В стандартном YAML NO читается как булево false, а не как строка "NO", и это застало врасплох не одного человека.

JSON тоже не ответ. Он не поддерживает комментарии, строг к висячим запятым и требует брать в кавычки каждый ключ, и ничто из этого не делает написание конфигов приятным.

KYAML решает всё это, делая структуру и типы явными:

  • Не полагается на отступы при описании структуры.

  • Всегда заключает строковые значения в кавычки, поэтому неявного приведения типов не происходит.

  • Всегда использует {} для отображений и структур.

  • Всегда использует [] для списков.

  • Допускает комментарии и висячие запятые, в отличие от JSON.

  • Содержит заголовок ---, чтобы с первого взгляда отличать его от JSON, поскольку оба начинаются с {.

В YAML это называется потоковым стилем, в отличие от привычного блочного стиля, которым пользуется большинство. KYAML находится посередине между JSON и YAML: он явнее, чем YAML по умолчанию, и дружелюбнее, чем JSON.

Для сравнения вот один и тот же манифест Pod в обоих форматах.

Стандартный YAML

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: demo
spec:
  containers:
    - name: nginx
      image: nginx:1.20

KYAML

---
{
  apiVersion: "v1",
  kind: "Pod",
  metadata: {
    name: "my-pod",
    labels: {
      app: "demo",
    },
  },
  spec: {
    containers: [{
      name: "nginx",
      image: "nginx:1.20",
    }],
  },
}

Обратите внимание на строковые значения в двойных кавычках, фигурные скобки вокруг каждого отображения, квадратные скобки вокруг списка и висячие запятые. Дополнительный синтаксис задаёт структуру документа явно, а не через отступы.

Как вывести YAML в формате KYAML

Получить вывод в формате KYAML можно несколькими способами.

Вариант 1: kubectl -o kyaml

Начиная с Kubernetes 1.34 kubectl поддерживает KYAML как нативный формат вывода.

# Kubernetes 1.35+ (beta; возможность включена по умолчанию, но параметр -o kyaml в CLI всё ещё нужен)
kubectl get deployment my-app -o kyaml
# Kubernetes 1.34 (alpha, включается вручную)
export KUBECTL_KYAML=true
kubectl get deployment my-app -o kyaml

Чтобы сохранить вывод в файл:

kubectl get deployment my-app -o kyaml > my-app.yaml

Делать KYAML форматом вывода по умолчанию пока не планируется. Если вам удобнее работать с KYAML по умолчанию, задайте нужное значение через kuberc4. Подробности смотрите в документации kuberc.

# Kubernetes 1.36+
kubectl kuberc set --section defaults --command get --option output=kyaml
# Kubernetes 1.33–1.35 (префикс alpha всё ещё обязателен)
kubectl alpha kuberc set --section defaults --command get --option output=kyaml

Вариант 2: yamlfmt от Kubernetes

Вместе с sigs.k8s.io/yaml поставляется инструмент yamlfmt, который преобразует файлы в KYAML.

Установка через Go:

go install sigs.k8s.io/yaml/yamlfmt@latest

Если запустить его на файле, он выведет KYAML-версию в stdout. Он принимает и каталог: тогда преобразует и выведет каждый файл внутри. Поэтому, чтобы преобразование сохранилось, вывод нужно перенаправить в файл (или файлы).

yamlfmt -o=kyaml my-deployment.yaml

Он также может показать diff вместо полного преобразования:

yamlfmt -o=kyaml -d my-deployment.yaml

Вариант 3: yamlfmt от Google

В версии v0.21.0 у yamlfmt от Google появился отдельный форматтер kyaml для преобразования существующих файлов.

Установите через Go или возьмите бинарник со страницы релизов:

go install github.com/google/yamlfmt/cmd/yamlfmt@latest

Он также доступен как pre-commit хук и как Docker-образ для CI-пайплайнов.

Добавьте конфиг .yamlfmt в корень проекта:

formatter:
  type: kyaml

Посмотрите результат, не изменяя файл:

yamlfmt -dry my-deployment.yaml

затем примените:

yamlfmt my-deployment.yaml

Чтобы преобразовать целый каталог:

yamlfmt ./k8s/

Форматтер kyaml не принимает дополнительной конфигурации и не имеет общих опций с форматтером по умолчанию, поэтому при смешивании возникнет ошибка.

Подробнее о доступных режимах и флагах смотрите в документации по использованию команд.

Стоит ли переходить на KYAML?

Каждый валидный файл KYAML — это валидный файл YAML. Поэтому, что бы вы ни написали на KYAML, существующим инструментам, kubectl, CI-пайплайнам — ничему из этого не нужно меняться. KYAML можно даже передать на вход любой версии kubectl, а не только 1.34+, потому что в конечном счёте это просто YAML.

KYAML не строго обязателен. Можно и дальше писать YAML в блочном стиле, и всё будет работать. Но это осознанный выбор: сделать конфиги устойчивее к ошибкам и последовательнее, особенно в команде или большом репозитории.

Это не столько миграция, сколько более удачная привычка.