I had some trouble finding some good examples of syntax and full explanation for creating VHD files (attaching new hard drives) from the Azure Powershell command line and attaching them to existing VMs. Here is my quick and dirty method of doing just that…
For some background, we like to attach the max number of VHD files (hard drives) we can and then use Storage Spaces to string them all together in Windows as a big storage pool and then provision Striped Hard Drive’s off of that for maximum throughput. Let’s just be honest. IOP’s for virtual machines (which is what everything in Azure is on some level or another no matter what Microsoft calls the actual service, platform, etc.) is by far THE Achilles heel of using cloud services, particularly for database servers. A physical bare-metal server is in many cases going to absolutely destroy a cloud instance in this area of performance.
UPDATE: Actually for very specific types of work loads I did find that Azure can actually perform quite well. The Crystal Diskmark 4k test with a Queue depth of 32 actually performs incredibly well. This kind of workload is commonly used by a well optimized database. Basically, this has to do with how many requests are sent to the HDD controller at one time. When azure detects that a bunch of requests are coming all at once, it apparently ramps up r/w performance which means Database performance can scale decently well.
After much fiddling, here was the command syntax that finally worked for me. This creates a 1000 GB VHD disk and attaches it to an existing Virtual Machine and it creates the VHD.
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data3" -LUN 3 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/FILENAME-OF-NEW-DISK.vhd" | Update-AzureVM
Now, I am going to walk through the command above step-by-step. If you aren’t using the Azure Powershell command-line, this won’t make any sense. Please read my article “Getting Started with Azure Powershell” and then return here.
- Get-AzureVM: This part of the command is specifying what Virtual Machine we are going to add a VHD file to. When a Virtual Machine is created in Azure, it creates a new service by default, or you can specify adding it to an existing service for things like Availability Groups for clusters. If you just followed the defaults when creating your VM, the service name and the VM name are the same as in my example above.
- | – “Pipe”… it is the special key most commonly found above “enter” on your keyboard and if you are new to command-line work it is often used to string together commands which is what powershell uses it for. The best way I can describe it is that it makes the next command “context sensitive” to the previous one. So in this case, we have specified our VM/Service with the Get-AzureVM command and now the pipe says that the next command is going to be affected against that service/vm.
- Add-AzureDataDisk -CreateNew -DiskSizeinGB 1000: I am assuming this is all fairly self-explanatory, you can modify 500 and at this present time up to 1000 (1 TB) max size.
- -DiskLabel: This can be anything you want it to be. I try to keep mine simple and just call them like “Data1” “Data2” etc…
- -Lun 3: You can have up to 16 attached VHD files on a single VM – The “LUN” = logical unit number and it is a holdover term from traditional SCSI hard drive/controller technology. Basically each disk gets a number in the OS. Starting at 0 and going up to I think 15? By default on most VM’s from the gallery LUN 0 is taken by the OS and LUN 1 is often taken by a secondary drive. If you are running Server 2012+ you can go into the storage spaces panel from Server Manager on the left and see what is available and what is taken. Each VHD you create for the same VM needs a unique LUN.
- -MediaLocation “https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/FILENAME-OF-NEW-DISK.vhd”: This was the part of the command syntax I had the most trouble with. Part of it is just my evolving comfort level with Azure storage options and terms like BLOBS (Binary Large OBjects = read “files”). Another part of it is my comfort level with every bloody thing in Azure being publicly addressable which still feels foreign to me coming from a traditional brick-and-mortar networking background. Okay… You VM has a storage account. I create storage accounts for each of my VM’s by name because I like keeping things as obvious as possible. Most folks probably just tick the option during VM creation time to “automatically generate new storage account” – If the latter describe you, we need to go into the portal and figure out which storage account your VM is using. To do that:
- Login in the Azure Portal
- Go the VM tab on the left
- Open the VM you want to add more drives to
- Click on “Dashboard” at the top
- Scroll down and look at the “disks” section
- In the right-hand “VHD” column you will see URL’s to VHD files. Hover over one and click the copy button and paste to a text file
- It should look something like this: “https://somestringofcharacters.blob.core.windows.net/vhds/vm-name-andotherstuff.vhd”
- So for your commmand syntax for adding VHD files to this VM it would look something like this for each drive: “https://somestringofcharacters.blob.core.windows.net/vhds/data1.vhd”
- Finally you see another | (pipe) followed by the Update-AzureVM commandlet. All of the preceding stuff is “piped” into this commandlet which says “execute these changes on my VM”
So… to make a quick and dirty script (this could be done much more gracefully by declaring some variables but for the sake of simplicity…)
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data3" -LUN 3 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data3.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data4" -LUN 4 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data4.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data5" -LUN 5 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data5.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data6" -LUN 6 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data6.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data7" -LUN 7 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data7.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data8" -LUN 8 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data8.vhd" | Update-AzureVM
Get-AzureVM "testvm1" -Name "testvm1" | Add-AzureDataDisk -CreateNew -DiskSizeInGB 1000 -DiskLabel "data9" -LUN 9 -MediaLocation "https://VM-STORAGE-ACCOUNT-URL.blob.core.windows.net/vhds/data9.vhd" | Update-AzureVM
I belive there is probably a much cleaner way to go about this by using some other commandlets at the front-end to declare what storage account you are using among other things. However the above setup will get you where you need to go. I will be revisiting this article in the future with an update or at least make a follow-up article when I get there.
Hope this is of use!