Udostępnij za pośrednictwem


Jak tworzyć zasoby na dużą skalę przy użyciu interfejsu wiersza polecenia platformy Azure

Jako menedżer zasobów platformy Azure często trzeba tworzyć wiele zasobów platformy Azure podczas konfigurowania nowych środowisk. Możesz również mieć proces zatwierdzania zasobów platformy Azure, który działa najlepiej, gdy zasoby platformy Azure są tworzone automatycznie na podstawie skryptu.

W tym artykule poznasz następujące informacje:

  • Utwórz wiele zasobów platformy Azure na podstawie parametrów odebranych z rozdzielanego pliku CSV.
  • Użyj if.. Instrukcje THEN do tworzenia zależnych zasobów platformy Azure.
  • Postęp skryptu dziennika w lokalnym pliku TXT.

Ten przykładowy skrypt został przetestowany w usłudze Azure Cloud Shell zarówno w środowiskach Bash, jak i PowerShell 7. Znajdź plik CSV i pełny skrypt w artykule Azure-samples/azure-cli-samples.

Przygotowywanie środowiska

Wykonaj następujące kroki, aby przygotować środowisko do uruchomienia przykładowego skryptu:

  • Otwórz środowisko Bash lub PowerShell w usłudze Azure Cloud Shell. Aby uzyskać więcej informacji, zobacz Szybki start dotyczący powłoki Bash w usłudze Azure Cloud Shell.

  • Pobierz i zapisz w katalogu lokalnym następujący plik CSV. Zastąp myExistingResourceGroupName ciąg w wierszu trzy rzeczywistą nazwą grupy zasobów.

    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]
    

    Uwaga

    Aby być odpowiednim plikiem tekstowym systemu Unix i być odczytywany przez powłokę Bash, plik CSV wymaga nowego znaku wiersza na końcu ostatniego wiersza danych. Spowoduje to wyświetlenie pustego wiersza na końcu pliku. Pusty wiersz nie musi powiedzieć [empty line] , ponieważ ten tekst jest podany tylko w celu wyświetlenia, że istnieje pusty wiersz. Środowiska programu PowerShell nie mają tego wymagania dotyczącego nowego znaku wiersza.

  • Przekaż zmodyfikowany plik CSV na konto magazynu bloga usługi Azure Cloud Shell. Najprostszym sposobem, aby to zrobić, jest użycie listy rozwijanej Zarządzanie plikami w menu głównym usługi Azure Cloud Shell. Aby uzyskać więcej informacji na temat magazynu usługi Cloud Shell, zobacz Utrwalanie plików w usłudze Azure Cloud Shell.

Omówienie skryptu

W tym artykule opisano podział pojedynczego dużego skryptu na cztery sekcje, dzięki czemu można wyjaśnić każdy krok.

  • Konfiguracja zmiennej
  • Sprawdzanie poprawności danych
  • Walidacja pętli
  • Tworzenie zasobów platformy Azure

Dostępne są również dwa skrypty: jeden dla powłoki Bash i drugi dla programu PowerShell. Oba skrypty używają tych samych poleceń interfejsu wiersza polecenia platformy Azure. Jest to środowisko lub profil terminalu, który jest inny. Na przykład powłoka Bash używa i do...done if...then...fi. W środowisku programu PowerShell używasz odpowiedników foreach i if (something is true)...{do this}. W usłudze Azure Cloud Shell można przełączać się między środowiskami przy użyciu przycisku Przełącz do programu PowerShell lub Przełącz na powłokę Bash w menu głównym usługi Azure Cloud Shell.

Jeśli wolisz, przejdź bezpośrednio do plików CSV i skryptów używanych w tym artykule w artykule Azure-samples/azure-cli-samples.

Ustawianie zmiennych

Rozpocznij od utworzenia zmiennych wymaganych dla skryptu. Następujące trzy zmienne wymagają rzeczywistych wartości dla danego środowiska:

  • subscriptionID: jest to identyfikator subskrypcji platformy Azure.
  • csvFileLocation: jest to lokalizacja i nazwa pliku wejściowego CSV.
  • logFileLocation: jest to lokalizacja i nazwa pliku, za pomocą których skrypt utworzy plik dziennika. Nie musisz tworzyć ani przekazywać tego pliku.

Zmienne z prefiksem msdocs- można zastąpić wybranym prefiksem. Wszystkie puste zmienne ("") używają wartości z pliku wejściowego CSV. Te puste zmienne są symbolami zastępczymi wymaganymi przez skrypt.

# 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

Weryfikowanie wartości plików CSV

Przed rozpoczęciem testowania skryptu tworzenia upewnij się, że plik CSV jest poprawnie sformatowany, a zmienne będą przypisywane poprawne wartości. Ten skrypt używa if.. Instrukcja THEN umożliwia jednoczesne przyjrzenie się jednemu scenariuszowi/wierszowi 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)

Przy użyciu pliku CSV podanego w tym artykule dane wyjściowe weryfikacji są następujące: ( 00000001 Losowy identyfikator będzie inny dla każdego testu).

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

Weryfikowanie logiki skryptu

Jeśli masz pewność co do możliwości tworzenia skryptów, możesz pominąć ten krok. Jednak ponieważ ten skrypt jest przeznaczony do tworzenia zasobów platformy Azure na dużą skalę, pętla przez skrypt za pomocą echo instrukcji lub write-host może zaoszczędzić czas i nieoczekiwane rozliczane zasoby platformy Azure.

Istnieje kilka sposobów iteracji pliku CSV przy użyciu powłoki Bash. W tym przykładzie użyto polecenia IFS z elementem 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

Przy użyciu pliku CSV podanego w tym artykule dane wyjściowe weryfikacji są następujące: ( 00000001, 2, 3 Losowe identyfikatory będą inne dla każdego testu, ale każdy zasób w ramach każdego resourceNo z nich powinien współdzielić ten sam losowy identyfikator).

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>

Tworzenie zasobów platformy Azure

Blok zmiennej został utworzony, zweryfikowano wartości CSV i ukończono przebieg testu za pomocą echo polecenia lub write-host. Wykonaj czwartą i ostatnią część skryptu, aby utworzyć zasoby platformy Azure zgodnie z definicją w pliku wejściowym 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

W danych wyjściowych konsoli brakuje ostatniego wiersza w pliku CSV? Może to być spowodowane brakiem znaku kontynuacji wiersza po ostatnim wierszu. Dodaj pusty wiersz na końcu pliku CSV, aby rozwiązać ten problem.

Dane wyjściowe konsoli przed odczytem pliku dziennika:

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

Zawartość pliku dziennika powinna wyglądać mniej więcej tak:

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
  }

Rozwiązywanie problemów

W powłoce Bash krok "Tworzenie zasobów platformy Azure" zostanie zatrzymany po kroku 1

W systemie Ubuntu 22.04.3 LTS i Debian w wersji 12 (bookworm) logika skryptu Validate działa zgodnie z oczekiwaniami, zwracając wyniki dla wszystkich trzech zasobów. Jednak tworzenie zasobów platformy Azure zatrzymuje się po pierwszym zasobie. Możliwą przyczyną tego problemu jest to, że utworzenie sieci wirtualnej w kroku 1 trwa kilka sekund. Zarówno system Ubuntu, jak i Debian przejść do drugiego zasobu bez oczekiwania na ukończenie sieci wirtualnej. Więcej informacji na ten temat można przeczytać w temacie wait't wait for the processes in the while loop to finish or Waiting for any process to finish in bash script (Oczekiwanie na zakończenie dowolnego procesu w skrywcie powłoki bash).

Skrypt powłoki Bash ignoruje instrukcję IF

W powłoce Bash jest uwzględniana wielkość liter. Wyraz true nie jest równy TRUE. Jest również greater than parametrem -gt, a nie >, a equals ==nie =. Upewnij się, że nie masz błędu typograficznego ani spacji wiodących/końcowych w wartościach kolumn CSV.

Wartości zmiennych nie zmieniają się przy użyciu każdej pętli

Jest to często spowodowane dodatkowymi spacjami w pliku CSV. Wiersz w pliku CSV będzie wyglądać mniej więcej tak: column1,column2,column3 lub column1,,column3, ale według zwyczaju można łatwo utworzyć plik testowy zawierający spację po każdym przecince, takim jak column1, column2, column3. Jeśli w woluminie CSV znajduje się spacja prowadząca lub końcowa, wartość kolumny jest rzeczywiście <space>columnValuewartością . Logika if [ "$columnName" = "columnValue" ] skryptu zwraca wartość "false". Usuń wszystkie spacje wiodące i końcowe w wierszach csv, aby rozwiązać ten problem.

Nieprawidłowa notacja CIDR

Podczas przekazywania nieprawidłowego prefiksu adresu do az network vnet createelementu zostanie wyświetlony błąd InvalidCIDRNotation. Może to być trudne, gdy wizualnie prefiks adresu wygląda poprawnie po powrocie w instrukcji echo . Aby rozwiązać problem z rzeczywistą wartością odczytywaną z pliku CSV, spróbuj wykonać ten skrypt:

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)

Jeśli wyniki wyglądają tak, xzy10.0.0.0 a nie oczekiwano abc10.0.0.0/24xyz, może istnieć ukryty znak lub dodatkowy przecinek się w pliku CSV. Dodaj kolumnę testową z tą samą wartością prefiksu, zmień kolejność kolumn CSV i skopiuj/wklej zawartość CSV w/w prostym edytorze Notatnika. Pisząc ten artykuł, zmiana kolejności kolumn CSV w końcu naprawiła błąd.

Argumenty są oczekiwane lub wymagane

Ten błąd występuje, gdy nie podano wymaganego parametru lub występuje błąd typograficzne, który powoduje niepoprawne przeanalizowanie polecenia odniesienia przez interfejs wiersza polecenia platformy Azure. Podczas pracy ze skryptem występuje również ten błąd, gdy spełniony jest jeden z następujących warunków:

  • Brak lub niepoprawny znak kontynuacji wiersza.
  • Po prawej stronie znaku kontynuacji linii znajdują się spacje końcowe.
  • Nazwa zmiennej zawiera znak specjalny, taki jak kreska (-).

InvalidTemplateDeployment

Podczas próby utworzenia zasobu platformy Azure w lokalizacji, która nie oferuje tego zasobu, zostanie wyświetlony błąd podobny do następującego: "Następujące jednostki SKU nie powiodły się w przypadku ograniczeń pojemności: Standard_DS1_v2" jest obecnie niedostępna w lokalizacji "westus".

Oto pełny przykład błędu:

{"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."}]}}

Aby naprawić błąd, zmień lokalizację lub wybierz inną wartość parametru oferowaną dla żądanej lokalizacji.

Zobacz też