How to convert an Azure virtual machine to a VM Scale Set

If you have a regular Azure Resource Manager virtual machine, you can convert it to be a source image for a VM Scale Set.

Update 3/21/17: Since Azure Managed Disks were introduced, it’s now recommended to create scale sets based on Managed Disks instead of the traditional storage account method. You get several advantages:

  • No more need to managed a bunch of storage accounts.
  • You can attach data disks to scale sets.
  • You can create scale sets based on platform images of up to 1000 VMs.
  • Scale sets based on custom images can be up to 100 VMs.
  • For a description of how to convert an Azure virtual machine to a VM Scale Set based on Managed Disks, see Derek Martin’s ARM Templates and Managed Disks article.

    The rest of this post is based on creating a scale set using self-managed storage. Hopefully I’ll update it at some point 🙂

    In this example I’ll convert an Azure VM running a Minecraft server, to a load balanced VM scale set of servers. Multiple Minecraft client connections will hit a load balancer and be routed to different VMs in the set. This would enable you to start with a single VM, and scale it out to handle a much larger load.

    In a nutshell, to convert a single VM into a scale set you need to: capture a generalized image of the VM and copy that image into the storage account you’ll use for the set, then deploy a VM Scale Set with a custom image pointing to the generalized image. The steps are:

    1. Generalize the VM (e.g. run sysprep on Windows or waagent –deprovision on Linux).

    2. Stop deallocate the VM.

    3. Set the VM state as generalized.

    4. Save the image to a storage account.

    5. Copy the image to the storage account where you want to create the scale set.

    6. Deploy a VM Scale Set template with the image->uri property set to the image location.

    Now let’s go through those steps in more detail..

    Before starting make sure you have an Azure VM that you can log in to. For the Minecraft scenario the starting point would be to deploy a Minecraft server VM using the Minecraft Server Azure template. See Creating a Minecraft server using an Azure Resource Manager template for more information on how to do that.

    Note: in the steps below I will mostly use Azure CLI examples. Steps 1-4 for PowerShell are described in detail in Stephane Laponte’s excellent blog post STEP BY STEP: HOW TO CAPTURE YOUR OWN CUSTOM VIRTUAL MACHINE IMAGE UNDER AZURE RESOURCE MANAGER. Another useful PowerShell resource for steps 1-4, particularly if you have a Windows VM is the Azure documentation: How to capture a Windows virtual machine in the Resource Manager deployment model.

    1. Generalize the VM

    The first step in preparing a VM to be a source image for new VM deployments is to log in to the machine and generalize the image so it can be assigned a new name/user/password/certificate etc. at VMSS deployment time.

    On Windows that means running sysprep. On Linux call the VM agent with the –deprovision argument: sudo waagent –deprovision.

    image

    2. Stop deallocate the VM

    Stop deallocate the VM so the OS drive image can be captured.

    For PowerShell the command is Stop-AzureRmVm. The CLI command is: vm deallocate . e.g.

    image

    3. Set the VM state as generalized

    Now tell Azure that the VM is generalized.

    The PowerShell command is:
    Set-AzureRmVM –ResourceGroupName –Name –Generalized

    The Azure CLI command is: azure vm generalize . E.g.

    image

    4. Save the image to a storage account

    Now it’s time to capture the generalized image and save it in a storage account. The PowerShell command is Save-AzureRmVMImage. The CLI command is: azure vm capture mineset , and you’ll get back a template for the captured image which includes the properties->storageProfile->osDisk->image->uri setting, which is the link to the captured image that you’ll need when copying it to a new storage account.

    image

    5. Copy the image to the storage account where you’ll create the scale set

    If  the generalized VM image capture is already in the storage account and container you want it to be in, fine. In most cases at this point you’ll probably want to create a new storage account that you will use for the scale set you’ll be creating. You can copy the image to the new storage account using PowerShell, CLI, or a storage explorer like CloudBerry Explorer. I like the CloudBerry tool because it offers a nice split screen to show 2 storage accounts at a time and easily copy blobs between them.

    image

    Make a note of the URI for the new image as it will be used when deploying the scale set.

    6. Deploy a VM Scale Set template with the image->uri property set to the new image location

    The last step is to create a VM Scale Set with the image URI property set to the new image. There are some example ARM templates which allow you to specify a custom image, like this one in Aure Quickstart Templates: https://github.com/Azure/azure-quickstart-templates/tree/master/201-vmss-windows-customimage, but for the Minecraft server scenario, as well as being a Linux image, I also wanted to create a public IP address, and a load balancer with a rule to load balance incoming requests to the default Minecraft server port of 25565 to every VM in the set. The specialized template I created is here: vmss-minecraft-custom.json.

    Deploying this template to Azure as a new custom deployment in the portal allows the URI of the new image to be specified as a deployment parameter (along with the number of VMs, VM size, etc.).

    image

    Once the template is successfully deployed, a VM Scale Set of 10 Minecraft servers is now running behind a load balancer. Yay! Now the set of Minecraft servers can handle 10 times the incoming load, or I could scale this out to 40 servers.

    Note the Minecraft world on each VM in the scale set is exactly how it was when I generalized the original VM, with the same operators, whitelist settings etc. When users start making changes to different VMs the worlds will diverge, but I can always reimage the VMs in the scale set to set them back to the source image.

    One manual thing I had to do was start the Minecraft server on each VM (i.e. SSH to each VM using the inbound NAT rules defined in the template and run sudo systemctl start minecraft-server). This shouldn’t be necessary, and it may have been because I had shut down the Minecraft server before generalizing the image.

    Minecraft 1.10 6_20_2016 5_39_33 PM

    Next steps

    This was a basic walkthrough of converting a standalone Azure VM to a VM Scale Set. A next logical step would be to configure the VMSS template to use Azure autoscale. This way instead of launching a fixed number of VMs and manually scaling in or out, you could save costs by automatically scaling in or out depending on a workload such as average CPU speed.

    Advertisements
    This entry was posted in Cloud, Computers and Internet, VM Scale Sets and tagged , , , , . Bookmark the permalink.

    2 Responses to How to convert an Azure virtual machine to a VM Scale Set

    1. Praneeth says:

      Hi Guy,

      Thanks for great articles on Virtual Machine scale set. I am having an issue on Virtual machine scale set and internal load balancer, probes are failing they are not able to reach VM (Redhat Linux 7.2). But inbound NAT rules are working and ports on which probe is trying to access Linux firewall is open.

      Can you suggest how to get through this hurdle.

      • sendmarsh says:

        Hi Praneeth, I’d start by determining if this is a load balancer or a scale set probe. Can you ping the expected port on the IP address yourself? If you can then it’s a load balancer issue. If you can’t then it might be the NAT rules don’t point where you expect. For example if the VMSS overprovision property is set to true, some VMs will be deleted after they come up, leaving gaps in NAT rules. Try adding 1 to the port and seeing if there is a VM there. Looking at the load balancer rules in resources.azure.com should show which ones were created.
        This blog post is not the best place t troubleshoot further. stackoverflow or serverfault would be a better place. Let me know if you log it there and I’ll respond further. We’ll figure it out.

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s