Thursday, October 1, 2020

Azure: Create an availability set with two VMs with PowerShell

If you have two or more virtual machines in Azure running in a pair or a cluster (for example domain controllers), you want to make sure that the proper redundancy is in place. Both in regards to separating VMs between datacenters and making sure that during maintenance that MS will not reboot your VMs at the same time. This can be done by creating an availability set which places VMs into availability zones.

An availability zone is the combination of a fault domain (which is a separate physical datacenter within a given region such as West Europe) and an update domain (the underlying hardware 'group', likely the hypervisor. This is to avoid VMs freezing or being rebooted at the same time during a Azure update which can happen on rare occasions according to MS).

The order in which you create the availability set is the following:
  • First you create the availability set
  • Then you create the individual VMs - and the important part is that the availability set has to be specified/set during VM creation using a parameter (AvailabilitySetName). If the VM has already been created without this parameter, then it cannot be added to the availability set later
If you are creating the VMs in PowerShell from scratch an not using the "New-AzVMConfig" cmdlet to specify VM settings in your script, then you can follow this MS guide. However, if you're using "New-AzVMConfig" then it has to be done slightly differently.

Create availability set

# Variables

$ResourceGroupName = "myRG"
$LocationName = "westeurope"
$AvailSetName = "AvailabilitySetAD01"

New-AzAvailabilitySet `
   -Location $LocationName `
   -Name $AvailSetName `
   -ResourceGroupName $ResourceGroupName `
   -Sku aligned `
   -PlatformFaultDomainCount 2 `
   -PlatformUpdateDomainCount 2

This creates the availability set with two fault domains and two update domains. In West Europe you can have up to three fault domains.

To create the VMs, make sure that the following lines are set in the script (copy/paste the snippet to get all the code):

$AvailSetName = "AvailabilitySetAD01"
# Get the availability set for domain controllers
$AvailSet = Get-AzAvailabilitySet -ResourceGroupName $ResourceGroupName -AvailabilitySetName $AvailSetName
# Create new VM config object and add it to the availability set
$VirtualMachine = New-AzVMConfig -VMName $VMName -VMSize $VMSize -AvailabilitySetID $AvailSet.Id

An example of a full VM script including the above three lines can be seen below. If using this in its entirety, make sure that the resource groups, key vault, and storage group are created in advance (or not use the specific parts about key vault and boot diagnostics).


# Update these variables:
# Update to correct RG name
$ResourceGroupName = "ad-RG"
$Vnetrgname = "vnet-RG"
$rgLogmon = "logmon-RG"
$secrgname  = "sec-RG"

$ComputerName = "myServer01" # Change this!
$VMName = "myServer01" # Change this!
$VMSize = "Standard_B2s"
$Vnetname = "MYvnet"
$SubnetName = "MyZone01"
$Disksize = "128"
$OSDiskName = $($VMName) + '-disk01'
$Publisher = "MicrosoftWindowsServer"
$Offer = "WindowsServer"
$Sku = "2019-Datacenter"
$DiskType = "StandardSSD_LRS"
$PrivateIP = "192.168.1.10" # Change this!
$stgaccountname = "myStorageAccount"
$kvname = "MyKV"
$secretname = "localadmpwd"
$AvailSetName = "AvailabilitySetAD01"

# Do not update these variables
$VMLocalAdminUser = "localadmin"
# Will prompt for password during deploy
#$VMLocalAdminSecurePassword = ConvertTo-SecureString  -AsPlainText -Force
# Will get password from text file
#$VMLocalAdminSecurePassword = Get-Content ./vmos-sec-key.txt | ConvertTo-SecureString -AsPlainText -Force
# Will retrieve passwd from key vault
$VMLocalAdminSecurePassword = (Get-AzKeyVaultSecret -vaultName $kvname -name $secretname).SecretValueText | ConvertTo-SecureString -AsPlainText -Force
$LocationName = "westeurope"
$NICName = $($VMName) + '-nic01'
$OSDiskName = $($VMName) + '-OsDisk01'

Write-Host "Creating variables at $(Get-Date)"
# Get existing Vnet
$Vnet = Get-AzVirtualNetwork -Name $Vnetname -ResourceGroupName $Vnetrgname
# Get existing subnet
$Subnet = Get-AzVirtualNetworkSubnetConfig -Name $SubnetName -VirtualNetwork $Vnet
# Set static private IP address
$IPconfig = New-AzNetworkInterfaceIpConfig -Name "IPConfig1" -PrivateIpAddressVersion IPv4 -PrivateIpAddress $PrivateIP -SubnetId $Subnet.Id
# Create a new NIC for the VM and associate the private IP
$NIC = New-AzNetworkInterface -Name $NICName -ResourceGroupName $ResourceGroupName -Location $LocationName -IpConfiguration $IPconfig -Force

# Create credentials object
$Credential = New-Object System.Management.Automation.PSCredential ($VMLocalAdminUser$VMLocalAdminSecurePassword);
# Get the availability set for domain controllers
$AvailSet = Get-AzAvailabilitySet -ResourceGroupName $ResourceGroupName -AvailabilitySetName $AvailSetName
# Create new VM config object and add it to the availability set
$VirtualMachine = New-AzVMConfig -VMName $VMName -VMSize $VMSize -AvailabilitySetID $AvailSet.Id
# Set OS type and OS name and add to VM config object
$VirtualMachine = Set-AzVMOperatingSystem -VM $VirtualMachine -Windows -ComputerName $ComputerName -Credential $Credential -ProvisionVMAgent -EnableAutoUpdate
# Associate the NIC with the VM config object
$VirtualMachine = Add-AzVMNetworkInterface -VM $VirtualMachine -Id $NIC.Id
# Specify OS type for the VM config object
$VirtualMachine = Set-AzVMSourceImage -VM $VirtualMachine -PublisherName $Publisher -Offer $Offer -Skus $Sku -Version latest
# Set disk size in GB
$VirtualMachine = Set-AzVMOSDisk -VM $VirtualMachine -DiskSizeInGB $Disksize -Name $OSDiskName -StorageAccountType $DiskType -CreateOption FromImage
# Set storage account for boot diagnostics (udpate line below)
$VirtualMachine = Set-AzVMBootDiagnostic -VM $VirtualMachine -Enable -ResourceGroupName $rgLogmon -StorageAccountName $stgaccountname

Write-Host "Creating new VM...(this can take 10+ minutes). Starting at $(Get-Date)"
# Create the VM using VM config object 
New-AzVM -ResourceGroupName $ResourceGroupName -Location $LocationName -VM $VirtualMachine -Verbose
Write-Host "VM created"
  
Write-Host
Write-Host "Script done at $(Get-Date)"
Write-Host

When done, it will look like below in the portal:






No comments:

Post a Comment

Note: Only a member of this blog may post a comment.