Bash용 Azure CLI 스크립트 만들기
Azure Portal에서 완료할 수 있는 거의 모든 작업은 Azure CLI 참조 명령을 사용하여 완료할 수 있습니다. Azure Portal을 사용하여 Azure에 대해 알아보는 것이 좋습니다. 그러나 Azure CLI 또는 Azure PowerShell 을 사용하여 대규모로 Azure 리소스를 관리하는 것이 좋습니다.
전 세계 기업의 Azure 를 관리하는 시나리오를 고려합니다. 새 리소스 그룹, Azure Logic Apps, 스토리지 계정, Azure Data Factory 파이프라인 및 Azure SQL 데이터베이스에 대해 매일 여러 요청을 받습니다. 모든 팀은 개발, 스테이징 및 프로덕션 환경에서 작업합니다. 모든 요청에 대해 회사의 명명 표준 및 보안 정책을 따르는 세 가지 유사한 Azure 리소스 를 만들어야 합니다. Azure CLI 스크립팅을 사용해야 합니다.
Azure CLI 스크립트 이해
Azure CLI 스크립트를 사용하면 반복적인 작업 및 인프라 배포를 대규모로 자동화할 수 있습니다. 스크립트는 일관성을 제공하고, 사용자 오류를 줄이며, IaC(Infrastructure as Code) 사례를 사용하도록 설정합니다. 개발, 스테이징 또는 프로덕션 환경을 관리하는 경우 Azure CLI 스크립팅은 리소스 프로비저닝 및 관리를 간소화합니다.
스크립트 구조 기본 사항
잘 구성된 Azure CLI 스크립트는 일반적으로 다음을 포함합니다.
-
Shebang (
#!/bin/bash또는#!/usr/bin/env bash): 스크립트를 실행하기 위한 인터프리터를 지정합니다. - 변수: 리소스 이름, 위치 및 SKU 구성과 같은 재사용 가능한 값을 저장합니다.
- 코멘트: 유지 관리를 위한 문서 스크립트 논리 및 매개 변수입니다.
- 오류 처리: 오류를 정상적으로 처리하도록 검사를 구현합니다.
- 루프 및 조건부: 여러 리소스를 만들거나 조건에 따라 논리를 적용합니다.
- 출력 서식 지정: 유효성 검사를 위해 결과를 읽을 수 있는 형식으로 표시합니다.
리소스 배포 스크립트 만들기
일관되고 반복 가능한 방식으로 여러 Azure Storage 계정을 만드는 실용적인 Bash 스크립트를 살펴보겠습니다.
#!/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
스크립트 분석
주요 구성 요소를 살펴보겠습니다.
인증 유효성 검사:
if ! az account show &> /dev/null; then
echo "Error: Not authenticated to Azure. Please run 'az login' first."
exit 1
fi
리소스 작업을 실행하기 전에 사용자가 인증되어 스크립트 오류가 발생하지 않도록 합니다.
존재 확인을 사용하여 리소스 그룹 만들기:
if ! az group show --name $resourceGroupName &> /dev/null; then
az group create --name $resourceGroupName --location $saLocation
fi
리소스 그룹이 아직 없는 경우에만 리소스 그룹을 만들어 스크립트가 항등성을 보장하도록 합니다.
고유 이름 생성:
timestamp=$(date +%s)
let "randomIdentifier=$RANDOM"
saName="${saNamePrefix}${timestamp}${randomIdentifier}"
saName=$(echo $saName | tr '[:upper:]' '[:lower:]' | cut -c1-24)
타임스탬프와 난수를 결합하여 고유한 스토리지 계정 이름을 생성하고, 소문자로 변환하고, Azure 명명 요구 사항에 따라 24자로 제한합니다.
오류 처리:
if az storage account create ...; then
echo "✓ Successfully created storage account $saName"
else
echo "✗ Failed to create storage account $saName"
fi
각 스토리지 계정 만들기의 유효성을 검사하고 명확한 성공/실패 피드백을 제공합니다.
매개 변수가 있는 스크립트 만들기
프로덕션 스크립트는 환경 전반에서 유연성을 위해 매개 변수를 허용해야 합니다.
#!/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...
매개 변수가 있는 스크립트 실행
# Make script executable
chmod +x create-storage-accounts.sh
# Execute with parameters
./create-storage-accounts.sh rg-storage-dev eastus 3 Development
구성 기반 스크립트 만들기
복잡한 배포의 경우 외부 구성 파일을 사용합니다.
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."
구성 기반 이점
- 우려 사항 분리: 배포 논리와 별도로 구성합니다.
- 환경 관리: 개발, 스테이징, 프로덕션에 대해 다른 구성 파일을 사용하는 동일한 스크립트입니다.
- 버전 제어: 코드와 함께 구성 변경 내용을 추적합니다.
- 유효성 검사: 배포 전에 구성 구조의 유효성을 검사합니다.
스크립트를 사용하여 Azure 리소스 삭제
스크립트를 만들고 테스트할 때 불필요한 비용을 방지하기 위해 테스트 리소스를 삭제해야 합니다. Azure CLI 스크립팅을 사용하면 안전하고 일관된 리소스 정리가 가능합니다.
만든 날짜별로 스토리지 계정 삭제
특정 날짜 및 시간 이후에 만든 모든 스토리지 계정을 삭제합니다.
#!/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
로깅을 사용하여 리소스 그룹 삭제
포괄적인 로깅을 사용하여 명명 패턴과 일치하는 리소스 그룹을 삭제합니다.
#!/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
안전한 삭제 사례
삭제하기 전에 안전 검사를 구현합니다.
#!/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."
경고
삭제하기 전에 항상 리소스를 확인합니다. 리소스 그룹을 삭제하면 리소스 그룹의 모든 리소스가 영구적으로 제거됩니다. 이 작업은 취소할 수 없습니다.
프로덕션 스크립트에 대한 모범 사례
프로덕션 준비 Azure CLI 스크립트에는 신중한 계획 및 구현이 필요합니다. 이 단원에서 제공하는 스크립트는 기본 개념을 보여 주지만 프로덕션 환경에는 추가 고려 사항이 필요합니다.
필수 프로덕션 스크립트 구성 요소
프로덕션 환경에 대한 강력한 Azure CLI 스크립트는 다음을 포함해야 합니다.
1. 인증 및 권한 부여:
#!/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. 포괄적인 오류 처리:
#!/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. 멱등성 검사:
#!/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. 구조적 로깅:
#!/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. 구성 유효성 검사:
#!/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. 태그 지정 전략:
#!/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. 롤백 기능:
#!/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
스크립트 조직 구조
스크립트를 논리 모듈로 구성합니다.
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
재사용 가능한 함수 라이브러리
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
}
안전하게 스크립트 테스트
격리된 환경에서 스크립트 테스트:
#!/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"
테스트 모드에서 실행:
TEST_MODE=true ./deploy-infrastructure.sh
추가 리소스
- Azure CLI 샘플 리포지토리:github.com/Azure-Samples/azure-cli-samples.
- Azure CLI 스크립팅 가이드:learn.microsoft.com/cli/azure/azure-cli-vm-tutorial.
Bash 스크립팅 모범 사례: www.gnu.org/software/bash/manual/ .
이 단원의 스크립트는 변수, 루프, 조건부 및 오류 처리를 Azure CLI 명령과 결합할 때 Azure CLI 기능을 보여 줍니다. 이러한 패턴은 몇 가지 리소스 관리에서 복잡한 엔터프라이즈 인프라 배포 오케스트레이션에 이르기까지 확장됩니다.