TL;DR: Use the
Set-AzureStaticVNetIP cmdlet to reserve static IPs in a VNet.
Yesterday I saw a blog post about deploying Couchbase on Windows Azure. It was good in everything related to creating VMs and actually installing Couchbase, but it had one flaw: it relied on the order in which the VMs were started to assign IPs in the virtual network. That is a terrible idea in production.
By default, the Windows Azure Virtual Network assigns IPs within a subnet in the order they're requested, starting from
*.*.*.4 - so for example, if your subnet is configured for
10.0.0.0/23, your machines will have the IP addresses
10.0.0.5, and so on. If you shutdown (deallocate) the first VM (that had the IP
10.0.0.4) and start another one, then the new VM will get
10.0.0.4 because it's the first free IP in the subnet range.
As you can see, relying on the default way that the VNet assigns addresses is very unreliable in practice. Furthermore, if you don't neet all the machines at all times, there is no good way to shutdown some of the VMs to save money, because they will most likely come back with a different IP later. In particular, when deploying something like Hadoop on Azure it makes sense to only have the cluster running part of the time, and deallocate the VMs the rest of the time to avoid paying for idle uptime. Having IPs reshuffle because you accidentally used a different order, or because Microsoft decided to change the default way IPs are allocated, will make your cluster unusable.
The common way of dealing with this issue until now, was to deploy a DNS server inside it's own subnet, so that it will always get the first IP. This way you have a (sort of) static IP for your DNS. Then you can configure proper domain name resolution for the rest of the virtual network, and use FQDNs (because Couchbase can't handle short hostnames due to a quirk in how Erlang works.) VMs in the domain automatically register their names with the dynamic DNS when they start up, so IP changes are not a problem. This pattern is pretty well documented and there are plenty of blogs that cover the exact steps.
However, the problem is that this way also relies on the specific implementation of how Azure VNets hand out IPs. If Microsoft suddenly change that, your DNS can end up with a different IP address, and there goes your name resolution for the cluster. Besides, in a proper production deployment, you pretty much have to have two DNS servers for durability. Even if you use small VM instances, the costs add up.
There is now a new option. In the latest Windows Azure PowerShell SDK tools there are 4 new cmdlets that let you reserve static IPs for VMs in a virtual network. The cross-platform tools haven't been updated yet, and there's no such option in the management portal. So for now, you're limited to using the PowerShell or figuring out the exact HTTP request they send (using some HTTP capture tool, like Fiddler) and sending your own custom request.
Set-AzureStaticVNetIP- Reserves a static IP for a VM.
Get-AzureStaticVNetIP- Retrieves the reserved static IP of a VM.
Remove-AzureStaticVNetIP- Removes the reserved static IP.
Test-AzureStaticVNetIP- Checks whether the specified IP is available for a VM. Returns a list of alternative suggestions if the IP is unavailable.
Using these cmdlets is pretty simple. To reserve a static IP for an existing VM:
> $vm = Get-AzureVM -ServiceName CouchbaseSVC -Name CouchbaseVM1 > Set-AzureStaticVNetIP -VM $vm -IPAddress 10.0.0.4 | Update-AzureVM
Replace the service name, VM name, and IP address parameters with your own, of course. The other three cmdlets are pretty simple to use as well, just play around and give them a try.
Take a look at Niall Moran's blog post about using these cmdlets to set up a new VM, including a sample PowerShell script.
Update: Important note - do NOT mix VMs with static and dynamic (DHCP) IPs within the same subnet. If a machine with a reserved static IP is shutdown (deallocated), its IP can be allocated by DHCP to another VM. Put the two types of VMs in different subnets to avoid conflicts.