Эффективная автоматизация управления ресурсами в Microsoft Azure с помощью Azure CLI немыслима без понимания того, как обрабатывать результаты выполнения команд. Выбор правильного формата вывода (--output или -o) — это фундаментальное архитектурное решение, влияющее на надежность, скорость разработки и поддержку скриптов.
На актуальными остаются два основных подхода: структурированный JSON (и его вариации jsonc, yaml) и плоские текстовые форматы (TSV, table, text). В этой статье мы подробно разберем, когда и почему стоит выбирать тот или иной формат, опираясь на лучшие практики и специфику сред выполнения (Bash, PowerShell, GitHub Actions, ARM Deployment Scripts).
Обзор доступных форматов вывода
Azure CLI поддерживает несколько форматов, задаваемых глобально (az configure --defaults output=json) или локально для каждой команды (az vm list -o tsv).
- json (по умолчанию): Стандартный JSON. Идеален для программной обработки;
- jsonc: JSON с цветами (для интерактивного чтения в терминале).
- yaml: YAML-сериализация (часто удобнее для чтения конфигов).
- tsv (Tab-Separated Values): Плоский текст, разделенный табуляцией. Отлично подходит для
awk,cut, цикловwhile readв Bash. - table: ASCII-таблица с заголовками. Только для человеческого чтения.
- text: Псевдоним для
tsv(в старых версиях) или простое текстовое представление. - none: Подавление вывода (для команд, где важен только код возврата или побочные эффекты).
JSON: Стандарт де-факто для автоматизации
Почему JSON выигрывает в сложных сценариях
JSON возвращает полную объектную модель ресурса Azure. Это означает, что у вас есть доступ ко всем свойствам: id, name, type, location, tags, properties (включая вложенные объекты, массивы SKU, сетевые интерфейсы, диски и т.д.).
Мощь запросов JMESPath (--query)
Главное преимущество JSON — язык запросов JMESPath. Он позволяет фильтровать, проецировать и трансформировать данные прямо внутри CLI, не вызывая внешние утилиты.
# Получить список ID запущенных ВМ в конкретной группе ресурсов
az vm list -g MyResourceGroup --query "[?powerState=='VM running'].id" -o tsv
az vm list-ip-addresses -g MyRG --query "[].{name: virtualMachine.name, ip: virtualMachine.network.publicIpAddresses[0].ipAddress}" -o json
Интеграция с Bash: jq — лучший друг DevOps
Хотя JMESPath мощен, для сложной логики (математика, рекурсия, сложные строковые манипуляции) стандарт де-факто — утилита jq.
# Пример: Найти ВМ с диском больше 100GB и вывести имя + размер
az vm show -g MyRG -n MyVM -o json |
jq -r '.storageProfile.dataDisks[] | select(.diskSizeGb > 100) | "(.name) (.diskSizeGb)GB"'
Специфика ARM Deployment Scripts (Bash/CLI)
Согласно документации Microsoft Learn (Use deployment scripts in Azure Resource Manager templates), при использовании Azure CLI в Deployment Scripts внутри ARM-шаблонов или Bicep, существует важная особенность:
В отличие от PowerShell, CLI/bash не предоставляет общую переменную для выходных данных. Вместо этого используется переменная окружения AZ_SCRIPTS_OUTPUT_PATH. Ее предопределенное значение:
/mnt/azscripts/azscriptoutput/scriptoutputs.json.
Практический вывод: Ваш Bash-скрипт внутри Deployment Script обязан записать результат в этот файл в формате JSON.
#!/bin/bash
RESULT=$(az storage account show -g $RG -n $STORAGE_ACCOUNT --query "{name: name, primaryEndpoints: primaryEndpoints.blob}" -o json)
echo $RESULT > $AZ_SCRIPTS_OUTPUT_PATH
Работа с JSON в PowerShell
Если вы вызываете Azure CLI из PowerShell (например, при миграции скриптов, как упоминалось на Stack Overflow Az Powershell function ─ how to get output in JSON format), JSON — единственный безопасный выбор.
# PowerShell 7+ (Core) / Windows PowerShell 5.1
$json = az resource list -g MyRG -o json | ConvertFrom-Json
$json | Where-Object { $_;type -eq 'Microsoft.Compute/virtualMachines' } | Select-Object name, location
Важно: Избегайте формата text или table в PowerShell — парсинг строк с пробелами в именах ресурсов приведет к ошибкам. Статья на Medium Use dynamic JSON strings with Azure CLI commands in PowerShell подчеркивает, что передача сложных объектов (JSON строк) в параметры CLI команд из PowerShell требует корректного экранирования, что возможно только при структурированных данных.
TEXT / TSV: Скорость и простота для простых задач
Когда TSV незаменим
- Циклы в Bash (while read loop): Самый быстрый способ итерироваться по списку ресурсов без накладных расходов на запуск
jqили парсинг JSON в чистом Bash. - Конвейеры Unix (pipes): Работа с
awk,sed,cut,xargs. - Генерация аргументов для других команд: Передача списка имен/ID в
xargs -I {} az vm delete --ids {}. - CI/CD Логирование: Компактный, читаемый лог в консоли GitHub Actions / Azure Pipelines.
Пример: Массовое удаление/операции через xargs
# Получить ID остановленных ВМ и удалить их (параллельно, по 4 процесса)
az vm list -g MyRG --query "[?powerState=='VM deallocated'].id" -o tsv |
xargs -P 4 -I {} az vm delete --ids {} --yes --no-wait
Опасность формата table в скриптах
Формат table (и text в некоторых версиях) выводит заголовки и выравнивание пробелами.
Name ResourceGroup Location
------ --------------- --------
vm-prod rg-prod eastus
Парсить это в скрипте — плохая практика (заголовки, переменная ширина колонок, проблемы с пробелами в именах). Всегда используйте tsv для машинной обработки.
Сравнительная таблица: JSON vs TSV
| Критерий | JSON (с JMESPath / jq) | TSV (Text) |
|---|---|---|
| Структура данных | Иерархическая, вложенные объекты/массивы | Плоская (строка = запись, колонка = поле) |
| Доступ к вложенным свойствам | Нативно (properties.storageProfile.imageReference.offer) | Требует предварительного --query для «выпрямления» |
| Парсинг в Bash | Требует jq (рекомендуется) или сложный Bash-парсинг | Нативный while IFS=$' ' read -r col1 col2; do ... done |
| Парсинг в PowerShell | Идеален (ConvertFrom-Json) | Сложен/хрупок (ConvertFrom-Csv -Delimiter "`t") |
| Безопасность имен (пробелы, спецсимволы) | Высокая (строгие кавычки в JSON) | Риск разбиения полей, если в значении есть таб/перенос строки (редко, но бывает) |
| Производительность (большие списки) | Чуть выше накладные расходы на сериализацию | Минимальные накладные расходы, быстрее стриминг |
| ARM Deployment Scripts | Обязателен (запись в AZ_SCRIPTS_OUTPUT_PATH) | Не подходит для возврата результата в ARM |
| GitHub Actions / Azure Pipelines | Для set-output / task.setvariable (сложные объекты) | Для простых списков, матриц стратегий (matrix) |
Лучшие практики и паттерны (Best Practices)
Правило №1: Явно указывайте формат в скриптах
Никогда не полагайтесь на дефолт (json) или конфиг пользователя (az configure). Всегда пишите -o json или -o tsv в каждой команде скрипта. Это гарантирует детерминированное поведение на любом агенте (Hosted Agent, Self-hosted, Cloud Shell);
Правило №2: Используйте --query для проекции до вывода
Не скачивайте весь объект ВМ (мегабайты JSON), если вам нужен только id и name.
# Плохо: лишний трафик и память
az vm list -g MyRG -o json | jq '.[].id'
az vm list -g MyRG --query "[].id" -o tsv
Правило №3: Гибридный подход для сложных пайплайнов
Часто оптимально: получить список ID в TSV, а детали конкретного ресурса — в JSON.
# 1. Быстрый список ID (TSV)
ids=$(az vm list -g $RG --query "[?tags.env=='prod'].id" -o tsv)
for id in $ids; do
sku=$(az vm show --ids $id -o json | jq -r '.hardwareProfile.vmSize')
if [[ "$sku" == "Standard_D2s_v3" ]]; then
echo "Resizing $id..."
az vm resize --ids $id --size Standard_D4s_v5 --no-wait
fi
done
Правило №4: Обработка ошибок и пустых выводов
- JSON: Пустой массив
[]— валидный JSON. Проверяйте длину:jq 'length == 0'. - TSV: Пустой вывод — пустая строка. В Bash цикл
while readпросто не выполнится ни разу (безопасно), но переменная будет пустой. - Всегда проверяйте
$?(код возврата CLI) перед парсингом вывода.
Правило №5: Экранирование в PowerShell при передаче JSON
Если вы формируете JSON строку в PowerShell для передачи в параметр Azure CLI (например, --parameters или тело запроса), используйте ConvertTo-Json -Compress -Depth 5 и будьте осторожны с кавычками. Статья Philipp Bauknecht Use dynamic JSON strings with Azure CLI commands in PowerShell рекомендует использовать Here-Strings (@' ... '@) или временные файлы для сложных полезных нагрузок, чтобы избежать «ада кавычек».
Специфические сценарии автоматизации
GitHub Actions / Azure Pipelines: Matrix Strategy
Для динамической матрицы (strategy.matrix) нужен JSON.
- name: Get VM List for Matrix
id: vm_matrix
run: |
# Формируем JSON объект для matrix: { "include": [ { "name": "vm1", "rg": "rg1" }, ... ] }
MATRIX=$(az vm list -g $RG --query "map(&{name: name, rg: resourceGroup}, @)" -o json)
echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT
Azure Cloud Shell / Bash: Интерактивная работа vs Скрипты
- Интерактивно:
az configure --defaults output=table(илиjsoncдля цвета). Удобно для исследования. - В скриптах (.sh): Жестко задавайте
-o tsvили-o jsonв каждой строке.
Работа с секретами и чувствительными данными
JSON часто содержит ключи доступа, connection strings, пароли (в properties).
- Используйте
--queryдля исключения секретных полей перед логированием/сохранением в артефакты. - В CI/CD маскируйте вывод:
echo "::add-mask::$(az keyvault secret show ... -o tsv --query value)".
Чек-лист: Что выбрать для вашей задачи?
- Нужно вернуть сложный объект в ARM Template / Bicep / Deployment Script? → JSON (запись в
AZ_SCRIPTS_OUTPUT_PATH). - Пишете скрипт на PowerShell? → JSON (
ConvertFrom-Json). - Нужно просто перебрать список имен/ID в Bash цикле? → TSV (
while IFS=$' ' read -r id name; do ... done). - Нужно извлечь вложенное свойство (например, IP адрес конкретного NIC)? → JSON +
jqили--query. - Формируете матрицу для GitHub Actions / Azure Pipelines? → JSON.
- Передаете список ID в
xargs/parallelдля массовых операций? → TSV. - Ловите ошибку «Property ‘x’ not found» в JMESPath? → Проверьте регистр свойств (JSON чувствителен к регистру) через
az ... -o json | head -20.
Выбор между JSON и TEXT/TSV в Azure CLI — это не вопрос вкуса, а вопрос инструментария окружения и сложности данных.
- JSON — это «тяжелая артиллерия»: стандарт для PowerShell, ARM Deployment Scripts, сложных трансформаций (
jq/JMESPath), работы с вложенными структурами и CI/CD матрицами. Это формат, который гарантирует целостность данных. - TSV — это «легкая пехота»: идеален для Bash-циклов, Unix-конвейеров,
xargs, быстрой выборки плоских списков идентификаторов. Минимальные накладные расходы, максимальная скорость парсинга в shell.
Профессиональный подход: Освойте оба. Используйте --query для формирования именно той «проекции» данных, которая удобна для следующего шага вашего конвейера: плоскую таблицу (TSV) для итераций или иерархию (JSON) для глубокого анализа. И помните про AZ_SCRIPTS_OUTPUT_PATH, это единственный контракт для возврата данных из CLI-скриптов в мир Infrastructure as Code (ARM/Bicep).