In a previous post, I detailed how to automate the creation of a standard multi-server environment using the IaaS capabilities in Azure. During the last days I had the opportunity of enhancing these scripts a bit. This second part of the post describe the enhancements.
Basically, the original scripts followed these set of steps:
- Defining environment variables
- Create cloud service
- Create storage account
- Create VM-n
Pretty simple uh? Yeah, but the resulting environment presented some issues:
- Are VMs created close enough (same subnet)? Most probably not..
- What if machines are created in the same rack (Fault Domain), and there is a hardware issue? The whole environment is gone!
- What if we have multiple WFEs? We would need to load balance them..
All these issues are resolved with the introduction of some Azure concepts such as: Affinity Groups, Availability Sets, Load Balancing. So I enhanced the scripts with them on mind, and the resulting steps are:
- Defining environment variables
- Create a new Affinity Group (New-AzureAffinityGroup)
- Create storage account (add it to the new Affinity Group)
- Create cloud service (add it to the new Affinity Group)
- For each new load balanced VM:
- Create the VM,
- Add it to the cloud service
- Add it to the same availability set
- Create and attach disks as necessary
- Configure endpoints (firewall)
- Configure load balancer and probe port.
The resulting scripts are:
$ErrorActionPreference = "Stop" # stop on any error
function GetLatestImage($family){
$images = Get-AzureVMImage `
| where { $_.ImageFamily -eq $family } `
| Sort-Object -Descending -Property PublishedDate
$latestImage = $images[0]
return $latestImage
}
$myAzureSubscription = 'Windows Azure MSDN - Visual Studio Ultimate'
# Environment variables are defined here:
# ONLY LOWERCASE LETTERS HERE!!
$EnvironmentName = "azrtest"
$tag = get-date -format 'hhmmss'
# Create Storage Account through the Portal (vmstorageazrtest)
$StorageAccount = "vmstorage$EnvironmentName"
Write-Host $StorageAccount
$AzurePubSettingsFile = "C:\Windows Azure MSDN - Visual Studio Ultimate-12-19-2013-credentials.publishsettings"
# ExtraSmall, Small, Medium, Large, ExtraLarge, A6, A7
$VMSize = "Small"
# Region - East US, West US, East Asia, Southeast Asia, North Europe, West Europe
$Location = "Southeast Asia"
$AdminUserName = "admin2K"
$AdminPwd = "password2K"
$OSFamily = "Windows Server 2008 R2 SP1"
# Server names cannot be more than 15 chars
$WFE_1_Name = 'WFESrv1'+$tag
$WFE_2_Name = 'WFESrv2'+$tag
$APPSRV_1_Name = 'AppSrv1'+$tag
$DBSRV_Name = 'DBSrv'+$tag
$myDataDiskSize = 20 # in GB # User-specified
# This must be unique
$CloudServiceName = "azrtest"+$tag
# Run GetLatestImage.ps1
$Image = GetLatestImage($OSFamily)
$ImageName = $Image.ImageName
# Affinity Groups - groups machines 'closer'
$myAffinityGroupName = $EnvironmentName+'-ag' # User-defined
# Availability Sets - defines resources on different HA Fault Domains
# One Availability Set is created per application tier. Not needed for the DB server
$myAvailabilitySetName_WFE = $EnvironmentName+'wfe-as' # User-defined
$myAvailabilitySetName_APPSRV = $EnvironmentName+'appsrv-as' # User-defined
$myEndpointName = $EnvironmentName+'-ep' # User-defined
$myLoadBalancerName = $EnvironmentName+'-lb' # User-defined
Select-AzureSubscription –Default $myAzureSubscription
# Config subscription
import-azurepublishsettingsfile $AzurePubSettingsFile
# Step 1 - Create the Affinity Group
New-AzureAffinityGroup -Name $myAffinityGroupName -Location $Location
# Step 2 - Create Storage Account
# Create Storage Account through the Portal
# IF NO StorageAccount exists, ONE IS CREATED HERE!
#New-AzureStorageAccount -StorageAccountName $StorageAccount -Location $Location -Label "azrtest"
# Remove-AzureStorageAccount -StorageAccountName $StorageAccount
New-AzureStorageAccount -StorageAccountName $StorageAccount -AffinityGroup $myAffinityGroupName
# Step 3 Create Azure Cloud Service
New-AzureService -ServiceName $CloudServiceName -AffinityGroup $myAffinityGroupName
# Step 4
#Get-AzureStorageAccount | Select Label
Set-AzureSubscription -SubscriptionName $myAzureSubscription -CurrentStorageAccount $StorageAccount
# Step 5
# Create WFE Machine(s)
# Create WFE #1
New-AzureVMConfig -ImageName $ImageName `
-InstanceSize $VMSize `
-Name $WFE_1_Name `
-availabilitysetname $myAvailabilitySetName_WFE `
-DiskLabel "OS" `
| Add-AzureProvisioningConfig -Windows `
-DisableAutomaticUpdates `
-AdminUserName $AdminUserName `
-Password $AdminPwd `
| Add-AzureDataDisk -CreateNew -DiskSizeInGB $myDataDiskSize `
-DiskLabel 'DataDisk0' `
-LUN 0 `
| Add-AzureEndpoint -Name $myEndpointName `
-Protocol tcp `
-LocalPort 80 `
-PublicPort 80 `
-LBSetName $myLoadBalancerName `
-ProbePort 8080 `
-ProbeProtocol tcp `
-ProbeIntervalInSeconds 15 `
| New-AzureVM -ServiceName $CloudServiceName
# Create WFE #2
New-AzureVMConfig -ImageName $ImageName `
-InstanceSize $VMSize `
-Name $WFE_2_Name `
-availabilitysetname $myAvailabilitySetName_WFE `
-DiskLabel "OS" `
| Add-AzureProvisioningConfig -Windows `
-DisableAutomaticUpdates `
-AdminUserName $AdminUserName `
-Password $AdminPwd `
| Add-AzureDataDisk -CreateNew -DiskSizeInGB $myDataDiskSize `
-DiskLabel 'DataDisk0' `
-LUN 0 `
| Add-AzureEndpoint -Name $myEndpointName `
-Protocol tcp `
-LocalPort 80 `
-PublicPort 80 `
-LBSetName $myLoadBalancerName `
-ProbePort 8080 `
-ProbeProtocol tcp `
-ProbeIntervalInSeconds 15 `
| New-AzureVM -ServiceName $CloudServiceName
# Create AppServer
New-AzureVMConfig -ImageName $ImageName `
-InstanceSize $VMSize `
-Name $APPSRV_1_Name `
-availabilitysetname $myAvailabilitySetName_APPSRV `
-DiskLabel "OS" `
| Add-AzureProvisioningConfig -Windows `
-DisableAutomaticUpdates `
-AdminUserName $AdminUserName `
-Password $AdminPwd `
| Add-AzureDataDisk -CreateNew -DiskSizeInGB $myDataDiskSize `
-DiskLabel 'DataDisk0' `
-LUN 0 `
| Add-AzureEndpoint -Name $myEndpointName `
-Protocol tcp `
-LocalPort 80 `
-PublicPort 80 `
-LBSetName $myLoadBalancerName `
-ProbePort 8080 `
-ProbeProtocol tcp `
-ProbeIntervalInSeconds 15 `
| New-AzureVM -ServiceName $CloudServiceName
# Create the DB Server
# We do not need to load balance the DB server...
# It would be better to use a SQL Server Image here..
New-AzureVMConfig -ImageName $ImageName `
-InstanceSize $VMSize `
-Name $DBSRV_Name `
-DiskLabel "OS" `
| Add-AzureProvisioningConfig -Windows `
-DisableAutomaticUpdates `
-AdminUserName $AdminUserName `
-Password $AdminPwd `
| Add-AzureDataDisk -CreateNew -DiskSizeInGB $myDataDiskSize `
-DiskLabel 'DataDisk0' `
-LUN 0 `
| Add-AzureDataDisk -CreateNew -DiskSizeInGB $myDataDiskSize `
-DiskLabel 'DataDisk1' `
-LUN 1 `
| New-AzureVM -ServiceName $CloudServiceName
Enjoy!
