Cloud Block Store Use Cases for Microsoft Azure - Terraform Edition

Share on:

Previously I explained how to use Terraform to Deploy an Azure VM. Now that Cloud Block Store iS GA in Azure, I can cover how to use Automation for Test/Dev, Disaster Recovery and Migration use cases to move workloads from on-premises to Microsoft Azure!

Overview

When it comes to automating deployments, its great to be able to use the same automation tool across clouds. This blog will focus on how to migrate windows based machines from on-premises to Microsoft Azure. We will utilize Terraform to automate provisioning. Utilizing previous powershell scripts to configure iSCSI will simplify and automate some of these use cases.

Pre-Requisites

Azure CLI

  • This is used to authenticate to Azure to deploy the VM via Terraform.

Hashicorp Terraform

  • This is used to automate the provisioning using a Terraform .TF file.

Microsoft Azure Account

  • This is the infrastructure to run the Azure virtual machines.

Terraform Manifest Configuration

Download the sample manifest from GitHub and update the variables for your environment. This includes the Azure Resource Group, Virtual Network, Subnet and Interface. You will also need to update the Azure VM’s hostname, admin username and password as well as any of fields you wish.

 1provider "azurerm" {
 2    features {}
 3}
 4
 5data "azurerm_resource_group" "resourcegroup" {
 6    name     = "Azure-ResourceGroup"
 7}
 8
 9data "azurerm_virtual_network" "virtualnetwork" {
10    name                = "Azure-VirtualNetwork"
11    resource_group_name = data.azurerm_resource_group.resourcegroup.name
12}
13
14data "azurerm_subnet" "subnet" {
15    name                 = "Azure-Subnet"
16    resource_group_name  = data.azurerm_resource_group.resourcegroup.name
17    virtual_network_name = data.azurerm_virtual_network.virtualnetwork.name
18}
19
20resource "azurerm_network_interface" "networkinterface" {
21    name                = "Azure-NetworkInterface"
22    location            = data.azurerm_resource_group.resourcegroup.location
23    resource_group_name = data.azurerm_resource_group.resourcegroup.name
24    ip_configuration {
25        name = "Azure-IP"
26        subnet_id = data.azurerm_subnet.subnet.id
27        private_ip_address_allocation = "Dynamic"
28    }
29}
30
31resource "azurerm_windows_virtual_machine" "avm" {
32    name = "DS-TERRAFORM"
33    resource_group_name = data.azurerm_resource_group.resourcegroup.name
34    location = data.azurerm_resource_group.resourcegroup.location
35    computer_name = "hostname"
36    admin_username = "terraform"
37    admin_password = "Password1!"
38    size = "Standard_B1s"
39    network_interface_ids = [
40        azurerm_network_interface.networkinterface.id,
41    ]
42    os_disk {
43        caching              = "ReadWrite"
44        storage_account_type = "Standard_LRS"
45    }
46    source_image_reference {
47        publisher = "MicrosoftWindowsServer"
48        offer     = "WindowsServer"
49        sku       = "2019-Datacenter"
50        version   = "latest"
51    }
52}
53
54resource "azurerm_virtual_machine_extension" "customize" {
55    name                 = "customize"
56    virtual_machine_id   = azurerm_windows_virtual_machine.avm.id
57    publisher            = "Microsoft.Compute"
58    type                 = "CustomScriptExtension"
59    type_handler_version = "1.9"
60    protected_settings = <<PROTECTED_SETTINGS
61
62    protected_settings = <<PROTECTED_SETTINGS
63    {
64        "commandToExecute": "powershell.exe -Command \"./chocolatey.ps1; exit 0;\""
65    }
66    PROTECTED_SETTINGS
67
68    settings = <<SETTINGS
69    {
70        "fileUris": [
71            "https://gist.githubusercontent.com/mcasperson/c815ac880df481418ff2e199ea1d0a46/raw/5d4fc583b28ecb27807d8ba90ec5f636387b00a3/chocolatey.ps1"
72        ]
73    }
74    SETTINGS
75}

Update the Terraform Manifest for Your Environment

This file is a standard deployment of an azure virtual machine. The best part about it is that you can utilize Azure customization to run a script once the machine is deployed.

To customize the Azure VM you’ll need to update the customize resource. You can either have it run a local file, or in my case it pulls down the script from a GIST. In an enterprise environment this can be a local server or repository.

 1resource "azurerm_virtual_machine_extension" "customize" {
 2    name                 = "customize"
 3    virtual_machine_id   = azurerm_windows_virtual_machine.avm.id
 4    publisher            = "Microsoft.Compute"
 5    type                 = "CustomScriptExtension"
 6    type_handler_version = "1.9"
 7    protected_settings = <<PROTECTED_SETTINGS
 8    protected_settings = <<PROTECTED_SETTINGS
 9    {
10        "commandToExecute": "powershell.exe -Command \"./ConfigureAzureCBS-DR.ps1; exit 0;\""
11    }
12    PROTECTED_SETTINGS
13
14    settings = <<SETTINGS
15    {
16        "fileUris": [
17            "https://gist.githubusercontent.com/dstamen/e021dcc181c30a9fc5af2d33deafff3f/raw/56b568a9e1183bc5920a344eb51b8a90690fd620/ConfigureAzureCBS-DR.ps1"
18        ]
19    }
20    SETTINGS

Scripted Use Cases

THe following script is a standard PowerShell script that will do the following for a Windows based Azure Virtual Machine.

  • Install PowerShell Pre-Requistives and the PureStoragePowershellSDK
  • Set iSCSI Service to Startup Automatically
  • Set a Custom iSCSI IQN (this allows the host to be pre-configured on CBS)
  • Configure iSCSI to talk to the CBS Array and Connect initiators
  • Login to the flasharray and will overwrite the CBS volume with the latest replicated snapshot. It will then online the disk within windows.
 1#Install Pure Powershell Module
 2Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
 3Install-Module PureStoragePowershellSDK -Confirm:$false -Force
 4
 5#Enable ISCSI
 6Set-Service -Name msiscsi -StartupType Automatic
 7Start-Service -Name msiscsi
 8
 9#Confgure Static Initiator Name
10Set-InitiatorPort -NodeAddress (Get-InitiatorPort).NodeAddress -NewNodeAddress "iqn.1991-05.com.ds-terraform"
11
12#Configure ISCSI to CBS
13$iscsitarget = "172.29.0.6"
14if ((Get-IscsiTargetPortal).TargetPortalAddress -notcontains $iscsitarget){
15    New-IscsiTargetPortal -TargetPortalAddress $iscsitarget
16    Get-IscsiTarget | Connect-IscsiTarget -InitiatorPortalAddress (Get-NetIPAddress |Where-Object {$_.InterfaceAlias -like "Ethernet" -and $_.AddressFamily -like "IPv4"}).IPAddress -IsMultipathEnabled $true -IsPersistent $true -TargetPortalAddress $iscsitarget
17}
18
19#Create Volume from Latest Snap and Online Disk
20$arrayendpoint = "IP-of-CBS"
21$srcprotectiongroup = "arrayname:pgname"
22$destvolumename = "destvolumename"
23$srcvolumename = "sourcevolumename"
24$pureuser = "pureuser"
25$purepass = ConvertTo-SecureString "MYPASSWORD" -AsPlainText -Force
26$purecred = New-Object System.Management.Automation.PSCredential -ArgumentList ($pureuser, $purepass)
27
28# Connect to and set the active Pure Storage FlashArray
29$array = New-PfaArray -endpoint $arrayendpoint -credentials $purecred -ignoreCertificateError
30
31#Get Most Recent Completed Snapshot
32Write-Host "Obtaining the most recent snapshot for the protection group..." -ForegroundColor Red
33$MostRecentSnapshots = Get-PfaProtectionGroupSnapshots -Array $array -Name $srcprotectiongroup | Sort-Object created -Descending | Select-Object -Property name -First 2
34
35# Check that the last snapshot has been fully replicated
36$FirstSnapStatus = Get-PfaProtectionGroupSnapshotReplicationStatus -Array $array -Name $MostRecentSnapshots[0].name
37
38# If the latest snapshot's completed property is null, then it hasn't been fully replicated - the previous snapshot is good, though
39if ($null -ne $FirstSnapStatus.completed) {
40    $MostRecentSnapshot = $MostRecentSnapshots[0].name
41}
42else {
43    $MostRecentSnapshot = $MostRecentSnapshots[1].name
44}
45
46# Perform the DR volume overwrite
47Write-Host "Overwriting the volume with a copy of the most recent snapshot..." -ForegroundColor Red
48New-PfaVolume -Array $array -VolumeName $destvolumename -Source ($MostRecentSnapshot + '.' + $srcvolumename) -Overwrite | Out-Null
49
50# Online the volume
51Write-Host "Onlining the volume..." -ForegroundColor Red
52Get-Disk | Where-Object {$_.OperationalStatus -eq "Offline"} | Set-Disk -IsOffline $false

This use case can be utilized for Test/Dev and/or Disaster Recovery. It utilizes a default Azure Machine template, but this can be customized for your liking. Remember any configuration here is done via powershell so truly the options are endless.

Deploy your Azure VM

Unlike with other Terraform providers where you specify login credentials in the manifest, Azure is a bit different. There are 4 options and the easiest is to authenticate using Azure CLI

To login just run the below command. It will open a web browser and you’ll authenticate.

1az login

Once authenticated, you can run your Terraform deployment.

Run terraform init to install any needed providers, terraform plan to make sure all the connectivity is working and then terraform apply to deploy!

1terraform init
2terraform plan
3terraform apply

If everything is successful your Azure Virtual Machine instance should be deployed in ~5minutes!

Conclusion

Im loving how flexible it is to take advantage of Pure Storage in the Cloud! Using Cloud Block Store, it can be utilized for Migration, Test/Dev, Disaster Recovery as well as Public/Hybrid/Multi Cloud.

If you have any additional questions or comments, please leave them below!

comments powered by Disqus

See Also