Managing Developer VMs in Azure with a Chocolatey Twist

Overview

Imagine you're in charge of managing your development team's workstation infrastructure. Let's say you have 20 developers and they all have their own physical workstation. Those workstations might have started life from a common sys-prepped image with a standard set of developer-related tools installed on them (Visual Studio, SQL Server, Fiddler, etc.). Oftentimes, there will also be a Software or Tools file share somewhere out on the network where the devs can manually install whatever else they need. But, over time, new software and tools are released and your devs want to use them. Your baseline workstation image is out-of-date the day after you build it and it's tedious and time-consuming to maintain. Keeping up the Software share with the latest/greatest toolset is a full-time job by itself. On top of that, your team is growing fast and it's getting really expensive to procure new workstations so your CTO is moving your development to the cloud. Well, it's your lucky day my friend because the cloud affords us many opportunities that we didn't have before. The combination of 3 cool technologies- Azure PowerShell, Windows PowerShell Desired State Configuration (DSC) and Chocolatey- will make managing your development environment in the cloud trivial. 

If you're not already familiar, Chocolatey is a machine package manager, similar to apt-get, but built for Windows. This enables you to install many common dev/test/ops tools with a simple command. Need Visual Studio 2013 Ultimate? Simple:

 PS: \> choco install visualstudio2013ultimate

BAM! Done. Say goodbye to that pesky Software share that you have to maintain. But what about the common list of software you need installed on all the new VMs? And what if I want to push new tools out to my existing VMs? That's where Azure PowerShell and DSC comes in. Azure PowerShell is a set of cmdlets designed to make scripting out your cloud environment dead simple while DSC is a technology that is used to automatically configure a machine with a desired state (think Windows Roles/Features, directory structures, security settings, etc.)

In this post, I will show you how to use these three technologies together to make your life easy.

Install the latest Azure PowerShell SDK

First things first. If you haven't already installed or used Azure PowerShell before, follow these steps to get started: How to install and configure Azure PowerShell. These tools are AMAZING, very simple to use and absolutely essential when talking about automating/standardizing your cloud environment.

Download and install the cChoco DSC Resource

The real magic of this particular scenario is how we can extend DSC to include Chocolatey natively in the process. I (foolishly) started writing my own custom DSC resource to wrap Chocolatey but when I ran into several issues, I Googled it with Bing and quickly realized that, like every other "original" idea I've ever had, someone from the community had already beat me to it :) cChoco is one of several projects hosted up on GitHub in the PowerShell.org repository and it makes using Chocolatey with DSC a breeze. Here's how to download and install:

  1. Download cChoco from the following location: https://github.com/PowerShellOrg/cChoco 
  2. Extract the downloaded zip to the following path on your workstation: C:\Program Files\WindowsPowerShell\Modules

That's it! You will then be able to import and leverage cChoco from your custom DSC configuration file which you'll now create.

Create your custom DSC configuration file with Chocolatey packages

There are several out of the box DSC resources that you can take advantage of. For example, you could use the WindowsFeature resource to install IIS on all of your development workstations. Here is a list of all of the built-in DSC resources. For this example, however, we'll just stick to using Chocolatey to install some common dev tools. Here's what our DSC file looks like:

https://gist.github.com/nkpatterson/ec1cd1c17ae27b11944a

This looks like a pretty typical DSC file. The cChocoInstaller performs the initial installation of Chocolatey on the machine (if it's not already there). The 3 cChocoPackageInstaller sections specify which packages to install. You have the complete list of Chocolatey packages at your fingertips but in this case I'm just installing Google Chrome, Fiddler and Visual Studio 2013 Ultimate. The Name attribute in the DSC file corresponds to the package name. Remember where you save your DSC file, you will be referencing it in the next step.

Use the DSC PowerShell cmdlets to publish your package

Once you've got your DSC file just the way you like it, you will need to package it up and push it to the cloud so it can be referenced while Azure is configuring your VMs. This is made easy with the Publish-AzureVMDSCConfiguration cmdlet.  You just need to obtain a reference to your Azure storage account, point it at your DSC file and the command does the rest.

https://gist.github.com/nkpatterson/5d532bd6fe9bed02a9ed#file-publish-ps1

Now, if you go to the Azure Portal and browse to your storage account and click over to the Containers tab, you will see your DSC file sitting up in the cloud ready for the next step.

Provision a new Developer VM using your new DSC package

Using the Set-AzureVMDSCExtension cmdlet, we can create new virtual machines with our DSC package. I went ahead and wrote a simple script that encapsulates all of the necessary steps, taking in a few parameters such as your storage account name, the local path to the DSC file, the desired names of the virtual machines, etc. to make provisioning one or more VMs really easy.

https://gist.github.com/nkpatterson/ce00ede9a03777aa1578#file-provision-ps1

With this script in hand, you can easily create 3 new developer VMs in a matter of minutes:

 PS: \>.\Provision.ps1 -StorageAccountName "MyAccountName" -DscConfigurationPath "DSC.ps1" -DscConfigurationName "DevWorkstation" `
 
 -ServiceName "DevWorkstations" -VmNames @("devvm01", "devvm02", "devvm03") -AdminUsername "Admin" -AdminPassword "SomethingMoreSecureThanThis"
 

A few things like the VM image and size are hard-coded in there but hopefully you get the point. After the script runs, you'll see this in the management portal:

And once the VMs are started and running, you can log in using the credentials you entered and verify that the software you had specified in your Chocolatey DSC file are, in fact, there. Cool!

Update an existing Developer VM with new Chocolatey packages

This is all well and good and helpful in getting your development environment stood up quickly. The REAL power, however, comes when you want to make a change to your workstation baseline. For example, what if after provisioning 20 of these developer VMs I want to install an awesome new tool that I found on all of them? If you were using a custom VM image, you would need to download the image VHD, start it up, install the new software, sysprep it and then upload it back into Azure, yada yada. This only covers new VMs going forward and does nothing for you regarding the 20 VMs you already have. You would have to manually install the software on each of those. With DSC and Chocolatey, this tedious maintenance scenario becomes a simple matter of updating your DSC file with the new Chocolatey packages you wish to install and leveraging the same PowerShell cmdlets we were using to provision new VMs to update the existing ones. Here's a script I threw together to do just that:

https://gist.github.com/nkpatterson/2292baa29bcf0820a8a7#file-updatevms-ps1

After adding the cool new package to our local DSC file you can call the Provision.ps1 script again with just the minimal parameters to get the DSC file uploaded to storage.

 PS: \>.\Provision.ps1 -StorageAccountName "MyAccountName" -DscConfigurationPath ".\DSC.ps1"

That will overwrite the existing DSC file in your storage container and make it ready for the next call to UpdateVMs.ps1:

 PS: \>.\UpdateVMs.ps1 -StorageAccountName "MyAccountName" -DscConfigurationFileName "DSC.ps1.zip" -DscConfigurationName "DevWorkstation" -ServiceName "DevWorkstations" -VmNames @("devvm01", "devvm02", "devvm03")

And in just a few minutes, all of your VMs will be updated with the new software!

Scripts.zip