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!

Leave a Reply

Your email address will not be published. Required fields are marked *