Yesterday

yq: инструмент YAML, который должен знать каждый специалист DevOps

Это перевод оригинальной статьи yq: The YAML Tool Every DevOps Should Know.

Подписывайтесь на телеграм-канал usr_bin, где я публикую много полезного по Linux, в том числе ссылки на статьи в этом блоге.

Создавайте и редактируйте YAML-файлы без ошибок

YAML стал основой DevOps, но достаточно одной незаметной опечатки, чтобы всё сломать.
YAML захватил современный DevOps. Он лежит в основе Kubernetes, GitHub Actions, CloudFormation, Docker Compose — по сути, почти всего. YAML — мощный инструмент, но его невероятно легко сломать. Один неправильный пробел, один пропущенный дефис — и вся наша система отказывается запускаться.

В этой статье мы подробно рассмотрим yq, суперспособность командной строки, которая предотвращает сбои в работе с YAML. Мы расскажем, как с помощью yq редактировать, проверять и автоматизировать YAML без опасений.

Введение в yq

Что такое yq?

yq — инструмент командной строки, предназначенный для безопасного чтения, редактирования, проверки и преобразования файлов YAML. Представьте jq как мощный, предсказуемый и идеально подходящий для автоматизации инструмент для работы с YAML.

Зачем использовать yq?

С помощью yq мы можем:

  • Просматривать и выполнять запросы к глубоко вложенным YAML-файлам
  • Безопасно изменять значения, массивы и ключи.
  • Объединять несколько YAML-файлов интеллектуально.
  • Применять условную логику и автоматизацию.

Начало работы с yq

Установка

Прежде чем использовать yq, нам необходимо установить его в нашей системе. yq доступен для macOS, Linux и Windows, и мы даже можем запускать его непосредственно из Docker без установки чего-либо локально.

# macOS
brew install yq

# Linux (binary)
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 \
  -O /usr/bin/yq && sudo chmod +x /usr/bin/yq

# Windows (Scoop)
scoop install yq

Проверка После установки yq убедитесь в работоспособности, проверив версию:

yq --version

Это подтверждает, что yq установлен, доступен для выполнения и работает корректно.

Базовые операции и синтаксис

Базовая структура команды достаточно проста:

yq [flags] '<expression>' [file(s)]
  • yq — сама команда
  • flags — необязательные параметры, которые изменяют поведение yq. Например: -i — редактирование на месте, -o=json — вывод в формате JSON.
  • '<expression>' — запрос или операция, которую мы хотим выполнить над файлом YAML.
  • [file(s)] — один или несколько YAML-файлов для чтения (config.yml, *.yml)

В рамках этого руководства мы будем использовать YAML-файл:

testing.yaml

app:
  name: demo       # key/value
  version: 1.0     # key/value
  ports:           # key with a sequence (array) value
    - 80
    - 443

other.yaml

app:
  name: other       
  version: 2.0     
  ports:           
    - 3000

Чтение и запрос значений. Мы используем оператор точки (.) для обхода ключей и квадратные скобки ([]) для обращения к индексам массивов.

Чтение всего YAML-файла:

yq '.' testing.yaml
  • . — представляет собой текущий документ

Чтение конкретного ключа (обход ключа):

yq '.app' testing.yaml
  • '.app'— выражение для выбора ключа с указанным именем app

Чтение вложенного ключа:

yq '.app.name' testing.yaml

Чтение конкретного элемента массива:

yq '.app.ports[0]' testing.yaml

Чтение нескольких файлов

yq e '.app.version' *.yaml
  • *.yaml — применяет команду ко всем YAML-файлам в текущей папке
  • *.yaml соответствует нескольким файлам
  • yq выводит результаты по одному файлу.
  • --- является разделителем документов в YAML

Вставка/обновление значений (на месте) Используем для этого оператор присваивания (=) и флаг -i (редактирование на месте).

Вставить/обновить строку:

yq e -i '.app.name = "new-demo"' testing.yaml
  • -i(редактирование на месте) — изменяет входной файл(ы) напрямую. Использовать с осторожностью!
  • e/ eval — вычислить выражение в соответствии с YAML-файлом. Без параметра e файл может быть не изменен.
  • 'app.name' — если ключ существует, он обновляется; в противном случае создаётся.

Вставить/обновить число:

yq -i '.app.replicas = 5' testing.yaml

Вставка/обновление элемента массива:

yq e -i '.app.ports[0] = 8081' testing.yaml
  • port=8080 — устанавливает значение первого элемента массива ports равным 8080

Использование переменных окружения:

NAME=prod yq -i '.env = strenv(NAME)' config.yaml

Несколько обновлений:

`yq -i '.a = 1
До версии v4 yq использовалась только команда `eval`, поэтому команда была проще. Но теперь в yq v4 есть разные подкоманды, например: e/eval,w , m/merge, d / diff. Всегда используйте yq e при чтении или редактировании..

Удаление, объединение и добавление

Удаление ключей или значений массива

yq e -i 'del(.app.replicas)' testing.yaml
yq e -i 'del(.app.ports[1])' testing.yaml
  • del() — встроенная функция для удаления пути
  • .app.replicas — ключ, который нужно удалить из файла

Добавить в массив

yq e -i '.app.ports += [9090]' testing.yaml
  • .app.ports — путь к массиву ports внутри ключа app
  • += [9090] — добавляет значение 9090 к существующему массиву

Добавить несколько элементов:

yq e -i '.app.ports += [5000, 5001]' testing.yaml

Добавить сложные структуры:

yq e -i '.services += [{"name": "cache", "port": 6379}]' file.yaml
  • += [...] — добавляет новые элементы в существующий массив
  • {...} — объект JSON внутри массива — добавляет сложный объект, а не просто число или строку.

Объединить два файла

yq -n 'load("testing.yaml") * load("other.yaml")'
  • -n — начать с пустого документа вместо чтения из stdin
  • load("testing.yaml") — загрузить файл testing.yaml как объект YAML.
  • * — оператор объединения (overlay merge)
  • load("other.yaml") — загрузить файл 2 и объединить его с файлом 1
  • Любые совпадающие ключи из other.yaml переопределят значения в testing.yaml.
  • Если ключ существует в other.yaml, но отсутствует в testing.yaml, он будет добавлен к результату.
  • Что касается массивов, то yq полностью заменяет их вместо добавления новых элементов

Объединение двух файлов с добавлением массивов вместо замены:

yq -n 'load("testing.yaml") *+ load("other.yaml")'
  • *+ — объединяет объекты и добавляет элементы в массивы

Объединить и сохранить результат:

yq -n 'load("testing.yaml") * load("other.yaml")' > merged.yaml

Использование переменных окружения в yq

В автоматизации (CI/CD, Docker, Kubernetes) часто возникает необходимость, чтобы yq напрямую подставлял динамические значения (например, переменные окружения) в YAML-файлы. Функция yq позволяет сделать это без проблем env().

Предположим, у нас есть переменная окружения:

export PORT=8088

Значение переменной окружения можно внедрить следующим образом:

yq e -i '.app.ports[0] = env(PORT)' testing.yaml

Мы также можем избежать случайного преобразования числа в строку:

yq e -i '.app.replicas = (env(REPLICAS) | tonumber)' file.yaml
  • Это позволяет сохранять числа в числовом виде, а не "number" в виде строк.

Расширенная фильтрация и логика

yq унаследовал мощные возможности фильтрации и обработки из языка выражений jq.

Мы можем:

  • выбрать элементы по условию
  • обновлять только подходящие поля
  • удалить определенные объекты
  • динамически преобразовывать значения
  • выполнять циклы и вычисления выражений

Давайте отредактируем наш файл testing.yaml, прежде чем переходить к следующему шагу.

app:
  name: demo-app
  version: 1.0
  enabled: true
  ports:
    - 8080
    - 443
  replicas: 2

services:
  - name: api
    url: https://api.demo.local
    role: backend
  - name: frontend
    url: https://demo.local
    role: web
  - name: db
    url: postgresql://db.demo.local
    role: database

debug: false

metadata:
  environment: staging
  owner: devops-team

Поиск элементов по условию

yq '.services[] | select(.role == "database")' testing.yaml
  • .services[] — перебор каждого элемента массива services.
  • select(...) — оставляет только элементы, соответствующие условию
  • .role == "database" (условие) — фильтр: выбираем только те элементы, у которых ключ role равен database

Условные обновления

yq -i '(.app.replicas | select(. < 3)) = 3' testing.yaml
  • Обновляет поле replicas в app только в том случае, если его текущее значение меньше 3, и записывает изменение обратно в файл.

Удаление объектов из массива на основе правила

yq -i '.services |= map(select(.role != "web"))' testing.yaml
  • map(...) — обработка каждого элемента массива
  • select(...) — оставляет только элементы, подходящие под условие
  • .role != "web"(Условие) — оставляем всё, кроме элементов с role равным "web"

Динамическое преобразование значений

yq -i '.services[].url |= . + ":latest"' testing.yaml
  • .url — целевое поле url каждого элемента
  • . + ":latest" — берём текущее значение (.) и добавляем :latest

Логика с использованием конструкции if-then-else

Включение режима отладки только для окружения staging:

yq -i '
  if .metadata.environment == "staging" then
    .debug = true
  else
    .
  end
' testing.yaml
  • if .metadata.environment == "staging"(Состояние) — проверьте значение environment
  • then .debug = true — действие, если условие истинно
  • else . — оставляем всё без изменений, если условие ложно.
  • end — Конец блока if-then-else

Работа с различными форматами

Одна из самых мощных функций — yq v4 это возможность возможность конвертации между YAML, JSON и даже raw strings. Это особенно полезно в современных конвейерах DevOps, где разные инструменты могут требовать разные форматы.

YAML в JSON

yq eval -o=json testing.yaml > testing.json
  • -o=json — вывод в формате JSON

JSON в YAML

yq eval -P testing.json > testing.yaml
  • -P или --prettyPrint выводит читаемый YAML

Чтение из stdin:

cat testing.json | yq eval '.app.name' -
  • - — указывает yq читать данные из stdin, удобно для конвейеров CI/CD.

Манипуляции со строками inline:

yq eval '"Hello " + .app.name' testing.yaml
  • Объединяет данные Hello с полем app.name. Работает также с числами, булевыми значениями и массивами.

Заключительные мысли

Благодаря yq, редактирование YAML-файлов перестаёт быть сложным и чреватым ошибками — он становится безопасным, эффективным и полностью автоматизированным. yq — это не просто парсер YAML, это мощный инструмент, готовый к автоматизации, который позволяет нам:

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

На этом все! Спасибо за внимание! Если статья была интересна, подпишитесь на телеграм-канал usr_bin, где будет еще больше полезной информации.