Tworzenie skryptu interfejsu wiersza polecenia platformy Azure dla powłoki Bash

Ukończone

Prawie każde zadanie, które można wykonać w witrynie Azure Portal, można wykonać za pomocą poleceń referencyjnych interfejsu wiersza polecenia platformy Azure . Korzystanie z witryny Azure Portal w celu zapoznania się z platformą Azure to doskonałe miejsce do rozpoczęcia. Zalecamy jednak używanie interfejsu wiersza polecenia platformy Azure lub programu Azure PowerShell do zarządzania zasobami platformy Azure na dużą skalę.

Rozważmy scenariusz, w którym zarządzasz platformą Azure dla światowej korporacji. Codziennie otrzymujesz wiele żądań dla nowych grup zasobów, Azure Logic Apps, kont storage, potoków Azure Data Factory i baz danych Azure SQL. Wszystkie wasze zespoły pracują w środowiskach programistycznych, testowych i produkcyjnych. Dla każdego żądania należy utworzyć trzy podobne zasoby platformy Azure zgodne ze standardami nazewnictwa i zasadami zabezpieczeń firmy. Nadszedł czas, aby użyć skryptów interfejsu wiersza polecenia platformy Azure !

Omówienie skryptów interfejsu wiersza polecenia platformy Azure

Skrypty interfejsu wiersza polecenia platformy Azure umożliwiają automatyzację powtarzających się zadań i wdrażania infrastruktury na dużą skalę. Skrypty zapewniają spójność, zmniejszają liczbę błędów ludzkich i włączają praktyki infrastruktury jako kodu (IaC). Niezależnie od tego, czy zarządzasz środowiskami deweloperskimi, testowymi czy produkcyjnymi, skrypty interfejsu wiersza polecenia platformy Azure usprawniają zarządzanie i przydzielanie zasobów.

Podstawy struktury skryptu

Dobrze ustrukturyzowany skrypt interfejsu wiersza polecenia platformy Azure zwykle obejmuje:

  • Shebang (#!/bin/bash lub #!/usr/bin/env bash): Określa interpreter do wykonywania skryptu.
  • Zmienna: Przechowuj wartość wielokrotnego użytku, taką jak nazwa zasobu, lokalizacja i konfiguracja jednostki SKU.
  • Komentarze: Logika i parametry skryptu dokumentu służące do konserwacji.
  • Obsługa błędów: Zaimplementuj kontrole, aby bezpiecznie obsługiwać błędy.
  • Pętle i instrukcje warunkowe: Tworzenie wielu zasobów lub zastosowanie logiki na podstawie warunków.
  • Formatowanie danych wyjściowych: Wyświetlanie wyników w formatach czytelnych na potrzeby walidacji.

Tworzenie skryptu wdrażania zasobów

Przyjrzyjmy się praktycznemu skryptowi Bash, który tworzy wiele kont Azure Storage w spójny, powtarzalny sposób.

#!/bin/bash

# Script: Create multiple Azure storage accounts
# Description: Automates storage account creation with consistent naming and configuration

# Define deployment parameters
resourceGroupName="rg-storage-prod-eastus"
saCount=3
saLocation="eastus"
saNamePrefix="stprod"
saSku="Standard_GRS"
saKind="StorageV2"

# Validate Azure CLI is installed and authenticated
if ! command -v az &> /dev/null; then
    echo "Error: Azure CLI is not installed. Please install Azure CLI first."
    exit 1
fi

if ! az account show &> /dev/null; then
    echo "Error: Not authenticated to Azure. Please run 'az login' first."
    exit 1
fi

echo "Starting storage account deployment..."
echo "Resource Group: $resourceGroupName"
echo "Location: $saLocation"
echo "Count: $saCount"
echo ""

# Create resource group if it doesn't exist
if ! az group show --name $resourceGroupName &> /dev/null; then
    echo "Creating resource group $resourceGroupName..."
    az group create --name $resourceGroupName --location $saLocation
else
    echo "Resource group $resourceGroupName already exists."
fi

# Loop to create multiple storage accounts
for i in $(seq 1 $saCount)
do
    # Generate unique identifier using timestamp and random number
    timestamp=$(date +%s)
    let "randomIdentifier=$RANDOM"
    saName="${saNamePrefix}${timestamp}${randomIdentifier}"

    # Ensure name is lowercase and within 24 character limit
    saName=$(echo $saName | tr '[:upper:]' '[:lower:]' | cut -c1-24)

    echo "Creating storage account $saName..."

    # Create storage account with error handling
    if az storage account create \
        --name $saName \
        --resource-group $resourceGroupName \
        --location $saLocation \
        --sku $saSku \
        --kind $saKind \
        --tags Environment=Production ManagedBy=AzureCLI \
        --output none; then
        echo "✓ Successfully created storage account $saName"
    else
        echo "✗ Failed to create storage account $saName"
    fi
done

echo ""
echo "Deployment complete. Verifying results..."
echo ""

# Verify results with formatted output
az storage account list \
    --resource-group $resourceGroupName \
    --query "[].{Name:name, Location:location, SKU:sku.name, Status:statusOfPrimary}" \
    --output table

Podział skryptów

Przyjrzyjmy się kluczowym składnikom:

Weryfikacja uwierzytelniania:

if ! az account show &> /dev/null; then
    echo "Error: Not authenticated to Azure. Please run 'az login' first."
    exit 1
fi

Gwarantuje, że użytkownik jest uwierzytelniany przed wykonaniem operacji zasobów, zapobiegając awariom skryptu.

Tworzenie grupy zasobów z sprawdzeniem istnienia:

if ! az group show --name $resourceGroupName &> /dev/null; then
    az group create --name $resourceGroupName --location $saLocation
fi

Tworzy grupę zasobów tylko wtedy, gdy jeszcze nie istnieje, czyniąc skrypt idempotentnym.

Unikatowe generowanie nazw:

timestamp=$(date +%s)
let "randomIdentifier=$RANDOM"
saName="${saNamePrefix}${timestamp}${randomIdentifier}"
saName=$(echo $saName | tr '[:upper:]' '[:lower:]' | cut -c1-24)

Łączy znacznik czasu i liczbę losową w celu wygenerowania unikatowych nazw kont magazynu, konwertując je na małe litery i ograniczając do 24 znaków zgodnie z wymaganiami dotyczącymi nazewnictwa platformy Azure.

Obsługa błędów:

if az storage account create ...; then
    echo "✓ Successfully created storage account $saName"
else
    echo "✗ Failed to create storage account $saName"
fi

Weryfikuje każde tworzenie konta magazynowego i dostarcza jasne informacje o powodzeniu/niepowodzeniu.

Tworzenie sparametryzowanego skryptu

Skrypty produkcyjne powinny akceptować parametry w celu zapewnienia elastyczności w różnych środowiskach:

#!/bin/bash

# Script: create-storage-accounts.sh
# Usage: ./create-storage-accounts.sh <resource-group> <location> <count> <environment>

# Accept command-line parameters
resourceGroupName=$1
saLocation=$2
saCount=$3
environment=$4

# Validate parameters
if [ -z "$resourceGroupName" ] || [ -z "$saLocation" ] || [ -z "$saCount" ] || [ -z "$environment" ]; then
    echo "Usage: $0 <resource-group> <location> <count> <environment>"
    echo "Example: $0 rg-storage-dev eastus 3 Development"
    exit 1
fi

# Validate count is a number
if ! [[ "$saCount" =~ ^[0-9]+$ ]]; then
    echo "Error: Count must be a number"
    exit 1
fi

echo "Parameters received:"
echo "  Resource Group: $resourceGroupName"
echo "  Location: $saLocation"
echo "  Count: $saCount"
echo "  Environment: $environment"
echo ""

# Set environment-specific configurations
case $environment in
    Development)
        saSku="Standard_LRS"
        saKind="StorageV2"
        ;;
    Staging)
        saSku="Standard_GRS"
        saKind="StorageV2"
        ;;
    Production)
        saSku="Standard_RAGRS"
        saKind="StorageV2"
        ;;
    *)
        echo "Error: Environment must be Development, Staging, or Production"
        exit 1
        ;;
esac

echo "Using SKU: $saSku for $environment environment"
echo ""

# Continue with resource creation...

Wykonywanie sparametryzowanego skryptu

# Make script executable
chmod +x create-storage-accounts.sh

# Execute with parameters
./create-storage-accounts.sh rg-storage-dev eastus 3 Development

Tworzenie skryptu opartego na konfiguracji

W przypadku złożonych wdrożeń użyj zewnętrznych plików konfiguracji:

config.json:

{
  "resourceGroup": {
    "name": "rg-app-prod-eastus",
    "location": "eastus"
  },
  "storageAccounts": [
    {
      "namePrefix": "stappdata",
      "sku": "Standard_RAGRS",
      "kind": "StorageV2",
      "count": 2
    },
    {
      "namePrefix": "stappbackup",
      "sku": "Standard_GRS",
      "kind": "StorageV2",
      "count": 1
    }
  ],
  "tags": {
    "Environment": "Production",
    "CostCenter": "Engineering",
    "ManagedBy": "AzureCLI"
  }
}

deploy-from-config.sh:

#!/bin/bash

# Load configuration file
configFile="config.json"

if [ ! -f "$configFile" ]; then
    echo "Error: Configuration file $configFile not found"
    exit 1
fi

# Parse configuration using jq (JSON processor)
resourceGroupName=$(jq -r '.resourceGroup.name' $configFile)
resourceGroupLocation=$(jq -r '.resourceGroup.location' $configFile)
tagsJson=$(jq -r '.tags | to_entries | map("\(.key)=\(.value)") | join(" ")' $configFile)

echo "Deploying resources from configuration file..."
echo "Resource Group: $resourceGroupName"
echo "Location: $resourceGroupLocation"
echo ""

# Create resource group
az group create --name $resourceGroupName --location $resourceGroupLocation

# Read storage account configurations
storageConfigCount=$(jq '.storageAccounts | length' $configFile)

for i in $(seq 0 $(($storageConfigCount - 1)))
do
    namePrefix=$(jq -r ".storageAccounts[$i].namePrefix" $configFile)
    sku=$(jq -r ".storageAccounts[$i].sku" $configFile)
    kind=$(jq -r ".storageAccounts[$i].kind" $configFile)
    count=$(jq -r ".storageAccounts[$i].count" $configFile)

    echo "Creating $count storage account(s) with prefix: $namePrefix"

    for j in $(seq 1 $count)
    do
        timestamp=$(date +%s)
        saName="${namePrefix}${timestamp}${RANDOM}"
        saName=$(echo $saName | tr '[:upper:]' '[:lower:]' | cut -c1-24)

        az storage account create \
            --name $saName \
            --resource-group $resourceGroupName \
            --location $resourceGroupLocation \
            --sku $sku \
            --kind $kind \
            --tags $tagsJson \
            --output none

        echo "  ✓ Created: $saName"
    done
done

echo ""
echo "Deployment complete."

Korzyści oparte na konfiguracji

  • Separacja zagadnień: Konfiguracja jest oddzielona od logiki wdrażania.
  • Promocja środowiska: Ten sam skrypt z różnymi plikami konfiguracyjnymi dla środowisk deweloperskiego, testowego, produkcyjnego.
  • Kontrola wersji: Śledzenie zmian konfiguracji wraz z kodem.
  • Walidacja: Zweryfikuj strukturę konfiguracji przed wdrożeniem.

Usuwanie zasobów platformy Azure za pomocą skryptów

Podczas tworzenia i testowania skryptów pamiętaj, aby usunąć zasoby testowe, aby uniknąć niepotrzebnych kosztów. Skrypty interfejsu wiersza polecenia platformy Azure umożliwiają bezpieczne, spójne czyszczenie zasobów.

Usuwanie kont magazynu według daty utworzenia

Usuń wszystkie konta magazynu utworzone w określonym dniu i godzinie lub po określonej dacie:

#!/bin/bash

# Define cleanup parameters
cutoffDate="2025-10-08T00:00:00.000000+00:00"
resourceGroup="rg-storage-dev-eastus"

echo "Finding storage accounts created on or after $cutoffDate..."

# Get list of storage accounts matching criteria
saList=$(az storage account list \
    --resource-group $resourceGroup \
    --query "[?creationTime >='$cutoffDate'].{Name:name, Created:creationTime}" \
    --output table)

echo "$saList"
echo ""

# Confirm deletion
read -p "Delete these storage accounts? (yes/no): " confirm

if [ "$confirm" == "yes" ]; then
    for saId in $(az storage account list \
        --resource-group $resourceGroup \
        --query "[?creationTime >='$cutoffDate'].id" \
        --output tsv); do
        echo "Deleting storage account: $saId"
        az storage account delete --ids $saId --yes
    done
    echo "Cleanup complete."
else
    echo "Deletion cancelled."
fi

Usuwanie grup zasobów przy użyciu rejestrowania

Usuń grupy zasobów pasujące do wzorca nazewnictwa z kompleksowym rejestrowaniem:

#!/bin/bash

# Define cleanup parameters
namePattern="rg-dev-*"
logFileLocation="cleanup-$(date +%Y%m%d-%H%M%S).log"

echo "Resource Group Cleanup" > $logFileLocation
echo "Started: $(date)" >> $logFileLocation
echo "Pattern: $namePattern" >> $logFileLocation
echo "----------------------------------------" >> $logFileLocation

# Find matching resource groups
echo "Finding resource groups matching pattern: $namePattern"
matchingGroups=$(az group list \
    --query "[?starts_with(name, 'rg-dev-')].name" \
    --output tsv)

if [ -z "$matchingGroups" ]; then
    echo "No resource groups found matching pattern: $namePattern"
    echo "No resource groups found" >> $logFileLocation
    exit 0
fi

# Display matches
echo "Found resource groups:"
echo "$matchingGroups"
echo ""

# Log matches
echo "Resource groups found:" >> $logFileLocation
echo "$matchingGroups" >> $logFileLocation
echo "" >> $logFileLocation

# Confirm deletion
read -p "Delete these resource groups? (yes/no): " confirm

if [ "$confirm" == "yes" ]; then
    echo "Starting deletion..." >> $logFileLocation

    for rgName in $matchingGroups
    do
        echo "Deleting resource group: $rgName"
        echo "$(date): Deleting $rgName" >> $logFileLocation

        # Delete with --no-wait for background execution
        if az group delete --name $rgName --yes --no-wait; then
            echo "  ✓ Deletion initiated for $rgName"
            echo "$(date): ✓ Deletion initiated for $rgName" >> $logFileLocation
        else
            echo "  ✗ Failed to initiate deletion for $rgName"
            echo "$(date): ✗ Failed to delete $rgName" >> $logFileLocation
        fi
    done

    echo ""
    echo "Deletion operations initiated. Resources will be removed in the background."
    echo "Check deletion status with: az group list --query \"[?starts_with(name, 'rg-dev-')].name\""

    echo "" >> $logFileLocation
    echo "Completed: $(date)" >> $logFileLocation
    echo "Log saved to: $logFileLocation"

    # Display log
    echo ""
    echo "=== Cleanup Log ==="
    cat $logFileLocation
else
    echo "Deletion cancelled by user" >> $logFileLocation
    echo "Deletion cancelled."
fi

Praktyki bezpiecznego usuwania

Przed usunięciem zaimplementuj kontrole bezpieczeństwa:

#!/bin/bash

# Delete resources safely with multiple confirmations
resourceGroup="rg-storage-test-eastus"

# Check if resource group exists
if ! az group show --name $resourceGroup &> /dev/null; then
    echo "Error: Resource group '$resourceGroup' not found"
    exit 1
fi

# Display resources that will be deleted
echo "Resources in resource group '$resourceGroup':"
az resource list --resource-group $resourceGroup \
    --query "[].{Name:name, Type:type, Location:location}" \
    --output table

echo ""
echo "⚠️  WARNING: This will delete ALL resources in '$resourceGroup'"
echo ""

# First confirmation
read -p "Are you sure you want to delete '$resourceGroup'? (yes/no): " confirm1

if [ "$confirm1" != "yes" ]; then
    echo "Deletion cancelled."
    exit 0
fi

# Second confirmation with exact name
read -p "Type the resource group name to confirm: " confirm2

if [ "$confirm2" != "$resourceGroup" ]; then
    echo "Resource group name does not match. Deletion cancelled."
    exit 1
fi

# Final countdown
echo "Deleting in 5 seconds. Press Ctrl+C to cancel."
sleep 5

echo "Deleting resource group '$resourceGroup'..."
az group delete --name $resourceGroup --yes

echo "Resource group deleted successfully."

Ostrzeżenie

Zawsze weryfikuj zasoby przed usunięciem. Usunięcie grupy zasobów powoduje trwałe usunięcie wszystkich zasobów w niej. Tej akcji nie można cofnąć.

Najlepsze rozwiązania dotyczące skryptów produkcyjnych

Skrypty interfejsu wiersza polecenia platformy Azure gotowe do produkcji wymagają starannego planowania i implementacji. Skrypty przedstawione w tej lekcji przedstawiają podstawowe pojęcia, ale środowiska produkcyjne wymagają dodatkowych zagadnień.

Podstawowe składniki skryptu produkcyjnego

Niezawodny skrypt interfejsu wiersza polecenia platformy Azure dla środowisk produkcyjnych powinien zawierać następujące elementy:

1. Uwierzytelnianie i autoryzacja:

#!/bin/bash

# Authenticate with service principal (for automation)
if [ -n "$AZURE_CLIENT_ID" ] && [ -n "$AZURE_CLIENT_SECRET" ] && [ -n "$AZURE_TENANT_ID" ]; then
    echo "Authenticating with service principal..."
    az login --service-principal \
        --username $AZURE_CLIENT_ID \
        --password $AZURE_CLIENT_SECRET \
        --tenant $AZURE_TENANT_ID
else
    echo "Error: Service principal credentials not found"
    exit 1
fi

# Set subscription
az account set --subscription $AZURE_SUBSCRIPTION_ID

# Verify authentication
if ! az account show &> /dev/null; then
    echo "Error: Authentication failed"
    exit 1
fi

2. Kompleksowa obsługa błędów:

#!/bin/bash

# Exit immediately if command fails
set -e

# Trap errors and perform cleanup
trap 'cleanup_on_error' ERR

cleanup_on_error() {
    echo "Error occurred on line $1"
    echo "Performing cleanup..."
    # Add cleanup logic here
    exit 1
}

# Enable error trapping with line numbers
trap 'cleanup_on_error $LINENO' ERR

3. Kontrole idempotentności:

#!/bin/bash

# Check if resource group exists before creation
create_resource_group() {
    local rgName=$1
    local location=$2

    if az group show --name $rgName &> /dev/null; then
        echo "Resource group $rgName already exists. Skipping creation."
    else
        echo "Creating resource group $rgName..."
        az group create --name $rgName --location $location
    fi
}

# Check if storage account exists
create_storage_account() {
    local saName=$1
    local rgName=$2

    if az storage account show --name $saName --resource-group $rgName &> /dev/null; then
        echo "Storage account $saName already exists. Skipping creation."
        return 0
    else
        echo "Creating storage account $saName..."
        az storage account create --name $saName --resource-group $rgName --location eastus
    fi
}

4. Rejestrowanie strukturalne:

#!/bin/bash

# Define log file with timestamp
logFile="deployment-$(date +%Y%m%d-%H%M%S).log"
errorLog="errors-$(date +%Y%m%d-%H%M%S).log"

# Logging function
log() {
    local level=$1
    shift
    local message="$@"
    local timestamp=$(date "+%Y-%m-%d %H:%M:%S")

    echo "[$timestamp] [$level] $message" | tee -a $logFile

    if [ "$level" == "ERROR" ]; then
        echo "[$timestamp] $message" >> $errorLog
    fi
}

# Usage
log "INFO" "Starting deployment..."
log "ERROR" "Failed to create resource"
log "SUCCESS" "Deployment complete"

5. Weryfikacja konfiguracji:

#!/bin/bash

# Validate required configuration
validate_config() {
    local errors=0

    if [ -z "$RESOURCE_GROUP" ]; then
        echo "Error: RESOURCE_GROUP not defined"
        ((errors++))
    fi

    if [ -z "$LOCATION" ]; then
        echo "Error: LOCATION not defined"
        ((errors++))
    fi

    # Validate location exists
    if ! az account list-locations --query "[?name=='$LOCATION']" | grep -q "$LOCATION"; then
        echo "Error: Invalid location: $LOCATION"
        ((errors++))
    fi

    if [ $errors -gt 0 ]; then
        echo "Configuration validation failed with $errors error(s)"
        exit 1
    fi

    echo "Configuration validation passed"
}

6. Strategia tagowania:

#!/bin/bash

# Define standard tags
environment=$1  # Development, Staging, Production
costCenter=$2
owner=$3

# Create tags string
tags="Environment=$environment CostCenter=$costCenter Owner=$owner \
      CreatedBy=AzureCLI CreatedDate=$(date +%Y-%m-%d) \
      ManagedBy=Infrastructure-Team Project=WebApp"

# Apply tags to resources
az group create \
    --name $resourceGroup \
    --location $location \
    --tags $tags

az storage account create \
    --name $saName \
    --resource-group $resourceGroup \
    --location $location \
    --tags $tags

7. Możliwość wycofywania:

#!/bin/bash

# Track created resources for rollback
createdResources=()

create_with_tracking() {
    local resourceType=$1
    local resourceName=$2

    # Attempt resource creation
    if create_resource "$resourceType" "$resourceName"; then
        createdResources+=("$resourceType:$resourceName")
        echo "✓ Created: $resourceType - $resourceName"
        return 0
    else
        echo "✗ Failed: $resourceType - $resourceName"
        return 1
    fi
}

rollback() {
    echo "Rolling back created resources..."

    for resource in "${createdResources[@]}"; do
        IFS=':' read -r type name <<< "$resource"
        echo "Deleting $type: $name"
        delete_resource "$type" "$name"
    done

    echo "Rollback complete"
}

# Use trap to rollback on error
trap rollback ERR

Struktura organizacji skryptu

Organizowanie skryptów w moduły logiczne:

azure-infrastructure/
├── config/
│   ├── dev.json
│   ├── staging.json
│   └── prod.json
├── scripts/
│   ├── deploy-infrastructure.sh
│   ├── deploy-storage.sh
│   └── cleanup.sh
├── lib/
│   ├── common-functions.sh
│   ├── logging.sh
│   └── validation.sh
├── logs/
└── README.md

Biblioteka funkcji wielokrotnego użytku

common-functions.sh:

#!/bin/bash

# Load this file in other scripts: source ./lib/common-functions.sh

# Check if Azure CLI is installed
check_azure_cli() {
    if ! command -v az &> /dev/null; then
        echo "Error: Azure CLI not installed"
        exit 1
    fi
}

# Wait for resource to be ready
wait_for_resource() {
    local resourceId=$1
    local maxAttempts=30
    local attempt=1

    echo "Waiting for resource to be ready..."

    while [ $attempt -le $maxAttempts ]; do
        if az resource show --ids $resourceId &> /dev/null; then
            echo "Resource is ready"
            return 0
        fi

        echo "Attempt $attempt/$maxAttempts - waiting..."
        sleep 10
        ((attempt++))
    done

    echo "Timeout waiting for resource"
    return 1
}

# Generate unique name
generate_unique_name() {
    local prefix=$1
    local timestamp=$(date +%s)
    local random=$RANDOM
    echo "${prefix}${timestamp}${random}" | tr '[:upper:]' '[:lower:]' | cut -c1-24
}

Bezpieczne testowanie skryptów

Skrypty testowe w środowiskach izolowanych:

#!/bin/bash

# Test mode flag
TEST_MODE=${TEST_MODE:-false}

execute_command() {
    local command=$1

    if [ "$TEST_MODE" == "true" ]; then
        echo "[TEST MODE] Would execute: $command"
    else
        echo "Executing: $command"
        eval $command
    fi
}

# Usage
execute_command "az group create --name rg-test --location eastus"

Uruchom w trybie testowym:

TEST_MODE=true ./deploy-infrastructure.sh

Dodatkowe zasoby

Skrypty w tej lekcji przedstawiają możliwości interfejsu wiersza polecenia platformy Azure podczas łączenia zmiennych, pętli, warunkowych i obsługi błędów za pomocą poleceń interfejsu wiersza polecenia platformy Azure . Te wzorce są skalowane od zarządzania kilkoma zasobami do organizowania złożonych wdrożeń infrastruktury przedsiębiorstwa.