Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

It is possible to have a hight available Master Controller in Azure using a feature of Azure called a Virtual Machine Scale Set. See: https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/overview

Since only one MC can be running at a time, we can take advantage of the ability of a VMSS (Virtual Machine Scale Set) and optionally an Azure Availability Zone to instruct Azure to always keep the Virtual Machine with the Master Controller running.

To take advantage of this feature it is necessary to have the MC software already installed on a Virtual Machine Image or have it installed automatically. In the following example the automatic installation using an ARM template with a Custom Script Extension is ued.

In the Delft-FEWS Basebuild distribution, there is a powershell script called setEnvFromJsonBase64.ps1 that can be used to pass env variables to install a MC as a service on an Azure Virtual Machine using a custom script extension (CSE). The mcLauncher will be started as a service using the NT AUTHORITY\Network Service account.

Code Block
languagejs
# Call the setEnvFromJsonBase64.ps1  script in Azure Custom Script Extension for Virtual Machine Scale Set
"variables": {
    "env": {
           "FEWS_MC_HOME_DIR": "c:/fews/mc",
           "FEWS_MC_MC00_DATABASE_URL": "[parameters('DatabaseUrl')]"
           },
    },

The following is a complete ARM template that is an example on how to deploy a VM using an arm template that installs the MC Software using a Custom Script Extension. The following parts are most relevant:

resource type: "Microsoft.Compute/virtualMachineScaleSets". This defines that a virtual scale set is used.

zones: a list of availibility zones the MC can move to in case of a failure.

sku capacity: 1. By setting the capacity to 1, Azure will always keep one MC Virtual Machine running.

extensionProfile:  takes care of installing the custom script extension with the MC software.

Code Block
languagejs
titleazuredeploy.json
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "NamingPrefix": {
      "type": "string",
      "minLength": 3,
      "maxLength": 16,
      "defaultValue": "DEVWINMCVMSS",
      "metadata": {
        "description": "VM Naming Prefix"
      }
    },
    "NamingPostfix": {
      "type": "string",
      "defaultValue": "01",
      "maxLength": 2,
      "metadata": {
        "description": "VM Naming Postfix"
      }
    },
    "LocalAdminUser": {
      "type": "string",
      "defaultValue": "XXX",
      "metadata": {
        "description": "Username for the local admin user"
      }
    },
    "LocalAdminPassword": {
      "type": "securestring",
      "defaultValue": "XXX",
      "metadata": {
        "description": "Password for the local admin user"
      }
    },
    "VMSize": {
      "type": "string",
      "allowedValues": [
        "Standard_D4s_v5",
        "Standard_B2s",
        "Standard_B2ms",
        "Standard_B4ms",
        "Standard_B8ms",
        "Standard_D2s_v3",
        "Standard_D4s_v3",
        "Standard_D8s_v3"
      ],
      "defaultValue": "Standard_B2s",
      "metadata": {
        "description": "VM Size SKU."
      }
    },
    "VnetResourceID": {
      "type": "string",
      "defaultValue": "fewsmc00-vnet",
      "metadata": {
        "description": "Resource ID of the Vnet that you would like the VM's NIC to be placed in"
      }
    },
    "SubNetName": {
      "type": "string",
      "defaultValue": "PrivateSubnet",
      "metadata": {
        "description": "the name of the subnet that this VM will placed in"
      }
    },
    "OSVersion": {
      "type": "string",
      "defaultValue": "2019-Datacenter-smalldisk",
      "allowedValues": [
        "2019-Datacenter",
        "2019-Datacenter-smalldisk"
      ],
      "metadata": {
        "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version. Using the small disk allow creating a c: drive from 32GBytes and up."
      }
    },
    "DiskSizeGB": {
      "type": "string",
      "defaultValue": "32",
      "metadata": {
        "description": "The size of the OS Disk."
      }
    },
    "FewsBaseBuildUrl": {
      "type": "string",
      "defaultValue": "https://myblobstorage.blob.core.windows.net/delft-fews-base-builds/fews-development-202302-121196-bin.zip",
      "metadata": {
        "description": "Basbuild distribution URL"
      }
    },
    "DatabaseUrl": {
      "type": "string",
      "defaultValue": "XXX",
      "metadata": {
        "description": "Database URL. Use a database URL with credentials encoded. The URL can be stored in Azure Keyvault."
      }
    },
    "ResourceTags": {
      "type": "object",
      "defaultValue": {
        "mc": "high available mc using a vmss"
      }
    }
  },
  "variables": {
    "Location": "[resourceGroup().location]",
    "SubnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('VnetResourceID'), parameters('SubNetName'))]",
    "VMNameScaleSet": "[concat(parameters('NamingPrefix'), parameters('NamingPostfix'))]",
    "env": {
           "FEWS_MC_HOME_DIR": "c:/fews/mc",
           "FEWS_MC_MC00_DATABASE_URL": "[parameters('DatabaseUrl')]"
           },
    "installScript": "Start-BitsTransfer -Source \"__BASEBUILD_DISTRIBUTION_URL__\" -Destination \"c:\\bin.zip\"\nExpand-Archive \"c:\\bin.zip\" -DestinationPath \"c:\\fews\\bin\";\nRemove-Item -Path \"c:\\bin.zip\";\nc:\\fews\\bin\\windows\\setEnvFromJsonBase64.ps1 \"__BASE64_ENV_VARIABLES__\";\nc:\\fews\\bin\\windows\\mcLauncherRegisterService.bat\nc:\\fews\\bin\\windows\\mcLauncherStartService.bat",
    "installData": "[replace(replace(variables('installScript'),'__BASE64_ENV_VARIABLES__',base64(string(variables('env')))),'__BASEBUILD_DISTRIBUTION_URL__',parameters('FewsBaseBuildUrl'))]"
  },
  "resources": [
    {
      "name": "[variables('VMNameScaleSet')]",
      "type": "Microsoft.Compute/virtualMachineScaleSets",
      "apiVersion": "2022-03-01",
      "zones": ["1", "2", "3"],
      "sku": {
        "name": "[parameters('VMSize')]",
        "capacity": 1,
        "tier": "Standard"
      },
      "location": "[variables('Location')]",
      "tags": "[parameters('ResourceTags')]",
      "properties": {
         "overprovision": false,
          "upgradePolicy": {
          "mode": "Manual"
        },
        "virtualMachineProfile": {
          "osProfile": {
            "computerNamePrefix": "MC",
            "adminUsername": "[parameters('LocalAdminUser')]",
            "adminPassword": "[parameters('LocalAdminPassword')]",
            "customData": "[base64(variables('installData'))]"
          },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "[parameters('OSVersion')]",
            "version": "latest"
          },
          "osDisk": {         
            "caching": "ReadWrite",
            "createOption": "FromImage",
            "diskSizeGB": "[parameters('DiskSizeGB')]",
            "managedDisk": {
              "storageAccountType": "Premium_LRS"
            }
          },
          "dataDisks": [
          ]
        },
        "extensionProfile": {
            "extensions": [
              {
                "name": "DelftFewsMasterControllerInstaller",
                "properties": {
                    "publisher": "Microsoft.Compute",
                    "type": "CustomScriptExtension",
                    "typeHandlerVersion": "1.10",
                    "autoUpgradeMinorVersion": true,
                    "protectedSettings": {
                      "commandToExecute": "powershell -ExecutionPolicy Unrestricted < %SYSTEMDRIVE%\\AzureData\\CustomData.bin  && del /f %SYSTEMDRIVE%\\AzureData\\CustomData.bin"
                    }

                }
              }
            ]
        },
        "networkProfile": {
            "networkInterfaceConfigurations": [
              {
                "name": "nic-config",
                "properties": {
                  "primary": true,
                  "ipConfigurations": [
                      {
                          "name": "ipconfig1",
                          "properties": {
                              "subnet": {
                                  "id": "[variables('SubnetRef')]"
                              }
                          }
                      }
                  ]
                }
              }
            ]
          }
        }
       }
    }
  ]
}