Using TeamCity and PowerShell to Deploy Automated Builds to Windows Azure

We’re building an ASP.NET MVC3 website that runs in Windows Azure, using the fabulous TeamCity as our build server. So far we have been just building and running the site locally on the build server, but we wanted to extend our build process into the cloud. Here’s what we wanted:

  • Build server runs a build and executes all tests
  • Deploy locally to the build server for our own smoke testing
  • Create Azure packages
  • Deploy to an existing Azure staging environment (retaining the same staging URL so our clients can access it)
  • If staging is all good, we can manually do a VIP-swap to move staging into production.

We found some pretty useful posts, including this one, which got us most of the way along the road. However, even that post seems overly convoluted. There’s no need to execute a cspack command line, for example. Perhaps it’s geared to older versions of the Azure tools? For the record, we’re using MVC3 and Azure tools 1.4, and we have a very basic solution with a single web role, a test project, and an Azure project.

So, assuming you already have a TeamCity build configuration that builds your web project without problems, here’s what you need to do to get your Azure packages built and deployed.

TeamCity Build Step to Create Azure Packages

This one was a lot easier than many blog posts made out. We didn’t need to call cspack via command line. Simply create an MSBuild step, point it at your Azure package (the actual ccproj file), and set the target to be CorePublish. That’s it. Once that step runs, you should see your cspkg file in the output location on your build server.

If you’re struggling with this step, make sure you have the Azure tools installed on your build server, and you might also need to copy across all the MSBuild include files from a PC with Visual Studio on it (from C:\Program Files (x86)\MSBuild\Microsoft\). Worst case you can install Visual Studio on your build server.

Open the little image at right to see an example of how this build step should look.

Create (or copy) a Powershell Script to Deploy to Azure

The first thing to do is install the Windows Azure Platform Powershell Cmdlets on your build server. Just install the package, and remember to run the “StartHere.cmd” file to install and configure the Cmdlets.

This is where we needed to do some jiggery-pokery. The original script we found was rather aggressive. It completely removed the existing staging deployment, then recreated it. The downside of this is that it changes the staging URL. Our modified script is below. This new script assumes an existing staging deployment exists, and will upgrade it. Ideally we should modify the script a tiny bit to deploy a new staging deployment if one doesn’t exist (in the else block).

We’ve also made a small change so that the staging URL is emitted as part of the build script (see the write-host $azureProperties.Url line).

Obviously you’ll need to insert the appropriate certificate thumbprint (you’ve got a management certificate in your Azure console right?!), and your subscription ID. The best way to test that you’ve got this right is to execute the script from the PowerShell command-line on your build server. It took us a few goes to get it bang-on, but once we had everything right, we could see the deploy happening in real-time.

$cert = Get-Item cert:\CurrentUser\My\your-management-certificate-thumbprint
$sub = "your-azure-subscription-id"
$buildPath = $args[0]
$packagename = $args[1]
$serviceconfig = $args[2]
$servicename = $args[3]
$storageservicename = $args[4]
$package = join-path $buildPath $packageName
$config = join-path $buildPath $serviceconfig
$a = Get-Date
$buildLabel = $a.ToShortDateString() + "-" + $a.ToShortTimeString()
 
if ((Get-PSSnapin | ?{$_.Name -eq "AzureManagementToolsSnapIn"}) -eq $null)
{
  Add-PSSnapin AzureManagementToolsSnapIn
}
 
write-host Getting service...
$hostedService = Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub | Get-Deployment -Slot Staging
 
if ($hostedService.Status -ne $null)
{
    write-host Service found.

	$currentService = Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub
 
	write-host Updating staging deployment...
	$currentService 
		| Set-Deployment -slot Staging -package $package -configuration $config -StorageServiceName $storageservicename -label $buildLabel 
		| Get-OperationStatus -WaitToComplete

	$azureProperties = $currentService | Get-Deployment -Slot Staging
	write-host $azureProperties.Url

	write-host Done!

} else {

	write-host Existing staging deployment not found!

}

TeamCity Build Step to Deploy Azure Packages

From there, it’s a simple step to call the script from your build server. Click the image to see how we do it (with placeholder parameters – use your own).

The parameters required in order are:

  • Path to your published package location
  • Package filename (the ones that ends in .cspkg)
  • Service configuration filename (.cscfg)
  • Hosted service name (aka DNS Prefix in Windows Azure console)
  • Storage service name, if this is different to the hosted service name

Done!

There you have it. When you execute this build configuration, you should see the staging deployment being replaced in-line, with zero downtime. If you’ve given your staging URL to client for UAT purposes, they will be able to use this same link and see the updated code as soon as it is deployed. Hooray!

Developers: POCKETVouchers on Azure

[box type=”info”]This is one of a series of sponsored blog posts highlighting New Zealand companies working with cutting-edge Microsoft technology. If you’re interested in Windows Phone 7 development, you should download the free Windows Phone Developer Tools and start building your own Windows Phone application.[/box]

POCKETVouchers is a local mobile marketing company who specialise in traceable mobile vouchers. Their unique approach means that customers can track exactly how many vouchers have gone out, how many have been redeemed, and ensures that vouchers cannot be redeemed multiple times.

“I would recommend start-ups have a good look at Azure.”

When POCKETVouchers decided to rebuild their platform to support future growth, they chose to go with Azure as their cloud provider. Todd mentions that they did look at alternatives such as Rackspace and Amazon, but chose Azure for a number of reasons: cost competitiveness, performance, and familiarity. For developers already familiar with the Microsoft server platform, shifting to Azure is a low-impact choice. Todd did mention some minor hurdles with getting existing code migrated to SQL Azure, but once those are understood, it was smooth sailing.

POCKETVouchers are using the beta version of the Azure Extra Small VMs, which allows them to move their low-load administration UI, or test services on these cheaper, smaller VMs. This frees up cost and capacity so that they can use large VMs for high-load periods, or even dedicate virtual machines to customers expecting a spike in load, perhaps around a concert or event.

In the future, Todd and the team are planning to automate scaling: bringing up VMs when the system is under heavy load, then shutting them down again when the load subsides. This approach, coupled with the pay-per-hour Azure billing, means that POCKETVouchers can get the best of both worlds: near-infinite scalability without the high ongoing cost of running hundreds of machines.