Как создавать ресурсы в масштабе с помощью Azure CLI

Администратор облачных ресурсов Azure часто должен создавать несколько ресурсов Azure при настройке новых сред. Кроме того, у вас может быть процесс утверждения ресурсов Azure, который лучше всего работает при автоматическом создании ресурсов Azure из скрипта.

В этой статье описаны следующие элементы:

  • Создайте несколько ресурсов Azure из параметров, полученных из CSV-файла с разделителями.
  • Используйте инструкции IF...THEN для создания связанных ресурсов Azure.
  • Записывать прогресс выполнения скрипта в локальный TXT-файл.

Этот пример скрипта был протестирован в Azure Cloud Shell с помощью сред Bash и PowerShell 7. Найдите CSV-файл и полный скрипт в Azure-samples/azure-cli-samples.

Подготовьте вашу среду

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

  • Откройте среду Bash или PowerShell в Azure Cloud Shell. Для получения дополнительной информации см. Краткое руководство по началу работы с Bash в Azure Cloud Shell.

  • Скачайте и сохраните следующий CSV-файл в локальный каталог. Замените myExistingResourceGroupName в строке три фактическим именем группы ресурсов.

    resourceNo,location,createRG,exstingRgName,createVnet,vnetAddressPrefix,subnetAddressPrefixes,vmImage,publicIpSku,Adminuser
    1,eastus,TRUE,,TRUE,10.0.0.0/16,10.0.0.0/24,Ubuntu2204,standard,
    2,eastus2,TRUE,,FALSE,,,Debian11,standard,alex-smith
    3,southcentralus,FALSE,myExistingResourceGroupName,FALSE,,,Ubuntu2204,standard,jan-smith
    [empty line for Bash]
    

    Замечание

    Чтобы быть правильным текстовым файлом Unix и быть считываемым Bash, CSV-файлу требуется новый символ строки в конце последней строки данных. Это приводит к пустой строке в конце файла. Пустая строка не должна говорить [empty line], так как этот текст предоставляется только для отображения того, что пустая строка существует. Среды PowerShell не требуют символа новой строки.

  • Отправьте измененный CSV-файл в учетную запись хранения блога Azure Cloud Shell. Самый простой способ сделать это — использовать раскрывающийся список "Управление файлами " в главном меню Azure Cloud Shell. Дополнительные сведения о хранилище Cloud Shell см. в статье "Сохранение файлов в Azure Cloud Shell".

Обзор скрипта

В этой статье разбивается один большой скрипт на четыре раздела, что позволяет объяснить каждый шаг.

  • Настройка переменной
  • Проверка данных
  • Проверка цикла
  • Создание ресурсов Azure

Существует также два сценария: один для Bash и второй для PowerShell. Оба сценария используют одни и те же команды Azure CLI. Отличается среда или профиль терминала. Например, Bash использует do...done и if...then...fi. В среде PowerShell используется эквивалент foreach и if (something is true)...{do this}. В Azure Cloud Shell можно переключаться между средами с помощью кнопки "Переключиться на PowerShell " или "Переключиться на Bash " в главном меню Azure Cloud Shell.

Если вы предпочитаете, перейдите непосредственно к CSV-файлам и файлам скриптов, используемым в этой статье в Azure-samples/azure-cli-samples.

Установка переменных

Начните с создания необходимых переменных для скрипта. Следующие три переменные требуют фактических значений для вашей среды:

  • subscriptionID: это идентификатор подписки Azure.
  • csvFileLocation: это расположение и имя файла входного ФАЙЛА CSV.
  • logFileLocation: это расположение и имя файла , который используется скриптом для создания файла журнала. Вам не нужно создавать или отправлять этот файл.

Переменные с msdocs- префиксом можно заменить префиксом на ваш выбор. Все пустые ("") переменные используют значения из входного CSV-файла. Эти пустые переменные служат заполнителями, необходимыми скриптом.

# Variable block

# Replace these three variable values with actual values
subscriptionID=00000000-0000-0000-0000-00000000
csvFileLocation="myFilePath\myFileName.csv"
logFileLocation="myFilePath\myLogName.txt"

# Variable values that contain a prefix can be replaced with the prefix of your choice.
#   These prefixes have a random ID appended to them in the script.
# Variable values without a prefix will be overwritten by the contents of your CSV file.
location=""
createRG=""
newRgName="msdocs-rg-"
existingRgName=""

createVnet=""
vnetName="msdocs-vnet-"
subnetName="msdocs-subnet-"
vnetAddressPrefix=""
subnetAddressPrefixes=""

vmName="msdocs-vm-"
vmImage=""
publicIpSku=""
adminUser=""
adminPassword="msdocs-PW-@"

# Set your Azure subscription 
az account set --subscription $subscriptionID

Проверка значений CSV-файла

Перед началом тестирования скрипта убедитесь, что CSV-файл отформатирован правильно, и эти переменные назначают правильные значения. Этот скрипт использует инструкцию IF..THEN , чтобы одновременно просматривать одну строку сценария или CSV.

# Verify CSV columns are being read correctly

# Take a look at the CSV contents
cat $csvFileLocation

# Validate select CSV row values
while IFS=, read -r resourceNo location createRG existingRgName createVnet vnetAddressPrefix subnetAddressPrefixes vmImage publicIpSku adminUser
do
  # Generate a random ID
  let "randomIdentifier=$RANDOM*$RANDOM"

  # Return the values for the first data row
  # Change the $resourceNo to check different scenarios in your CSV
  if [ "$resourceNo" = "1" ]; then
    echo "resourceNo = $resourceNo"
    echo "location = $location"
    echo "randomIdentifier = $randomIdentifier"
    echo ""
    
    echo "RESOURCE GROUP INFORMATION:"
    echo "createRG = $createRG"
    if [ "$createRG" = "TRUE" ]; then 
      echo "newRGName = $newRgName$randomIdentifier"
    else
      echo "exsitingRgName = $existingRgName"
    fi
    echo ""

    echo "VNET INFORMATION:"
    echo "createVnet = $createVnet"
    if [ "$createVnet" = "TRUE" ]; then 
      echo "vnetName = $vnetName$randomIdentifier"
      echo "subnetName = $subnetName$randomIdentifier"
      echo "vnetAddressPrefix = $vnetAddressPrefix"
      echo "subnetAddressPrefixes = $subnetAddressPrefixes"
    fi
    echo ""

    echo "VM INFORMATION:"
    echo "vmName = $vmName$randomIdentifier"
    echo "vmImage = $vmImage"
    echo "vmSku = $publicIpSku"
    if [ `expr length "$adminUser"` == "1" ]; then
      echo "SSH keys will be generated."
    else
      echo "vmAdminUser = $adminUser"
      echo "vmAdminPassword = $adminPassword$randomIdentifier"        
    fi
  fi  
# skip the header line
done < <(tail -n +2 $csvFileLocation)

Используя CSV-файл, предоставленный в этой статье, выходные данные проверки приведены следующим образом: ( 00000001 случайный идентификатор отличается для каждого теста.)

resourceNo = 1
location = eastus

RESOURCE GROUP INFORMATION:
createRG = TRUE
newRGName = msdocs-rg-00000001

VNET INFORMATION:
createVnet = TRUE
vnetName = msdocs-vnet-00000001
subnetName = msdocs-subnet-00000001
vnetAddressPrefix = 10.0.0.0/16
subnetAddressPrefix = 10.0.0.0/24

VM INFORMATION:
vmName = msdocs-vm-00000001
vmImage = Ubuntu2204
vmSku = standard
SSH keys will be created

Проверка логики скрипта

Если вы уверены в возможностях сценариев, вы можете пропустить этот шаг. Тем не менее, поскольку этот скрипт предназначен для создания ресурсов Azure в большом масштабе, использование цикла с инструкциями echo или write-host может сэкономить ваше время и избежать дополнительных непредвиденных расходов на ресурсы Azure.

Существует несколько способов итерации через CSV-файл с помощью оболочки Bash. В этом примере используется IFS с параметром while loop.

# Validate script logic

# Create the log file
echo "SCRIPT LOGIC VALIDATION.">$logFileLocation

# Loop through each row in the CSV file
while IFS=, read -r resourceNo location createRG existingRgName createVnet vnetAddressPrefix subnetAddressPrefixes vmImage publicIpSku adminUser
do
  # Generate a random ID
  let "randomIdentifier=$RANDOM*$RANDOM"
    
  # Log resource number and random ID
  echo "resourceNo = $resourceNo">>$logFileLocation
  echo "randomIdentifier = $randomIdentifier">>$logFileLocation

  # Check if a new resource group should be created
  if [ "$createRG" == "TRUE" ]; then
    echo "Will create RG $newRgName$randomIdentifier.">>$logFileLocation
    existingRgName=$newRgName$randomIdentifier
  fi

  # Check if a new virtual network should be created, then create the VM
  if [ "$createVnet" == "TRUE" ]; then
    echo "Will create VNet $vnetName$randomIdentifier in RG $existingRgName.">>$logFileLocation
    echo "Will create VM $vmName$randomIdentifier in Vnet $vnetName$randomIdentifier in RG $existingRgName.">>$logFileLocation
  else
    echo "Will create VM $vmName$randomIdentifier in RG $existingRgName.">>$logFileLocation
  fi
# Skip the header line.
done < <(tail -n +2 $csvFileLocation)

# Clear the console and display the log file
Clear
cat $logFileLocation

Используя CSV-файл, предоставленный в этой статье, выходные данные проверки приведены следующим образом: ( 00000001, 2, 3 случайные идентификаторы отличаются для каждого теста, но каждый ресурс в каждом resourceNo из них должен использовать один и тот же случайный идентификатор.)

resourceNo = 1
createRG = TRUE
createVnet = TRUE
Will create RG msdocs-rg-00000001
Will create VNet msdocs-vnet-00000001 in RG msdocs-rg-00000001
Will create VM msdocs-vm-00000001 within Vnet msdocs-vnet-00000001 in RG msdocs-rg-00000001

resourceNo = 2
createRG = TRUE
createVnet = FALSE
Will create RG msdocs-rg-00000002
Will create VM msdocs-vm-00000002 without Vnet in RG msdocs-rg-00000002

resourceNo = 3
createRG = FALSE
createVnet = FALSE
Will create VM msdocs-vm-00000003 without Vnet in RG <myExistingResourceGroup>

Создание ресурсов Azure

Вы создали блок переменной, проверили значения CSV и завершили тестовое выполнение с помощью echo или write-host. Выполните четвертую и окончательную часть скрипта, чтобы создать ресурсы Azure, как определено в csv-файле ввода.

# Create Azure resources

# Create the log file
echo "CREATE AZURE RESOURCES.">$logFileLocation

# Loop through each CSV row
while IFS=, read -r resourceNo location createRG existingRgName createVnet vnetAddressPrefix subnetAddressPrefixes vmImage publicIpSku adminUser
do
  # Generate a random ID
  let "randomIdentifier=$RANDOM*$RANDOM"

  # Log resource number, random ID and display start time
  echo "resourceNo = $resourceNo">>$logFileLocation
  echo "randomIdentifier = $randomIdentifier">>$logFileLocation
  echo "Starting creation of resourceNo $resourceNo at $(date +"%Y-%m-%d %T")."

  # Check if a new resource group should be created
  if [ "$createRG" == "TRUE" ]; then
    echo "Creating RG $newRgName$randomIdentifier at $(date +"%Y-%m-%d %T").">>$logFileLocation
    az group create --location $location --name $newRgName$randomIdentifier >>$logFileLocation
    existingRgName=$newRgName$randomIdentifier
    echo "  RG $newRgName$randomIdentifier creation complete"
  fi

  # Check if a new virtual network should be created, then create the VM
  if [ "$createVnet" == "TRUE" ]; then
    echo "Creating VNet $vnetName$randomIdentifier in RG $existingRgName at $(date +"%Y-%m-%d %T").">>$logFileLocation
    az network vnet create \
        --name $vnetName$randomIdentifier \
        --resource-group $existingRgName \
        --address-prefix $vnetAddressPrefix \
        --subnet-name $subnetName$randomIdentifier \
        --subnet-prefixes $subnetAddressPrefixes >>$logFileLocation
    echo "  VNet $vnetName$randomIdentifier creation complete"
    
    echo "Creating VM $vmName$randomIdentifier in Vnet $vnetName$randomIdentifier in RG $existingRgName at $(date +"%Y-%m-%d %T").">>$logFileLocation
    az vm create \
        --resource-group $existingRgName \
        --name $vmName$randomIdentifier \
        --image $vmImage \
        --vnet-name $vnetName$randomIdentifier \
        --subnet $subnetName$randomIdentifier \
        --public-ip-sku $publicIpSku \
        --generate-ssh-keys >>$logFileLocation
    echo "  VM $vmName$randomIdentifier creation complete"
  else
    echo "Creating VM $vmName$randomIdentifier in RG $existingRgName at $(date +"%Y-%m-%d %T").">>$logFileLocation
    az vm create \
        --resource-group $existingRgName \
        --name $vmName$randomIdentifier \
        --image $vmImage \
        --public-ip-sku $publicIpSku \
        --admin-username $adminUser\
        --admin-password $adminPassword$randomIdentifier >>$logFileLocation
    echo "  VM $vmName$randomIdentifier creation complete"    
  fi
# skip the header line
done < <(tail -n +2 $csvFileLocation)

# Clear the console (optional) and display the log file
# clear
cat $logFileLocation

В вашем консольном выводе отсутствует последняя строка в CSV-файле? Эта проблема может быть вызвана отсутствующим символом продолжения строки после последней строки. Чтобы устранить проблему, добавьте пустую строку в конце CSV-файла.

Выходные данные консоли перед чтением файла журнала:

Starting creation of resourceNo 1 at YYYY-MM-DD HH:MM:SS.
  RG msdocs-rg-00000001 creation complete
  VNet msdocs-vnet-00000001 creation complete
  VM msdocs-vm-00000001 creation complete

Starting creation of resourceNo 2 at YYYY-MM-DD HH:MM:SS.
  RG msdocs-rg-00000002 creation complete
  VM msdocs-vm-00000002 creation complete

Starting creation of resourceNo 3 at YYYY-MM-DD HH:MM:SS.
  VM msdocs-vm-00000003 creation complete

Содержимое файла журнала должно выглядеть следующим образом:

Starting creation of resourceNo 1 at YYYY-MM-DD HH:MM:SS.
  Creating RG msdocs-rg-00000001 at YYYY-MM-DD HH:MM:SS.
  {
  Resource group create output
  }
  Creating VNet msdocs-vnet-00000001 in RG msdocs-rg-000000001 at YYYY-MM-DD HH:MM:SS.
  {
  VNet create output
  }  
  Creating VM msdocs-vm-00000001 in RG msdocs-rg-00000001 at YYYY-MM-DD HH:MM:SS.
  {
  VM create output
  }

Starting creation of resourceNo 2 at YYYY-MM-DD HH:MM:SS.
  Creating RG msdocs-rg-00000002 at YYYY-MM-DD HH:MM:SS.
  {
  Resource group create output
  }
  Creating VM msdocs-vm-00000002 in RG msdocs-rg-00000002 at YYYY-MM-DD HH:MM:SS.
  {
  VM create output
  }

Starting creation of resourceNo 3 at YYYY-MM-DD HH:MM:SS.
  Creating msdocs-vm-00000003 creation complete
  {
  VM create output
  }

Устранение неполадок

В Bash шаг "Создание ресурсов Azure" останавливается после шага 1

В Ubuntu 22.04.3 LTS и Debian версии 12 (bookworm), логика скрипта проверки работает должным образом, возвращая результаты для всех трех ресурсов. Однако после создания первого ресурса будет остановлено создание ресурсов Azure . Возможная причина этой проблемы заключается в том, что создание виртуальной сети на шаге 1 занимает несколько секунд. Ubuntu и Debian переходят ко второму ресурсу, не ожидая завершения виртуальной сети (VNet). Дополнительные сведения об этом можно прочитать в неожидании завершения процессов в цикле или ожидании завершения любого процесса в скрипте bash.

Скрипт Bash игнорирует оператор IF

Bash чувствителен к регистру. Слово true не равно TRUE. Также greater than является -gt, а не >, и equals является ==, а не =. Убедитесь, что у вас нет типографических ошибок или начальных или конечных пробелов в значениях столбца CSV.

Значения переменных не изменяются при каждом цикле

Эта проблема часто вызвана дополнительными пробелами в CSV-файле. Строка в CSV-файле выглядит примерно так: column1,column2,column3 или column1,,column3, но по привычке легко создать тестовый файл, содержащий пробел после каждой запятой.column1, column2, column3 Если в CSV-файле есть начальный или конечный пробел, значение столбца на самом деле <space>columnValue. Логика if [ "$columnName" = "columnValue" ] скрипта возвращает значение false. Чтобы устранить проблему, удалите все начальные и конечные пробелы в строках CSV.

Недопустимая нотация CIDR

Ошибка InvalidCIDRNotation возникает, когда вы передаете неправильный префикс адреса az network vnet create. Это может быть сложно, когда префикс адреса выглядит правильно при возврате в инструкции echo . Чтобы устранить неполадки с фактическим значением, считываемым из CSV-файла, попробуйте выполнить следующий скрипт:

while IFS=, read -r resourceNo location createRG existingRgName createVnet vnetAddressPrefix subnetAddressPrefixes vmImage publicIpSku adminUser
do
    echo "resourceNo = $resourceNo"

    if [ "$createVnet" == "TRUE" ]; then
      startTest="abc"
      endTest="xyz"
      echo $startTest$vnetAddressPrefix$endTest
    fi
done < <(tail -n +2 $setupFileLocation)

Если результаты выглядят как xzy10.0.0.0 и не как ожидаемый abc10.0.0.0/24xyz, в вашем CSV-файле может содержаться скрытый символ или дополнительная запятая. Добавьте тестовый столбец с тем же значением префикса, переупорядочьте столбцы CSV, скопируйте и вставьте содержимое CSV-файла в/из простого редактора Блокнот. При написании этой статьи ошибка была наконец исправлена путем переупорядочения столбцов CSV.

Аргументы ожидаются или требуются

Эта ошибка возникает, если не указать обязательный параметр или возникает типографическая ошибка, которая приводит к неправильному анализу команды ссылки с помощью Azure CLI. При работе со скриптом эта ошибка также возникает, если один или более из следующих элементов имеет значение true:

  • Отсутствует или неправильный символ продолжения строки.
  • В правой части символа продолжения строки имеются конечные пробелы.
  • Имя переменной содержит специальный символ, например дефис (-).

Ошибка развертывания шаблона

При попытке создать ресурс Azure в расположении, в котором этот ресурс недоступен, вы получите сообщение об ошибке, например, следующее: "Следующие SKU не были созданы из-за ограничений емкости: 'Standard_DS1_v2' в настоящее время не доступны в расположении 'westus'."

Ниже приведен полный пример ошибки:

{"error":{"code":"InvalidTemplateDeployment","message":"The template deployment 'vm_deploy_<32 character ID>'
is not valid according to the validation procedure. The tracking id is '<36 character ID>'.
See inner errors for details.","details":[{"code":"SkuNotAvailable","message":"The requested VM size for resource
'Following SKUs have failed for Capacity Restrictions: Standard_DS1_v2' is currently not available
in location '<your specified location>'. Please try another size or deploy to a different location
or different zone. See https://aka.ms/azureskunotavailable for details."}]}}

Чтобы исправить ошибку, измените расположение или выберите другое значение параметра, предлагаемое для требуемого расположения.

См. также